Skip to content

Commit d738ce6

Browse files
committed
good progress, get tessts running in ci
1 parent 49ad3e0 commit d738ce6

File tree

3 files changed

+53
-66
lines changed

3 files changed

+53
-66
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ jobs:
3232
test_chapter_16_javascript,
3333
test_chapter_18_spiking_custom_auth,
3434
test_chapter_19_mocking,
35+
test_chapter_20_fixtures_and_wait_decorator,
3536
unit-test
3637
]
3738

chapter_20_fixtures_and_wait_decorator.asciidoc

Lines changed: 51 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,49 @@
11
[[chapter_20_fixtures_and_wait_decorator]]
2-
Test Fixtures and a Decorator for [keep-together]#Explicit Waits#
3-
-----------------------------------------------------------------
2+
== Test Fixtures and a Decorator for [keep-together]#Explicit Waits#
43

5-
.Warning, Chapter Not Updated.
4+
.Warning, Chapter Update in progress
65
*******************************************************************************
7-
🚧 Warning, this Chapter is the 2e version, and uses Django 1.11
6+
🚧 Warning, this Chapter is being updates for Django 4 + Python 3.12.
87
9-
This chapter and all the following ones are the second edition versions, so they still use Django 1.11, Python 3.8, and so on.
10-
11-
To follow along with this chapter, it’s probably easiest to reset your code to match my example code as it was in the 2e, by resetting to: https://github.com/hjwp/book-example/tree/chapter_19_mocking
12-
13-
And you should also probably delete and re-create your virtualenv with * Python 3.8 or 3.9 * and Django 1.11 (pip install "django <2")
14-
15-
Alternatively, you can muddle through and try and figure out how to make things work with Django 4 etc, but be aware that the listings below won’t be quite right.
8+
Some code listings may be inconsistent.
169
*******************************************************************************
1710

18-
((("authentication", "skipping in FTs")))Now
19-
that we have a functional authentication system, we want to use it to
20-
identify users, and be able to show them all the lists they have created.
11+
((("authentication", "skipping in FTs")))
12+
Now that we have a functional authentication system, we want to use it to identify users,
13+
and be able to show them all the lists they have created.
2114

22-
To do that, we're going to have to write FTs that have a logged-in user. Rather
23-
than making each test go through the (time-consuming) login email dance, we
24-
want to be able to skip that part.
15+
To do that, we're going to have to write FTs that have a logged-in user.
16+
Rather than making each test go through the (time-consuming) login email dance,
17+
we want to be able to skip that part.
2518

2619

27-
28-
This is about separation of concerns. Functional tests aren't like unit tests,
29-
in that they don't usually have a single assertion. But, conceptually, they
30-
should be testing a single thing. There's no need for every single FT to test
31-
the login/logout mechanisms. If we can figure out a way to "cheat" and skip
32-
that part, we'll spend less time waiting for duplicated test paths.
20+
This is about separation of concerns.
21+
Functional tests aren't like unit tests,
22+
in that they don't usually have a single assertion.
23+
But, conceptually, they should be testing a single thing.
24+
There's no need for every single FT to test the login/logout mechanisms.
25+
If we can figure out a way to "cheat" and skip that part,
26+
we'll spend less time waiting for duplicated test paths.
3327

3428
TIP: Don't overdo de-duplication in FTs. One of the benefits of an FT is that
3529
it can catch strange and unpredictable interactions between different
3630
parts of your application.
3731

3832

39-
NOTE: This chapter has only just been rewritten for the new edition, so let me
40-
know via [email protected] if you spot any problems or have any
41-
suggestions for improvement!
42-
43-
44-
Skipping the Login Process by Pre-creating a Session
45-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4633

34+
=== Skipping the Login Process by Pre-creating a Session
4735

4836

49-
((("sessions, pre-creating", id="sessions20")))((("login process, skipping", seealso="authentication")))((("cookies")))It's
50-
quite common for a user to return to a site and still have a cookie, which
51-
means they are "pre-authenticated", so this isn't an unrealistic cheat at all.
37+
((("sessions, pre-creating", id="sessions20")))
38+
((("login process, skipping", seealso="authentication")))
39+
((("cookies")))
40+
It's quite common for a user to return to a site and still have a cookie,
41+
which means they are "pre-authenticated",
42+
so this isn't an unrealistic cheat at all.
5243
Here's how you can set it up:
5344

