11# ` Elm ` (_ ish_ )
22
3- ### How to Build a Front-end Micro-Framework _ From Scratch_
3+ ### ( How to Build a Front-end Micro-Framework _ From Scratch_ )
44
55![ elmlogo-ish] ( https://user-images.githubusercontent.com/194400/43213139-b70a4c68-902d-11e8-8162-3c7cb56b6360.png )
66<!-- the colors are deliberately "a bit off" to emphasize that
@@ -78,26 +78,18 @@ please see:
7878and
7979[ front-end-with-tape.md] ( https://github.com/dwyl/learn-tape/blob/master/front-end-with-tape.md )
8080
81- ### Start by Creating the Files
82-
83- It's "OK" to ask: "_ Where do I ** start** (my ** TDD** quest)?_ " <br />
84- The answer is: create ** two** new files:
85- ` examples/todo-list/elmish.js ` and ` test/elmish.test.js `
86-
87- We will create a couple of tests and their corresponding functions _ next_
88- but first, let's take a moment to think about what we _ can_ generalise
89- from the code we wrote for our "counter" example at the start of this tutorial.
9081
9182### What _ Can_ We _ Generalise_ ?
9283
93- Our ** first step** in creating ` Elm ` (_ ish_ ) is to consider
94- what _ can_ be _ generalised_ into
84+ Our ** first step** in creating ` Elm ` (_ ish_ )
85+ is to _ re-visit_ the functions we wrote for the "counter app"
86+ and consider what _ can_ be _ generalised_ into
9587an application-independent re-useable framework.
9688
9789> Our ** rule-of-thumb** is: anything that creates (_ or destroys_ )
9890 a DOM element or looks like "plumbing"
99- (_ e .g: "routing" or "managing state"_ ) is _ generic _
100- and should thus be abstracted into the ` Elm ` (_ ish_ ) framework.
91+ (_ that which is common to ** all apps ** , e .g: "routing" or "managing state"_ )
92+ is _ generic _ and should thus be abstracted into the ` Elm ` (_ ish_ ) framework.
10193
10294
10395Recall that there are ** 3 parts** to the Elm Architecture:
@@ -134,21 +126,106 @@ these _can_ (_will_) be generalised (_below_).
134126
135127
136128Let's start with a couple of "_ familiar_ " _ generic_ functions
137- (_ which we saw and used in the "counter" example_ ):
138- ` empty ` and ` mount ` . <br />
129+ (_ which we used in the "counter-reset " example_ ):
130+ ` init ` , ` empty ` and ` mount ` . <br />
139131
140132<br />
141133
142- #### ` empty ` the DOM
134+ ### Start by Creating the Files
135+
136+ It's _ essential_ to ask: "_ Where do I ** start** (my ** TDD** quest)?_ " <br />
137+ The answer is: create ** two** new files:
138+ ` examples/todo-list/elmish.js ` and ` test/elmish.test.js `
139+
140+
141+ ### Test Setup
142+
143+ In order to run our test, we need some "setup" code
144+ that "requires" the libraries so we can _ execute_ the functions.
145+
146+ In the ` test/elmish.test.js ` file, type the following code:
147+ ``` js
148+ const test = require (' tape' ); // https://github.com/dwyl/learn-tape
149+ const fs = require (' fs' ); // to read html files (see below)
150+ const path = require (' path' ); // so we can open files cross-platform
151+ const html = fs .readFileSync (path .resolve (__dirname ,
152+ ' ../examples/todo-list/index.html' )); // sample HTML file to initialise JSDOM.
153+ require (' jsdom-global' )(html); // https://github.com/rstacruz/jsdom-global
154+ const elmish = require (' ../examples/todo-list/elmish.js' ); // functions to test
155+ elmish .init (document ); // pass JSDOM into elmish for DOM functions
156+ const id = ' test-app' ; // all tests use 'test-app' as root element
157+ ```
158+
159+ > Most of this code should be _ familiar_ to you
160+ if you have followed previous tutorials.
161+ > If anything is _ unclear_ please revisit
162+ https://github.com/dwyl/learn-tape
163+ and
164+
165+ If you attempt to run this code using the command:
166+ ``` sh
167+ node test/elmish.test.js
168+ ```
169+
170+ you will see something like the following:
171+ ![ no-init-function] ( https://user-images.githubusercontent.com/194400/43359605-b8cc9418-929c-11e8-92d6-97feb8c67596.png )
172+
173+ This is because we do not have anything in the ` elmish.js ` , yet.
174+ Let's address that now!
175+
176+
177+ ### Add ` init ` function
178+
179+ Open the ` examples/todo-list/elmish.js ` file and add the following code:
180+
181+ ``` js
182+
183+
184+ /**
185+ * `init` initialises the document (Global) variable for DOM operations.
186+ * @param {Object} doc window.document in browser and JSDOM.document in tests.
187+ * @return {Object} document returns whatever is passed in.
188+ */
189+ function init (doc ){
190+ document = doc; // this is used for instantiating JSDOM for testing.
191+ return document ;
192+ }
193+ ```
194+
195+ This code is simply to allow us to "initialise" ` Elm ` (_ ish_ )
196+ with a "fake" DOM (` JSDOM ` ) so that we can _ test_ it.
197+
198+
199+ ### Add ` module.exports ` to "export" the ` init ` function
200+
201+ Adding the function to the ` elmish.js ` file is a good _ start_ ,
202+ but we need to *** ` export ` *** it to be able to _ invoke_ it in our test.
203+ Let's add the following code at the end of ` examples/todo-list/elmish.js ` :
204+
205+ ``` js
206+ /* module.exports is needed to run the functions using Node.js for testing! */
207+ /* istanbul ignore next */
208+ if (typeof module !== ' undefined' && module .exports ) {
209+ module .exports = {
210+ init: init
211+ }
212+ } else { init (document );
213+ ` ` `
214+
215+
216+
217+
218+ ### ` empty` the DOM
143219
144220Start by _describing_ what the ` empty` function _does_. <br />
145221This is both to clarify our _own_ understanding
146222as the people _writing_ the code <br />
147223and to _clearly communicate_ with the **` humans` _reading_** the code.
148224
149- ##### Function Description
225+ #### ` empty ` Function _Description_
150226
151- The ` empty ` function clears the DOM elements out of a specific "root" element.
227+ The ` empty` function deletes all DOM elements
228+ from within a specific "root" element.
152229We use it to erase the DOM before re-rendering our app.
153230
154231Following "**_Document(ation)_ Driven Development**",
@@ -158,12 +235,13 @@ with _just_ the function description:
158235
159236` ` ` js
160237/**
161- * `empty` clears the DOM elements out of a specific "root" element.
238+ * `empty` deletes all the DOM elements from within a specific "root" element.
162239 * it is used to erase the DOM before re-rendering the app.
163240 */
164241` ` `
165242Writing out the function documentation _first_
166- helps us _ think_ about the functionality.
243+ allows (_our subconscious_) time to _think_ about the functionality
244+ and how to _test_ for the "_acceptance criteria_".
167245Even if you know _exactly_ what code needs to be written,
168246_resist_ the temptation to write the code until it is documented.
169247Even if you are writing code alone,
@@ -172,12 +250,15 @@ who does _not_ (_already_) "know the solution"
172250and you are _explaining_ it to them.
173251
174252
253+ #### ` empty` Function _Test_
175254
176- Given that we _ know_ we are going to use the ` empty `
177-
178- function we used previously in our ` counter ` ,
255+ We previously used the ` empty` function in our ` counter` ,
179256` counter- reset` and ` multiple- counters` examples (_in the "basic" TEA tutorial_)
180- we can write a _ test_ for the ` empty ` function quite easily.
257+ so we have a "head start" on writing the test.
258+
259+ > _The **reason**(s) we write the **test first**
260+ even when we (already) know the "solution" is:_ <br />
261+ >
181262
182263
183264In the ` test/ elmish .test .js ` file, type the following code:
@@ -187,7 +268,7 @@ const fs = require('fs'); // to read html files (see below)
187268const path = require (' path' ); // so we can open files cross-platform
188269const elmish = require (' ../examples/todo-list/elmish.js' ); // functions to test
189270const html = fs .readFileSync (path .resolve (__dirname ,
190- ' ../examples/todo-list/index.html' )); // sample HTML file for JSDOM to load
271+ ' ../examples/todo-list/index.html' )); // sample HTML file to initialise JSDOM.
191272require (' jsdom-global' )(html); // https://github.com/rstacruz/jsdom-global
192273elmish .init (document ); // pass JSDOM into elmish for DOM functions
193274const id = ' test-app' ; // all tests use 'test-app' as root element
@@ -223,17 +304,19 @@ issue***!](https://github.com/dwyl/learn-elm-architecture-in-javascript/issues)
223304_It's **essential** that you **understand** each **character**
224305in the code **before** continuing to **avoid** "**confusion**" later._
225306
307+ #### ` empty` Function _Implementation_
308+
226309Now that we have the **test** for our ` empty` function written,
227310we can add the ` empty` function to ` examples/ todo- list/ elmish .js ` :
228311` ` ` js
229312/**
230- * `empty` the contents of a given DOM element "node" (before re-rendering).
313+ * `empty` deletes all the DOM elements from within a specific "root" element.
314+ * it is used to erase the DOM before re-rendering the app.
231315 * This is the *fastest* way according to: stackoverflow.com/a/3955238/1148249
232- * @param {Object} node the exact DOM node you want to empty
316+ * @param {Object} node the exact ("parent") DOM node you want to empty
233317 * @example
234318 * // returns true (once the 'app' node is emptied)
235- * const node = document .getElementById (' app' );
236- * empty (node);
319+ * empty (document .getElementById (' app' ));
237320 */
238321function empty (node ) {
239322 while (node .lastChild ) {
@@ -242,12 +325,18 @@ function empty(node) {
242325}
243326` ` `
244327
245- If the ** comment syntax**
246- above the function definition
247- is _ unfamiliar_ ,
328+ If the **comment syntax** above the function definition is _unfamiliar_,
248329please see:
249330[https://github.com/dwyl/**learn-jsdoc**](https://github.com/dwyl/learn-jsdoc)
250331
332+ When you run the test in your terminal with the command
333+ ` node test/ elmish .test .js `
334+ you should see something _similar_ to this:
335+
336+
337+
338+
339+
251340
252341### ` mount` the App
253342
0 commit comments