Skip to content

Commit ab9af90

Browse files
committed
start on new plan for 16
1 parent 9d2df6c commit ab9af90

File tree

2 files changed

+173
-51
lines changed

2 files changed

+173
-51
lines changed

chapter_16_javascript.asciidoc

Lines changed: 171 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,178 @@ AssertionError: True is not false
159159
And we can commit this as the first cut of our FT.
160160

161161

162+
=== A Quick Spike of a solution
163+
164+
This will be our first bit of JavaScript.
165+
We're also interacting with the Bootstrap CSS framework,
166+
which we maybe don't know very well.
167+
168+
In <<chapter_14_simple_form>> we saw that you
169+
can use a unit test as a way of exploring a new API or tool.
170+
Sometimes though, you just want to hack something together
171+
without any tests at all, just to see if it works,
172+
to learn it or get a feel for it.
173+
174+
That's absolutely fine.
175+
When learning a new tool or exploring a new possible solution,
176+
it's often appropriate to leave the rigorous TDD process to one side,
177+
and build a little prototype without tests, or perhaps with very few tests.
178+
The goat doesn't mind looking the other way for a bit.
179+
180+
This kind of prototyping activity is often called a "spike",
181+
for http://stackoverflow.com/questions/249969/why-are-tdd-spikes-called-spikes[
182+
reasons that aren't entirely clear].
183+
184+
185+
==== A Simple Inline Script
186+
187+
I hacked around for a bit,
188+
and here's more or less the first thing I came up with.
189+
I'm adding the code inline, in a `<script>` tag
190+
at the bottom of our _base.html_ template:
191+
192+
[role="sourcecode"]
193+
.lists/templates/base.html
194+
====
195+
[source,javascript]
196+
----
197+
</div>
198+
199+
<script>
200+
const textInput = document.querySelector("#id_text"); //<1>
201+
textInput.oninput = () => { //<2><3>
202+
const errorMsg = document.querySelector(".invalid-feedback");
203+
errorMsg.style.display = "none"; //<4>
204+
}
205+
</script>
206+
----
207+
====
208+
209+
<1> `document.querySelector` is a way of finding an element in the DOM,
210+
using CSS selector syntax, very much like the Selenium
211+
`find_element(By.CSS_SELECTOR)` method from our FTs.
212+
213+
<2> `oninput` is how you attach an event listener "callback" function,
214+
which will be called whenever the user inputs something into the text box.
215+
216+
<3> Arrow functions `() => {...}` are the new way of writing anonymous functions
217+
in JavaScript, a bit like Python's `lambda` syntax.
218+
I think they're cute!
219+
Arguments go in the round brackets,
220+
the function body goes in the curly braces.
221+
So this is a function that takes no arguments,
222+
or I should say, ignores any arguments you try to give it.
223+
What does it do?
224+
225+
<4> It finds the error message element,
226+
and then hides it by setting its `style.display` to "none".
227+
228+
That's actually good enough to get our FT passing:
229+
230+
[subs="specialcharacters,quotes"]
231+
----
232+
$ *python src/manage.py test functional_tests.test_list_item_validation.\
233+
ItemValidationTest.test_error_messages_are_cleared_on_input
234+
Found 1 test(s).
235+
[...]
236+
.
237+
---------------------------------------------------------------------
238+
Ran 1 test in 3.284s
239+
240+
OK
241+
----
242+
243+
244+
==== Using the Browser Devtools
245+
246+
The test might be happy, but our solution is a little unsatisfactory.
247+
If you actually try it in your browser,
248+
you'll see that although the error message is gone,
249+
the input is still red an invalid-looking, see <<input-still-red>>.
250+
251+
[[input-still-red]]
252+
.The error message is gone but the input box is still red
253+
image::images/error-gone-but-input-still-red.png["Screenshot of our page where the error div is gone but the input is still red."]
254+
255+
You're probably imagining that this is something to do with Bootstrap.
256+
We might have been able to hide the error message,
257+
but we also need to tell bootstrap that this input no longer has invalid contents.
258+
259+
This is where I'd normally open up the browser
260+
https://firefox-source-docs.mozilla.org/devtools-user/[devtools].
261+
If level 1 of hacking is spiking code directly into an inline `<script>` tag,
262+
level 2 is hacking things directly in the browser,
263+
where it's not even saved to a file!
264+
265+
[[editing-html-in-devtools]]
266+
.Editing the HTML in the browser devtools
267+
image::images/editing-html-via-devtools.png["Screenshot of the browser devtools with us editing the classes for the input element"]
268+
269+
In <<editing-html-in-devtools>> you can see me directly editing the HTML of the page,
270+
and finding out that removing the `is-invalid` class from the input element
271+
seems to do the trick.
272+
It not only removes the error message,
273+
but also the red border around the input box.
274+
275+
We have a reasonable solution now, time to de-spike!
276+
277+
278+
.Do we Really Need to Write Unit Tests for This?
279+
*******************************************************************************
280+
281+
By this point in the book, you probably know I'm going to say "yes",
282+
but let's talk about it anyway.
283+
284+
Our FT definitely covers this funcitonality,
285+
and we could extend it if we wanted to,
286+
to check on the colour of the input box,
287+
or to look at the input element's CSS classes.
288+
289+
And if I was really sure that this was the only bit of JavaScript
290+
we were ever going to write,
291+
I probably would be tempted to leave it at that.
292+
293+
But I want to press on for two reasons.
294+
Firstly, because any book on web development has to talk about JavaScript,
295+
and in a TDD book, I have to show a bit of TDD in JavaScript.
296+
297+
More importantly though, as always we have the boiled frog problem.
298+
We might not have enough JavaScript _yet_ to justify a full test suite,
299+
but what about when we come along later and add a tiny bit more?
300+
And a tiny bit more again?
301+
302+
It's always a judgement call, and on the one hand YAGNI,
303+
but on the other hand, I think it's best to but the scaffolding in place early,
304+
so that going test-first is the easy choice later.
305+
306+
I can already think of several extra things I'd want to do in the frontend!
307+
What about re-setting the input to being invalid if someone types in the
308+
exact duplicate text again?
309+
310+
*******************************************************************************
311+
312+
162313
=== Setting Up a Basic JavaScript Test Runner
163314