5445
[role="sourcecode"]
55-
.functional_tests/test_my_lists.py
46+
.src/functional_tests/test_my_lists.py
5647
====
5748
[source,python]
5849
----
@@ -138,7 +129,7 @@ in a [keep-together]#`./manage.py`# `shell` if you like:
138129
[role="skipme small-code"]
139130
[subs="specialcharacters,macros"]
140131
----
141-
$ pass:quotes[*python manage.py shell*]
132+
$ pass:quotes[*python src/manage.py shell*]
142133
[...]
143134
In [1]: from django.contrib.sessions.models import Session
144135
@@ -172,26 +163,23 @@ to pull them up into `FunctionalTest`. We'll also tweak them slightly so that
172163
they can take an arbitrary email address as a parameter:
173164

174165
[role="sourcecode"]
175-
.functional_tests/base.py (ch18l002)
166+
.src/functional_tests/base.py (ch20l002)
176167
====
177168
[source,python]
178169
----
179170
class FunctionalTest(StaticLiveServerTestCase):
180171
[...]
181172
182173
def wait_to_be_logged_in(self, email):
183-
self.wait_for(
184-
lambda: self.browser.find_element_by_link_text('Log out')
185-
)
186-
navbar = self.browser.find_element_by_css_selector('.navbar')
174+
self.wait_for(lambda: self.browser.find_element(By.LINK_TEXT, "Log out"))
175+
navbar = self.browser.find_element(By.CSS_SELECTOR, ".navbar")
187176
self.assertIn(email, navbar.text)
188177
189-
190178
def wait_to_be_logged_out(self, email):
191179
self.wait_for(
192-
lambda: self.browser.find_element_by_name('email')
180+
lambda: self.browser.find_element(By.CSS_SELECTOR, "input[name=email]")
193181
)
194-
navbar = self.browser.find_element_by_css_selector('.navbar')
182+
navbar = self.browser.find_element(By.CSS_SELECTOR, ".navbar")
195183
self.assertNotIn(email, navbar.text)
196184
----
197185
====
@@ -211,7 +199,7 @@ First we use them in 'test_login.py':
211199

212200

213201
[role="sourcecode"]
214-
.functional_tests/test_login.py (ch18l003)
202+
.src/functional_tests/test_login.py (ch20l003)
215203
====
216204
[source,python]
217205
----
@@ -221,7 +209,7 @@ First we use them in 'test_login.py':
221209
self.wait_to_be_logged_in(email=TEST_EMAIL)
222210
223211
# Now she logs out
224-
self.browser.find_element_by_link_text('Log out').click()
212+
self.browser.find_element(By.LINK_TEXT, "Log out").click()
225213
226214
# She is logged out
227215
self.wait_to_be_logged_out(email=TEST_EMAIL)
@@ -233,7 +221,7 @@ Just to make sure we haven't broken anything, we rerun the login test:
233221

234222
[subs="specialcharacters,macros"]
235223
----
236-
$ pass:quotes[*python manage.py test functional_tests.test_login*]
224+
$ pass:quotes[*python src/manage.py test functional_tests.test_login*]
237225
[...]
238226
OK
239227
----
@@ -242,12 +230,12 @@ And now we can write a placeholder for the "My Lists" test, to see if
242230
our pre-authenticated session creator really does work:
243231

244232
[role="sourcecode"]
245-
.functional_tests/test_my_lists.py (ch18l004)
233+
.src/functional_tests/test_my_lists.py (ch20l004)
246234
====
247235
[source,python]
248236
----
249237
def test_logged_in_users_lists_are_saved_as_my_lists(self):
250-
238+
251239
self.browser.get(self.live_server_url)
252240
self.wait_to_be_logged_out(email)
253241
@@ -262,7 +250,7 @@ That gets us:
262250

