@@ -12,9 +12,9 @@ We will start from `05-custom-commands`.
12
12
npm install
13
13
```
14
14
15
- - To edit an hotel we need to visit ` hotels ` and click on edit button:
15
+ To edit an hotel we need to visit ` hotels ` and click on edit button:
16
16
17
- ### ./cypress/e2e/hotel-edit.spec.ts
17
+ _ ./cypress/e2e/hotel-edit.spec.ts _
18
18
19
19
``` javascript
20
20
describe (' Hotel edit specs' , () => {
@@ -26,9 +26,9 @@ describe('Hotel edit specs', () => {
26
26
});
27
27
```
28
28
29
- - To get available ` edit button selector ` , we need to add accessibility label:
29
+ To get available ` edit button selector ` , we need to add accessibility label:
30
30
31
- ### ./src/pods/hotel-collection/components/hotel-card.component.tsx
31
+ _ ./src/pods/hotel-collection/components/hotel-card.component.tsx _
32
32
33
33
``` diff
34
34
...
@@ -42,260 +42,126 @@ describe('Hotel edit specs', () => {
42
42
</CardActions>
43
43
```
44
44
45
- - Add spec:
45
+ Add spec:
46
46
47
- ### ./cypress/e2e/hotel-edit.spec.ts
47
+ _ ./cypress/e2e/hotel-edit.spec.ts _
48
48
49
49
``` diff
50
50
...
51
51
it('should navigate to second hotel when click on edit second hotel', () => {
52
52
// Arrange
53
+ + cy.intercept('GET', '/api/hotels').as('fetchHotels');
53
54
54
55
// Act
55
- + cy.loadAndVisit('/api/hotels', '/hotel-collection');
56
- + cy.findAllByRole('button', { name: 'Edit hotel' }).then((buttons) => {
57
- + buttons[1].click();
58
- + });
56
+ + cy.visit('/hotel-collection');
57
+ + cy.wait('@fetchHotels');
58
+ + cy.findAllByRole('button', { name: /edit hotel/i })
59
+ + .eq(1)
60
+ + .click();
59
61
60
62
// Assert
61
63
+ cy.url().should('equal', 'http://localhost:8080/#/hotel-edit/2');
62
64
});
63
65
64
66
```
65
-
67
+ > [ eq command] ( https://docs.cypress.io/api/commands/eq )
68
+ >
69
+ > See also:
70
+ >
71
+ > ` cy.findAllByRole('button', { name: 'Edit hotel' }).then((buttons) => { buttons[1].click(); }); `
72
+ >
66
73
> [ Official docs] ( https://docs.cypress.io/api/commands/then )
67
74
68
- - Add update hotel spec:
75
+ Add update hotel spec:
69
76
70
- ### ./cypress/e2e/hotel-edit.spec.ts
77
+ _ ./cypress/e2e/hotel-edit.spec.ts _
71
78
72
79
``` diff
73
80
...
74
81
+ it('should update hotel name when it edits an hotel and click on save button', () => {
75
82
+ // Arrange
83
+ + cy.intercept('GET', '/api/hotels').as('fetchHotels');
76
84
77
85
+ // Act
78
- + cy.loadAndVisit('/api/hotels', '/hotel-collection');
79
-
80
- + cy.findAllByRole('button', { name: 'Edit hotel' }).then(($buttons) => {
81
- + $buttons[1].click();
82
- + } );
86
+ + cy.visit( '/hotel-collection');
87
+ + cy.wait('@fetchHotels');
88
+ + cy.findAllByRole('button', { name: /edit hotel/i })
89
+ + .eq(1)
90
+ + .click( );
83
91
84
92
+ cy.findByLabelText('Name').clear().type('Updated hotel two');
85
-
86
93
+ cy.findByRole('button', { name: 'Save' }).click();
87
94
88
95
+ // Assert
89
96
+ cy.findByText('Updated hotel two');
90
97
+ });
91
98
```
92
99
93
- - The previous spec could works or not, due to we are not waiting to be resolved the get hotel request. If we change network to ` Fast 3G ` on ` Chrome options ` to simulate it, we will need do something like :
100
+ The previous spec could works or not, due to we are not waiting to be resolved the get hotel request:
94
101
95
- ### ./cypress/e2e/hotel-edit.spec.ts
102
+ _ ./cypress/e2e/hotel-edit.spec.ts _
96
103
97
104
``` diff
98
105
...
99
106
it('should update hotel name when it edits an hotel and click on save button', () => {
100
107
// Arrange
108
+ cy.intercept('GET', '/api/hotels').as('fetchHotels');
109
+ + cy.intercept('GET', '/api/hotels/2').as('fetchHotel');
110
+ + cy.intercept('GET', '/api/cities').as('fetchCities');
101
111
102
112
// Act
103
- cy.loadAndVisit('/api/hotels', '/hotel-collection');
113
+ cy.visit('/hotel-collection');
114
+ cy.wait('@fetchHotels');
115
+ cy.findAllByRole('button', { name: /edit hotel/i })
116
+ .eq(1)
117
+ .click();
104
118
105
- + cy.intercept('GET', '/api/hotels/2').as('loadHotel');
106
-
107
- cy.findAllByRole('button', { name: 'Edit hotel' }).then(($buttons) => {
108
- $buttons[1].click();
109
- });
110
-
111
- + cy.wait('@loadHotel');
112
- + cy.findByLabelText('Name').should('not.have.value', '');
119
+ + cy.wait('@fetchHotel');
120
+ + cy.wait('@fetchCities');
113
121
114
122
cy.findByLabelText('Name').clear().type('Updated hotel two');
115
-
116
123
cy.findByRole('button', { name: 'Save' }).click();
117
124
118
125
// Assert
119
- + cy.wait('@load '); // TODO: Refactor custom command loadAndVisit
126
+ + cy.wait('@fetchHotels ');
120
127
cy.findByText('Updated hotel two');
121
128
});
122
129
```
123
130
124
- > Notice: some this has to wait until it has some value.
125
- >
126
- > [ Wait default timeouts] ( https://docs.cypress.io/guides/references/configuration#Timeouts )
127
-
128
- - Refactor command:
129
-
130
- ### ./cypress/support/commands.ts
131
-
132
- ``` diff
133
- + interface Resource {
134
- + path: string;
135
- + fixture?: string;
136
- + alias?: string;
137
- + }
138
-
139
- Cypress.Commands.add(
140
- 'loadAndVisit',
141
- - (apiPath: string, routePath: string, fixture?: string) => {
142
- + (visitUrl: string, resources: Resource[], callbackAfterVisit?: () => void) => {
143
- - Boolean(fixture)
144
- - ? cy.intercept('GET', apiPath, { fixture }).as('load')
145
- - : cy.intercept('GET', apiPath).as('load');
146
- + const aliasList = resources.map((resource, index) => {
147
- + const alias = resource.alias || `load-${index}`;
148
- + Boolean(resource.fixture)
149
- + ? cy
150
- + .intercept('GET', resource.path, { fixture: resource.fixture })
151
- + .as(alias)
152
- + : cy.intercept('GET', resource.path).as(alias);
153
-
154
- + return alias;
155
- + });
156
-
157
- - cy.visit(routePath);
158
- + cy.visit(visitUrl);
159
- + if (callbackAfterVisit) {
160
- + callbackAfterVisit();
161
- + }
162
-
163
- - cy.wait('@load');
164
- + aliasList.forEach((alias) => {
165
- + cy.wait(`@${alias}`);
166
- + });
167
- }
168
- );
169
-
170
- ```
171
-
172
- - Update ` d.ts ` :
173
-
174
- ### ./cypress/support/index.d.ts
175
-
176
- ``` diff
177
- declare namespace Cypress {
178
- + interface Resource {
179
- + path: string;
180
- + fixture?: string;
181
- + alias?: string;
182
- + }
183
-
184
- interface Chainable {
185
- loadAndVisit(
186
- - apiPath: string,
187
- + visitUrl: string,
188
- - routePath: string,
189
- + resources: Resource[],
190
- - fixture?: string
191
- + callbackAfterVisit?: () => void
192
- ): Chainable<Element>;
193
- }
194
- }
195
-
196
- ```
131
+ But if we change network to ` Fast 4G ` on ` Chrome options ` to simulate a device with a slow connection, it will fail. Because it takes more time to render the hotel page with the new values from the server and the spec is not waiting for it.
197
132
198
- - Update specs :
133
+ In this case, we can use a selector to wait for the component to have some value before writing the new one :
199
134
200
- ### ./cypress/e2e/hotel-edit.spec.ts
135
+ _ ./cypress/e2e/hotel-edit.spec.ts _
201
136
202
137
``` diff
203
138
...
204
- it('should navigate to second hotel when click on edit second hotel', () => {
205
- // Arrange
206
-
207
- // Act
208
- - cy.loadAndVisit('/api/hotels', '/hotel-collection');
209
- + cy.loadAndVisit('/hotel-collection', [{ path: '/api/hotels' }]);
210
-
211
- cy.findAllByRole('button', { name: 'Edit hotel' }).then(($buttons) => {
212
- $buttons[1].click();
213
- });
214
-
215
- // Assert
216
- cy.url().should('eq', 'http://localhost:8080/#/hotel-edit/2');
217
- });
218
-
219
139
it('should update hotel name when it edits an hotel and click on save button', () => {
220
140
// Arrange
141
+ cy.intercept('GET', '/api/hotels').as('fetchHotels');
142
+ cy.intercept('GET', '/api/hotels/2').as('fetchHotel');
143
+ cy.intercept('GET', '/api/cities').as('fetchCities');
221
144
222
145
// Act
223
- - cy.loadAndVisit('/api/hotels', '/hotel-collection');
224
- + cy.loadAndVisit(
225
- + '/hotel-collection',
226
- + [
227
- + { path: '/api/hotels', alias: 'loadHotels' },
228
- + { path: '/api/hotels/2' },
229
- + { path: '/api/cities' },
230
- + ],
231
- + () => {
232
- + cy.findAllByRole('button', { name: 'Edit hotel' }).then((buttons) => {
233
- + buttons[1].click();
234
- + });
235
- + }
236
- + );
237
-
238
- - cy.intercept('GET', '/api/hotels/2').as('loadHotel');
239
-
240
- - cy.findAllByRole('button', { name: 'Edit hotel' }).then(($buttons) => {
241
- - $buttons[1].click();
242
- - });
243
-
244
- - cy.wait('@loadHotel');
245
-
246
- cy.findByLabelText('Name').should('not.have.value', '');
146
+ cy.visit('/hotel-collection');
147
+ cy.wait('@fetchHotels');
148
+ cy.findAllByRole('button', { name: /edit hotel/i })
149
+ .eq(1)
150
+ .click();
247
151
248
- cy.findByLabelText('Name').clear().type('Updated hotel two');
152
+ cy.wait('@fetchHotel');
153
+ cy.wait('@fetchCities');
249
154
155
+ + cy.findByLabelText('Name').should('not.have.value', '');
156
+ cy.findByLabelText('Name').clear().type('Updated hotel two');
250
157
cy.findByRole('button', { name: 'Save' }).click();
251
158
252
159
// Assert
253
- - cy.wait('@load'); // TODO: Refactor custom command loadAndVisit
254
- + cy.wait('@loadHotels');
160
+ cy.wait('@fetchHotels');
255
161
cy.findByText('Updated hotel two');
256
162
});
257
163
```
258
164
259
- ### ./cypress/e2e/hotel-collection.spec.ts
260
-
261
- ``` diff
262
- ...
263
- it('should fetch hotel list and show it in screen when visit /hotel-collection url', () => {
264
- // Arrange
265
-
266
- // Act
267
- - cy.loadAndVisit('/api/hotels', '/hotel-collection');
268
- + cy.loadAndVisit('/hotel-collection', [{ path: '/api/hotels' }]);
269
-
270
- // Assert
271
- cy.findAllByRole('listitem').should('have.length', 10);
272
- });
273
-
274
- it('should fetch hotel list greater than 0 when visit /hotel-collection url', () => {
275
- // Arrange
276
-
277
- // Act
278
- - cy.loadAndVisit('/api/hotels', '/hotel-collection');
279
- + cy.loadAndVisit('/hotel-collection', [{ path: '/api/hotels' }]);
280
-
281
- // Assert
282
- cy.findAllByRole('listitem').should('have.length.greaterThan', 0);
283
- });
284
-
285
- it('should fetch two hotels when visit /hotel-collection url', () => {
286
- // Arrange
287
-
288
- // Act
289
- - cy.loadAndVisit('/api/hotels', '/hotel-collection', 'hotels.json');
290
- + cy.loadAndVisit('/hotel-collection', [
291
- + { path: '/api/hotels', fixture: 'hotels' },
292
- + ]);
293
-
294
- // Assert
295
- cy.findAllByRole('listitem').should('have.length', 2);
296
- });
297
- ```
298
-
299
165
# About Basefactor + Lemoncode
300
166
301
167
We are an innovating team of Javascript experts, passionate about turning your ideas into robust products.
0 commit comments