164315

316+
////
317+
=== TODO: new plan
318+
319+
this chapter is a decent first pass now, want to improve it as follows:
320+
321+
* start with basic inline script that just hides the thing on input,
322+
see FT pass [DONE]
323+
324+
* install jasmine browser runner via npm/npx. use esm/modules straight away
325+
326+
* see if just specifying it as a .js works, and we can do the chat about execution times. then switch to .mjs and imports
327+
328+
* split out tests, especially sense-check bits, into 3 different its
329+
////
330+
331+
332+
333+
165334
((("test running libraries")))
166335
((("JavaScript testing", "test running libraries", id="JStestrunner16")))
167336
((("pytest")))
@@ -473,25 +642,6 @@ Superlists tests
473642

474643

475644

476-
////
477-
478-
=== TODO: new plan
479-
480-
this chapter is a decent first pass now, want to improve it as follows:
481-
482-
* start with basic inline script that just hides the thing on input,
483-
see FT pass
484-
485-
* install jasmine browser runner via npm/npx. use esm/modules straight away
486-
487-
* see if just specifying it as a .js works, and we can do the chat about execution times. then switch to .mjs and imports
488-
489-
* split out tests, especially sense-check bits, into 3 different its
490-
////
491-
492-
493-
494-
495645
=== Building a JavaScript Unit Test for Our Desired Functionality
496646

497647

@@ -501,9 +651,9 @@ Now that we're acquainted with our JavaScript testing tools,
501651
we can switch back to just one test and start to write the real thing:
502652

503653
[role="sourcecode small-code"]
504-
.lists/static/tests/Spec.js (ch16l012)
654+
.lists/static/tests/spec.js (ch16l012)
505655
====
506-
[source,html]
656+
[source,javascript]
507657
----
508658
it("error message should be hidden on input", () => { //<1>
509659
const inputSelector = "input#id_text";
@@ -918,36 +1068,6 @@ $ *git commit -m"add jamsine specrunner, js tests, and lists.js with onpinput li
9181068

9191069
TODO: resume here:
9201070

921-
* open in browser, not quite right. see <<input-still-red>>
922-
923-
[[input-still-red]]
924-
.The error message is gone but the input box is still red
925-
image::images/error-gone-but-input-still-red.png["Screenshot of our page where the error div is gone but the input is still red."]
926-
927-
* Also you might notice some errors in the js console see <<js-console-errors>>
928-
929-
[[js-console-errors]]
930-
.An error in the browser devtools console
931-
image::images/js-errordiv-is-null-in-console.png["Screenshot of the browser devtools console with an error saying errorDiv is Null"]
932-
933-
934-
How to fix?
935-
936-
=== Experimenting with the browser devtools
937-
938-
939-
this calls for a spike really, we don't know bootstrap well enough.
940-
let's hack about in devtools
941-
942-
943-
see <<editing-html-in-devtools>>
944-
945-
[[editing-html-in-devtools]]
946-
.Editing the HTML in the browser devtools
947-
image::images/editing-html-via-devtools.png["Screenshot of the browser devtools with us editing the classes for the input element"]
948-
949-
950-
removing the `is-invalid` class from the input element seems to do the trick
9511071

9521072

9531073

chapter_spiking_custom_auth.asciidoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ a production website, but this is just a fun toy project so let's give it a go.
7070
Exploratory Coding, aka "Spiking"
7171
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7272

73+
TODO: I have copied this paragraph into <<chapter_16_javascript>> so it's now
74+
a duplicate.
7375

7476

7577
((("exploratory coding", see="also spiking and de-spiking")))((("spiking and de-spiking", "defined")))((("prototyping", see="spiking and de-spiking")))Before

0 commit comments

Comments
 (0)