263251
[subs="specialcharacters,macros"]
264252
----
265-
$ pass:quotes[*python manage.py test functional_tests.test_my_lists*]
253+
$ pass:quotes[*python src/manage.py test functional_tests.test_my_lists*]
266254
[...]
267255
OK
268256
----
@@ -328,28 +316,26 @@ pass:[<code>wait_for_row_&#x200b;in_list_table</code>] and the inline `self.wait
328316

329317

330318
[role="sourcecode"]
331-
.functional_tests/base.py (ch18l005)
319+
.src/functional_tests/base.py (ch20l005)
332320
====
333321
[source,python]
334322
----
335323
@wait
336324
def wait_for_row_in_list_table(self, row_text):
337-
table = self.browser.find_element_by_id('id_list_table')
338-
rows = table.find_elements_by_tag_name('tr')
325+
table = self.browser.find_element(By.ID, "id_list_table")
326+
rows = table.find_elements(By.TAG_NAME, "tr")
339327
self.assertIn(row_text, [row.text for row in rows])
340328
341-
342329
@wait
343330
def wait_to_be_logged_in(self, email):
344-
self.browser.find_element_by_link_text('Log out')
345-
navbar = self.browser.find_element_by_css_selector('.navbar')
331+
self.browser.find_element(By.LINK_TEXT, "Log out")
332+
navbar = self.browser.find_element(By.CSS_SELECTOR, ".navbar")
346333
self.assertIn(email, navbar.text)
347334
348-
349335
@wait
350336
def wait_to_be_logged_out(self, email):
351-
self.browser.find_element_by_name('email')
352-
navbar = self.browser.find_element_by_css_selector('.navbar')
337+
self.browser.find_element(By.CSS_SELECTOR, "input[name=email]")
338+
navbar = self.browser.find_element(By.CSS_SELECTOR, ".navbar")
353339
self.assertNotIn(email, navbar.text)
354340
----
355341
====
@@ -371,7 +357,7 @@ timeout occurs. Here's a first cut:
371357

372358

373359
[role="sourcecode"]
374-
.functional_tests/base.py (ch18l006)
360+
.src/functional_tests/base.py (ch20l006)
375361
====
376362
[source,python]
377363
----
@@ -409,7 +395,7 @@ That's 'almost' right, but not quite; try running it?
409395

410396
[subs="specialcharacters,macros"]
411397
----
412-
$ pass:quotes[*python manage.py test functional_tests.test_my_lists*]
398+
$ pass:quotes[*python src/manage.py test functional_tests.test_my_lists*]
413399
[...]
414400
self.wait_to_be_logged_out(email)
415401
TypeError: modified_fn() takes 0 positional arguments but 2 were given
@@ -422,13 +408,13 @@ that have [keep-together]#arguments#:
422408

423409

424410
[role="sourcecode currentcontents"]
425-
.functional_tests/base.py
411+
.src/functional_tests/base.py
426412
====
427413
[source,python]
428414
----
429415
@wait
430416
def wait_to_be_logged_in(self, email):
431-
self.browser.find_element_by_link_text('Log out')
417+
self.browser.find_element(By.LINK_TEXT, "Log out").click()
432418
----
433419
====
434420

@@ -445,7 +431,7 @@ arguments"], apparently (I only just learned that):
445431

446432

447433
[role="sourcecode"]
448-
.functional_tests/base.py (ch18l007)
434+
.src/functional_tests/base.py (ch20l007)
449435
====
450436
[source,python]
451437
----
@@ -476,7 +462,7 @@ is that our decorator now works:
476462

477463
[subs="specialcharacters,macros"]
478464
----
479-
$ pass:quotes[*python manage.py test functional_tests.test_my_lists*]
465+
$ pass:quotes[*python src/manage.py test functional_tests.test_my_lists*]
480466
[...]
481467
OK
482468
----
@@ -487,7 +473,7 @@ for our `self.wait_for` helper as well! Like this:
487473

488474

489475
[role="sourcecode"]
490-
.functional_tests/base.py (ch18l008)
476+
.src/functional_tests/base.py (ch20l008)
491477
====
492478
[source,python]
493479
----

0 commit comments

Comments
 (0)