@@ -12,9 +12,9 @@ We will start from `05-custom-commands`.
1212npm install
1313```
1414
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:
1616
17- ### ./cypress/e2e/hotel-edit.spec.ts
17+ _ ./cypress/e2e/hotel-edit.spec.ts _
1818
1919``` javascript
2020describe (' Hotel edit specs' , () => {
@@ -26,9 +26,9 @@ describe('Hotel edit specs', () => {
2626});
2727```
2828
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:
3030
31- ### ./src/pods/hotel-collection/components/hotel-card.component.tsx
31+ _ ./src/pods/hotel-collection/components/hotel-card.component.tsx _
3232
3333``` diff
3434...
@@ -42,260 +42,126 @@ describe('Hotel edit specs', () => {
4242 </CardActions>
4343```
4444
45- - Add spec:
45+ Add spec:
4646
47- ### ./cypress/e2e/hotel-edit.spec.ts
47+ _ ./cypress/e2e/hotel-edit.spec.ts _
4848
4949``` diff
5050...
5151 it('should navigate to second hotel when click on edit second hotel', () => {
5252 // Arrange
53+ + cy.intercept('GET', '/api/hotels').as('fetchHotels');
5354
5455 // 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();
5961
6062 // Assert
6163+ cy.url().should('equal', 'http://localhost:8080/#/hotel-edit/2');
6264 });
6365
6466```
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+ >
6673> [ Official docs] ( https://docs.cypress.io/api/commands/then )
6774
68- - Add update hotel spec:
75+ Add update hotel spec:
6976
70- ### ./cypress/e2e/hotel-edit.spec.ts
77+ _ ./cypress/e2e/hotel-edit.spec.ts _
7178
7279``` diff
7380...
7481+ it('should update hotel name when it edits an hotel and click on save button', () => {
7582+ // Arrange
83+ + cy.intercept('GET', '/api/hotels').as('fetchHotels');
7684
7785+ // 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( );
8391
8492+ cy.findByLabelText('Name').clear().type('Updated hotel two');
85-
8693+ cy.findByRole('button', { name: 'Save' }).click();
8794
8895+ // Assert
8996+ cy.findByText('Updated hotel two');
9097+ });
9198```
9299
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:
94101
95- ### ./cypress/e2e/hotel-edit.spec.ts
102+ _ ./cypress/e2e/hotel-edit.spec.ts _
96103
97104``` diff
98105...
99106 it('should update hotel name when it edits an hotel and click on save button', () => {
100107 // 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');
101111
102112 // 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();
104118
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');
113121
114122 cy.findByLabelText('Name').clear().type('Updated hotel two');
115-
116123 cy.findByRole('button', { name: 'Save' }).click();
117124
118125 // Assert
119- + cy.wait('@load '); // TODO: Refactor custom command loadAndVisit
126+ + cy.wait('@fetchHotels ');
120127 cy.findByText('Updated hotel two');
121128 });
122129```
123130
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.
197132
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 :
199134
200- ### ./cypress/e2e/hotel-edit.spec.ts
135+ _ ./cypress/e2e/hotel-edit.spec.ts _
201136
202137``` diff
203138...
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-
219139 it('should update hotel name when it edits an hotel and click on save button', () => {
220140 // 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');
221144
222145 // 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();
247151
248- cy.findByLabelText('Name').clear().type('Updated hotel two');
152+ cy.wait('@fetchHotel');
153+ cy.wait('@fetchCities');
249154
155+ + cy.findByLabelText('Name').should('not.have.value', '');
156+ cy.findByLabelText('Name').clear().type('Updated hotel two');
250157 cy.findByRole('button', { name: 'Save' }).click();
251158
252159 // Assert
253- - cy.wait('@load'); // TODO: Refactor custom command loadAndVisit
254- + cy.wait('@loadHotels');
160+ cy.wait('@fetchHotels');
255161 cy.findByText('Updated hotel two');
256162 });
257163```
258164
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-
299165# About Basefactor + Lemoncode
300166
301167We are an innovating team of Javascript experts, passionate about turning your ideas into robust products.
0 commit comments