You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/content/5/en/part5d.md
+33-34Lines changed: 33 additions & 34 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -24,28 +24,27 @@ Some tests might pass one time and fail another, even if the code does not chang
24
24
25
25
Perhaps the two easiest libraries for End to End testing at the moment are [Cypress](https://www.cypress.io/) and [Playwright](https://playwright.dev/).
26
26
27
-
From the statistics on [npmtrends.com](https://npmtrends.com/cypress-vs-playwright) we see that Cypress, which dominated the market for the last five years, is still the clear number one, but Playwright is on a rapid rise:
27
+
From the statistics on [npmtrends.com](https://npmtrends.com/cypress-vs-playwright) we see that Cypress, which dominated the market for the last five years, is still clearly the number one, but Playwright is on a rapid rise:
28
28
29
29

30
30
31
31
This course has been using Cypress for years. Now Playwright is a new addition. You can choose whether to complete the E2E testing part of the course with Cypress or Playwright. The operating principles of both libraries are very similar, so your choice is not very important. However, Playwright is now the preferred E2E library for the course.
32
32
33
33
If your choice is Playwright, please proceed. If you end up using Cypress, go [here](/en/part5/end_to_end_testing_cypress).
34
34
35
-
36
35
### Playwright
37
36
38
37
So [Playwright](https://playwright.dev/) is a newcomer to the End to End tests, which started to explode in popularity towards the end of 2023. Playwright is roughly on a par with Cypress in terms of ease of use. The libraries are slightly different in terms of how they work. Cypress is radically different from most libraries suitable for E2E testing, as Cypress tests are run entirely within the browser. Playwright's tests, on the other hand, are executed in the Node process, which is connected to the browser via programming interfaces.
39
38
40
39
Many blogs have been written about library comparisons, e.g. [this](https://www.lambdatest.com/blog/cypress-vs-playwright/) and [this](https://www.browserstack.com/guide/playwright-vs-cypress).
41
40
42
-
It is difficult to say which library is better. One advantage of Playwright is its browser support, Playwright supports Chrome, Firefox and Webkit-based browsers like Safari. Currently Cypress includes support for all these browsers, although Webkit support is experimental and does not support all Cypress features. At the time of writing (1.3.2024), my personal preference leans slightly towards Playwright.
41
+
It is difficult to say which library is better. One advantage of Playwright is its browser support; Playwright supports Chrome, Firefox and Webkit-based browsers like Safari. Currently, Cypress includes support for all these browsers, although Webkit support is experimental and does not support all of Cypress features. At the time of writing (1.3.2024), my personal preference leans slightly towards Playwright.
43
42
44
43
Now let's explore Playwright.
45
44
46
45
### Initializing tests
47
46
48
-
Unlike the backend tests or unit tests done on the React front-end, End to End tests do not need to be located in the same npm project where the code is. Let's make a completely separate project for the E2E tests with the _npm init_ command. Then install Playwright by running in the new project directory the command
47
+
Unlike the backend tests or unit tests done on the React front-end, End to End tests do not need to be located in the same npm project where the code is. Let's make a completely separate project for the E2E tests with the _npm init_ command. Then install Playwright by running in the new project directory the command:
49
48
50
49
```js
51
50
npm init playwright@latest
@@ -68,7 +67,7 @@ Let's define an npm script for running tests and test reports in _package.json_:
68
67
}
69
68
```
70
69
71
-
During installation, the following is printed to the console
70
+
During installation, the following is printed to the console:
72
71
73
72
```
74
73
And check out the following files:
@@ -77,7 +76,7 @@ And check out the following files:
77
76
- ./playwright.config.js - Playwright Test configuration
78
77
```
79
78
80
-
that is, the installation created a few example tests for the project.
79
+
that is, the location of a few example tests for the project that the installation has created.
81
80
82
81
Let's run the tests:
83
82
@@ -102,7 +101,7 @@ The tests pass. A more detailed test report can be opened either with the comman
102
101
npm run test:report
103
102
```
104
103
105
-
Tests can also be run via the graphical UI with a command
104
+
Tests can also be run via the graphical UI with the command:
The first line of the test function says that the tests are testing the page at https://playwright.dev/.
133
+
The first line of the test functions says that the tests are testing the page at https://playwright.dev/.
135
134
136
-
### Testing own code
135
+
### Testing our own code
137
136
138
137
Now let's remove the sample tests and start testing our own application.
139
138
140
-
Playwright tests assume that the system under test is running when the tests are executed, i.e. unlike e.g. backend integration tests, Playwright tests <i>do not start</i> the system under test during testing.
139
+
Playwright tests assume that the system under test is running when the tests are executed. Unlike, for example, backend integration tests, Playwright tests <i>do not start</i> the system under test during testing.
141
140
142
141
Let's make an npm script for the <i>backend</i>, which will enable it to be started in testing mode, i.e. so that <i>NODE\_ENV</i> gets the value <i>test</i>.
143
142
@@ -173,7 +172,7 @@ test('front page can be opened', async ({ page }) => {
173
172
})
174
173
```
175
174
176
-
First, the test opens the application with the method [page.goto](https://playwright.dev/docs/writing-tests#navigation). After this, the test uses the [page.getByText](https://playwright.dev/docs/api/class-page#page-get-by-text) to get a [locator](https://playwright.dev/docs/locators) that corresponds to the element where the text <i>Notes</i> is found.
175
+
First, the test opens the application with the method [page.goto](https://playwright.dev/docs/writing-tests#navigation). After this, it uses the [page.getByText](https://playwright.dev/docs/api/class-page#page-get-by-text) to get a [locator](https://playwright.dev/docs/locators) that corresponds to the element where the text <i>Notes</i> is found.
177
176
178
177
The method [toBeVisible](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-be-visible) ensures that the element corresponding to the locator is visible at the page.
179
178
@@ -193,28 +192,28 @@ test('front page can be opened', async ({ page }) => {
193
192
})
194
193
```
195
194
196
-
As expected, the test fails. Playwright opens the test report in the browser and it becomes clear that Playwright has actually performed the tests with three different browsers: Chrome, one Firefox and Webkit, i.e. the browser engine used by Safari:
195
+
As expected, the test fails. Playwright opens the test report in the browser and it becomes clear that Playwright has actually performed the tests with three different browsers: Chrome, Firefox and Webkit, i.e. the browser engine used by Safari:
197
196
198
-

197
+

199
198
200
199
By clicking on the report of one of the browsers, we can see a more detailed error message:
201
200
202
-

201
+

203
202
204
-
In the big picture, it is of course a very good thing that the testing takes place with all three commonly used browser engines, but this is slow, and when developing the tests it is probably best to carry out the tests mainly with only one browser. You can define the browser engine to be used with the command line parameter:
203
+
In the big picture, it is of course a very good thing that the testing takes place with all three commonly used browser engines, but this is slow, and when developing the tests it is probably best to carry them out mainly with only one browser. You can define the browser engine to be used with the command line parameter:
205
204
206
205
```js
207
206
npm test ----project chromium
208
207
```
209
208
210
-
Now let's correct the outdated year in the frontend code that caused the error in the code.
209
+
Now let's correct the outdated year in the frontend code that caused the error.
211
210
212
211
Before we continue, let's add a _describe_ block to the tests:
test('front page can be opened', async ({ page }) => {
219
218
awaitpage.goto('http://localhost:5173')
220
219
@@ -225,7 +224,7 @@ describe('Note app', () => {
225
224
})
226
225
```
227
226
228
-
Before we move on, let's break the tests one more time. We notice that the execution of the tests is quite fast when the tests pass, but much slower if the tests do not pass. The reason for this is that Playwright's policy is to wait for searched elements until [they are rendered and ready for action](https://playwright.dev/docs/actionability). If the element is not found, a _TimeoutError_ is raised and the test fails. Playwright waits for elements by default for 5 or 30 seconds [depending on the functions used in testing](https://playwright.dev/docs/test-timeouts#introduction).
227
+
Before we move on, let's break the tests one more time. We notice that the execution of the tests is quite fast when they pass, but much slower if the they do not pass. The reason for this is that Playwright's policy is to wait for searched elements until [they are rendered and ready for action](https://playwright.dev/docs/actionability). If the element is not found, a _TimeoutError_ is raised and the test fails. Playwright waits for elements by default for 5 or 30 seconds [depending on the functions used in testing](https://playwright.dev/docs/test-timeouts#introduction).
229
228
230
229
When developing tests, it may be wiser to reduce the waiting time to a few seconds. According to the [documentation](https://playwright.dev/docs/test-timeouts), this can be done by changing the file _playwright.config.js_ as follows:
231
230
@@ -242,7 +241,7 @@ We also made two other changes to the file, and specified that all tests [be exe
242
241
243
242
### Writing on the form
244
243
245
-
Let's expand the tests so that the test tries to log into the application. Let's assume that a user is stored in the database, with username <i>mluukkai</i> and password <i>salainen</i>.
244
+
Let's write a new test that tries to log into the application. Let's assume that a user is stored in the database, with username <i>mluukkai</i> and password <i>salainen</i>.
246
245
247
246
Let's start by opening the login form.
248
247
@@ -268,11 +267,11 @@ npm test -- --ui
268
267
269
268
We now see that the test finds the button
270
269
271
-

270
+

272
271
273
272
After clicking, the form will appear
274
273
275
-

274
+

276
275
277
276
When the form is opened, the test should look for the text fields and enter the username and password in them. Let's make the first attempt using the method [page.getByRole](https://playwright.dev/docs/api/class-page#page-get-by-role):
Both this and the previous version of the test work. However, both are problematic to the extent that if the registration form is changed, the tests may break, as they rely on the fields to be on the page in a certain order.
344
346
345
-
A better solution is to define unique test id attributes for the fields, and search the fields in the tests based on them using the method [getByTestId](https://playwright.dev/docs/api/class-page#page-get-by-test-id).
347
+
A better solution is to define unique test id attributes for the fields, to search for them in the tests using the method [getByTestId](https://playwright.dev/docs/api/class-page#page-get-by-test-id).
Note that passing the test at this stage requires that there is a user in the <i>test</i> database of the backend with username <i>mluukkai</i> and password <i>salainen</i>. Create a user if needed!
402
404
403
-
Initialization of tests
404
-
405
405
Since both tests start in the same way, i.e. by opening the page <i>http://localhost:5173</i>, it is recommended to isolate the common part in the <i>beforeEach</i> block that is executed before each test:
The test is defined in its own _describe_ block. Creating a note requires that the user is logged in, and the login is handled in the _beforeEach_ block.
461
+
The test is defined in its own _describe_ block. Creating a note requires that the user is logged in, which is handled in the _beforeEach_ block.
464
462
465
-
The test trusts that when creating a new note there is only one input field on the page, i.e. it searches for the field as follows
463
+
The test trusts that when creating a new note, there is only one input field on the page, so it searches for it as follows:
466
464
467
465
```js
468
466
page.getByRole('textbox')
469
467
```
470
468
471
-
If there were more fields, the test would break. Because of this, it would be better to add a test-id to the field of the form and search for the field in the test based on the id.
469
+
If there were more fields, the test would break. Because of this, it would be better to add a test-id to the form input and search for it in the test based on this id.
472
470
473
-
**Note:** the test will only pass the first time. The reason for this is that expectation
471
+
**Note:** the test will only pass the first time. The reason for this is that its expectation
474
472
475
473
```js
476
474
awaitexpect(page.getByText('a note created by playwright')).toBeVisible()
@@ -510,7 +508,6 @@ describe('Note app', () => {
510
508
})
511
509
})
512
510
})
513
-
514
511
```
515
512
516
513
Since we have prevented the tests from running in parallel, Playwright runs the tests in the order they appear in the test code. That is, first the test <i>user can log in</i>, where the user logs into the application, is performed. After this the test <i>a new note can be created</i> gets executed, which also does a log in, in the <i>beforeEach</i> block. Why is this done, isn't the user already logged in thanks to the previous test? No, because the execution of <i>each</i> test starts from the browser's "zero state", all changes made to the browser's state by the previous tests are reset.
0 commit comments