Skip to content

Commit 23d28fd

Browse files
Wrote Part 3 section 2
1 parent 6ddc335 commit 23d28fd

File tree

2 files changed

+118
-1
lines changed

2 files changed

+118
-1
lines changed

workshop/3-assertions.md

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,124 @@ The test should still pass.
7474

7575
## Checking the result links
7676

77-
TBD
77+
The next test step is, "And the search result links pertain to the phrase".
78+
It makes sure that the result links returned actually relate to the search phrase entered.
79+
An easy way to check this is to make sure the phrase appears in some of the result link titles.
80+
This will only work for simple phrases (one or two words with no punctuation),
81+
and not every result link may have a match.
82+
Nevertheless, our test is a basic search test,
83+
so its scope should cover only the most basic aspects of searching behavior.
84+
We would need to write other, more advanced tests if we wanted to use sharper assertions.
85+
86+
Typically, elements in a list share a common DOM structure and common CSS classes.
87+
Here's the inspection panel for result links:
88+
89+
![Inspecting the result link elements](images/inspect-result-links.png)
90+
91+
Result links are `a` elements with the class `result__a`.
92+
They are under `h2` elements with the class `result__title`.
93+
We could use the selector `.result__title a.result__a` to identify all result links on the page.
94+
(If you look in the DevTools search bar, you'll see that this selector locates 10 elements.)
95+
96+
Since we can get all elements with one selector,
97+
we can take the following steps to verify that search result links pertain to the phrase:
98+
99+
1. Wait for the first few result links to appear on the page.
100+
2. Scrape the text contents of the result link titles.
101+
3. Filter the titles that contain the search phrase.
102+
4. Verify that the list of filtered titles is nonempty.
103+
104+
In this case, we *must* do explicit waiting for multiple result links to appear.
105+
If we try to get text contents without waiting for all targets to appear, then some (or all) might be left out!
106+
This risk is small, but it is nonzero.
107+
Always safely mitigate potential race conditions with proper waiting.
108+
109+
Explicit waiting will be tricky.
110+
Add the following line to the test:
111+
112+
```python
113+
page.locator('.result__title a.result__a >> nth=4').wait_for()
114+
```
115+
116+
Let's break this down:
117+
118+
1. [`locator`](https://playwright.dev/python/docs/api/class-page#page-locator) is a method that returns a
119+
[`Locator`](https://playwright.dev/python/docs/api/class-locator) object for the target element.
120+
A `Locator` object can make many of the same calls as a page, like clicking and getting text.
121+
However, it can also make calls for explicit waiting and calls that target multiple elements.
122+
2. `.result__title a.result__a` is the selector for the result links.
123+
3. `>> nth=4` is an [N-th element selector](https://playwright.dev/python/docs/selectors#n-th-element-selector).
124+
N-th element selectors are zero-indexed and may be appended to any selector.
125+
In this `locator` call, it will fetch the fifth result link element.
126+
4. [`wait_for`](https://playwright.dev/python/docs/api/class-locator#locator-wait-for)
127+
is a method that will wait for the target element to be visible.
128+
129+
In summary, this line will wait for the fifth result link to become visible on the page.
130+
Why check for the fifth?
131+
Most DuckDuckGo searches return ten links, but sometimes, they return fewer.
132+
Waiting for five links to appear should be good enough for our testing purposes.
133+
134+
After the links appear, we can scrape their text contents like this:
135+
136+
```python
137+
titles = page.locator('.result__title a.result__a').all_text_contents()
138+
```
139+
140+
Again, we must use the `locator` method because we want to target a list of elements instead of one.
141+
This selector does *not* include the N-th element selector because we want to target all result links.
142+
The [`all_text_contents`](https://playwright.dev/python/docs/api/class-locator#locator-all-text-contents) method
143+
returns a list containing the text content of each located element.
144+
After this call, `titles` will be a list of strings of the titles we need to check!
145+
146+
Next, we can filter the list of titles to find the ones that contain the search phrase.
147+
For proper comparisons, the titles and the search phrase should all be lowercase.
148+
Add this line to the test:
149+
150+
```python
151+
matches = [t for t in titles if 'panda' in t.lower()]
152+
```
153+
154+
This is a Python [list comprehension](https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions).
155+
Basically, it filters `titles` for elements that contain the search phrase.
156+
If the lowercase version of a title contains the search phrase, then it is added to `matches`.
157+
Otherwise, it is omitted.
158+
159+
In the best case, all titles will match.
160+
However, in the real world, some titles may not include the full search phrase.
161+
Since ours is merely a basic search test, it should verify that at least one title matches.
162+
Add this assertion to the test:
163+
164+
```python
165+
assert len(matches) > 0
166+
```
167+
168+
The full test case should now look like this:
169+
170+
```python
171+
def test_basic_duckduckgo_search(page):
172+
173+
# Given the DuckDuckGo home page is displayed
174+
page.goto('https://www.duckduckgo.com')
175+
176+
# When the user searches for a phrase
177+
page.fill('#search_form_input_homepage', 'panda')
178+
page.click('#search_button_homepage')
179+
180+
# Then the search result query is the phrase
181+
assert 'panda' == page.input_value('#search_form_input')
182+
183+
# And the search result links pertain to the phrase
184+
page.locator('.result__title a.result__a >> nth=4').wait_for()
185+
titles = page.locator('.result__title a.result__a').all_text_contents()
186+
matches = [t for t in titles if 'panda' in t.lower()]
187+
assert len(matches) > 0
188+
189+
# And the search result title contains the phrase
190+
pass
191+
```
192+
193+
This step had the most complex code so far, but it still wasn't too bad.
194+
Rerun the test to make sure things still pass.
78195

79196

80197
## Checking the title
2.37 MB
Loading

0 commit comments

Comments
 (0)