Skip to content

Commit a11700f

Browse files
❄️ Fix flaky async integration tests for amp-bind (#40372)
1 parent 74f5ef3 commit a11700f

File tree

1 file changed

+62
-51
lines changed

1 file changed

+62
-51
lines changed

test/integration/test-amp-bind.js

Lines changed: 62 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import {BrowserController} from '#testing/helpers/service';
22
import {poll as classicPoll} from '#testing/iframe';
33

4-
const TIMEOUT = 10000;
4+
const TIMEOUT = 2000;
55

66
describes.sandboxed('amp-bind', {}, function () {
77
this.timeout(TIMEOUT);
88

99
// Helper that sets the poll timeout.
1010
function poll(desc, condition, onError) {
11-
return classicPoll(desc, condition, onError, TIMEOUT);
11+
return classicPoll(desc, condition, onError, 800);
1212
}
1313

1414
describes.integration(
@@ -32,33 +32,39 @@ describes.sandboxed('amp-bind', {}, function () {
3232
browser = new BrowserController(env.win);
3333
});
3434

35-
it('[text]', function* () {
35+
it('[text]', async () => {
3636
expect(text.textContent).to.equal('before_text');
37-
yield browser.wait(200);
37+
await browser.wait(200);
3838
browser.click('#changeText');
39-
yield poll('[text]', () => text.textContent === 'after_text');
39+
await poll('[text]', () => text.textContent === 'after_text').should.be
40+
.fulfilled;
4041
});
4142

42-
it('[class]', function* () {
43+
it('[class]', async () => {
4344
expect(text.className).to.equal('before_class');
44-
yield browser.wait(200);
45+
await browser.wait(200);
4546
browser.click('#changeClass');
46-
yield poll('[class]', () => text.className === 'after_class');
47+
await poll('[class]', () => text.className === 'after_class').should.be
48+
.fulfilled;
4749
});
4850
}
4951
);
5052

53+
const BEFORE_IMG_DATA_URL =
54+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAAAAACPAi4CAAAABGdBTUEAALGPC/xhBQAAABtJREFUWAntwYEAAAAAw6D7Uw/hAtUAAAAAjgAQQAABWWUZmwAAAABJRU5ErkJggg==';
55+
const AFTER_IMG_DATA_URL =
56+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAAAAACPAi4CAAAABGdBTUEAALGPC/xhBQAAAClJREFUWMPtzEERAAAMAiD7l9YQ++0gAOlRBAKBQCAQCAQCgUAgEHwPBqcL8OI+wmxEAAAAAElFTkSuQmCC';
5157
describes.integration(
5258
'+ amp-img',
5359
{
5460
body: `
5561
<amp-img id="image" layout="responsive"
56-
src="http://example.com/before.jpg" [src]="src"
62+
src="${BEFORE_IMG_DATA_URL}" [src]="src"
5763
alt="before_alt" [alt]="alt"
5864
width="1" [width]="w"
5965
height="1" [height]="h"></amp-img>
6066
61-
<button on="tap:AMP.setState({src: 'http://example.com/after.jpg'})" id="changeSrc"></button>
67+
<button on="tap:AMP.setState({src: '${AFTER_IMG_DATA_URL}'})" id="changeSrc"></button>
6268
<button on="tap:AMP.setState({alt: 'after_alt'})" id="changeAlt"></button>
6369
<button on="tap:AMP.setState({w: 2, h: 2})" id="changeSize"></button>
6470
`,
@@ -72,34 +78,33 @@ describes.sandboxed('amp-bind', {}, function () {
7278
img = doc.querySelector('amp-img');
7379
});
7480

75-
it('[src] with valid URL', () => {
81+
it('[src] with valid URL', async () => {
7682
const button = doc.getElementById('changeSrc');
77-
expect(img.getAttribute('src')).to.equal(
78-
'http://example.com/before.jpg'
79-
);
83+
expect(img.getAttribute('src')).to.equal(BEFORE_IMG_DATA_URL);
8084
button.click();
81-
return poll(
85+
await poll(
8286
'[src]',
83-
() => img.getAttribute('src') === 'http://example.com/after.jpg'
84-
);
87+
() => img.getAttribute('src') === AFTER_IMG_DATA_URL
88+
).should.be.fulfilled;
8589
});
8690

87-
it('[alt]', () => {
91+
it('[alt]', async () => {
8892
const button = doc.getElementById('changeAlt');
8993
expect(img.getAttribute('alt')).to.equal('before_alt');
9094
button.click();
91-
return poll('[src]', () => img.getAttribute('alt') === 'after_alt');
95+
await poll('[src]', () => img.getAttribute('alt') === 'after_alt')
96+
.should.be.fulfilled;
9297
});
9398

94-
it('[width] and [height]', () => {
99+
it('[width] and [height]', async () => {
95100
const button = doc.getElementById('changeSize');
96101
expect(img.getAttribute('width')).to.equal('1');
97102
expect(img.getAttribute('height')).to.equal('1');
98103
button.click();
99-
return Promise.all([
104+
await Promise.all([
100105
poll('[width]', () => img.getAttribute('width') === '2'),
101106
poll('[height]', () => img.getAttribute('height') === '2'),
102-
]);
107+
]).should.be.fulfilled;
103108
});
104109
}
105110
);
@@ -127,26 +132,28 @@ describes.sandboxed('amp-bind', {}, function () {
127132
doc = env.win.document;
128133
});
129134

130-
it('input[type=range] on:change', () => {
135+
it('input[type=range] on:change', async () => {
131136
const rangeText = doc.getElementById('range');
132137
const range = doc.querySelector('input[type="range"]');
133138
expect(rangeText.textContent).to.equal('before_range');
134139
// Calling #click() on the range element will not generate a change event,
135140
// so it must be generated manually.
136141
range.value = 47;
137142
range.dispatchEvent(new Event('change', {bubbles: true}));
138-
poll('[text]', () => rangeText.textContent === '0 <= 47 <= 100');
143+
await poll('[text]', () => rangeText.textContent === '0 <= 47 <= 100')
144+
.should.be.fulfilled;
139145
});
140146

141-
it('input[type=checkbox] on:change', () => {
147+
it('input[type=checkbox] on:change', async () => {
142148
const checkboxText = doc.getElementById('checkbox');
143149
const checkbox = doc.querySelector('input[type="checkbox"]');
144150
expect(checkboxText.textContent).to.equal('before_check');
145151
checkbox.click();
146-
poll('[text]', () => checkboxText.textContent === 'checked: true');
152+
await poll('[text]', () => checkboxText.textContent === 'checked: true')
153+
.should.be.fulfilled;
147154
});
148155

149-
it('[checked]', function* () {
156+
it('[checked]', async () => {
150157
const checkbox = doc.querySelector('input[type="checkbox"]');
151158
const button = doc.querySelector('button');
152159

@@ -156,21 +163,22 @@ describes.sandboxed('amp-bind', {}, function () {
156163
expect(checkbox.checked).to.be.true;
157164

158165
button.click();
159-
yield poll('[checked]', () => !checkbox.checked);
166+
await poll('[checked]', () => !checkbox.checked).should.be.fulfilled;
160167
expect(checkbox.hasAttribute('checked')).to.be.false;
161168

162169
button.click();
163-
yield poll('[checked]', () => checkbox.checked);
170+
await poll('[checked]', () => checkbox.checked).should.be.fulfilled;
164171
// amp-bind sets both the attribute and property.
165172
expect(checkbox.hasAttribute('checked')).to.be.true;
166173
});
167174

168-
it('input[type=radio] on:change', () => {
175+
it('input[type=radio] on:change', async () => {
169176
const radioText = doc.getElementById('radio');
170177
const radio = doc.querySelector('input[type="radio"]');
171178
expect(radioText.textContent).to.equal('before_radio');
172179
radio.click();
173-
poll('[text]', () => radioText.textContent === 'checked: true');
180+
await poll('[text]', () => radioText.textContent === 'checked: true')
181+
.should.be.fulfilled;
174182
});
175183
}
176184
);
@@ -192,26 +200,27 @@ describes.sandboxed('amp-bind', {}, function () {
192200
(env) => {
193201
let doc, carousel, slideText;
194202

195-
beforeEach(() => {
203+
beforeEach(async () => {
196204
doc = env.win.document;
197205
carousel = doc.querySelector('amp-carousel');
198206
slideText = doc.querySelector('p');
199207

200208
const browserController = new BrowserController(env.win);
201-
return browserController.waitForElementLayout('amp-carousel');
209+
await browserController.waitForElementLayout('amp-carousel');
202210
});
203211

204-
it('on:slideChange', () => {
212+
it('on:slideChange', async () => {
205213
expect(slideText.textContent).to.equal('0');
206214

207215
const nextSlide = carousel.querySelector(
208216
'div.amp-carousel-button-next'
209217
);
210218
nextSlide.click();
211-
return poll('[slide]', () => slideText.textContent === '1');
219+
await poll('[slide]', () => slideText.textContent === '1').should.be
220+
.fulfilled;
212221
});
213222

214-
it('[slide]', function* () {
223+
it('[slide]', async () => {
215224
const slides = carousel.querySelectorAll(
216225
'.i-amphtml-slide-item > amp-img'
217226
);
@@ -224,14 +233,14 @@ describes.sandboxed('amp-bind', {}, function () {
224233
const button = doc.getElementById('goToSlideOne');
225234
button.click();
226235

227-
yield poll(
236+
await poll(
228237
'[slide]',
229238
() => first.getAttribute('aria-hidden') === 'true'
230-
);
231-
yield poll(
239+
).should.be.fulfilled;
240+
await poll(
232241
'[slide]',
233242
() => second.getAttribute('aria-hidden') === 'false'
234-
);
243+
).should.be.fulfilled;
235244
});
236245
}
237246
);
@@ -261,17 +270,17 @@ describes.sandboxed('amp-bind', {}, function () {
261270
browser = new BrowserController(env.win);
262271
});
263272

264-
it('[src]', () => {
273+
it('[src]', async () => {
265274
expect(list.getAttribute('src')).to.equal('/list/fruit-data/get?cors=0');
266275
browser.click('button');
267-
poll(
276+
await poll(
268277
'[src]',
269278
() => list.getAttribute('src') === 'https://example.com/data'
270-
);
279+
).should.be.fulfilled;
271280
});
272281

273-
it('evaluate bindings in children', function* () {
274-
yield browser.waitForElementLayout('amp-list');
282+
it('evaluate bindings in children', async () => {
283+
await browser.waitForElementLayout('amp-list');
275284
const children = list.querySelectorAll('p');
276285
expect(children.length).to.equal(3);
277286
children.forEach((span) => {
@@ -315,35 +324,37 @@ describes.sandboxed('amp-bind', {}, function () {
315324
(env) => {
316325
let doc, images, selectedText;
317326

318-
beforeEach(() => {
327+
beforeEach(async () => {
319328
doc = env.win.document;
320329
images = doc.getElementsByTagName('amp-img');
321330
selectedText = doc.querySelector('p');
322331

323332
const browserController = new BrowserController(env.win);
324-
return browserController.waitForElementLayout('amp-selector');
333+
await browserController.waitForElementLayout('amp-selector');
325334
});
326335

327-
it('on:select', function* () {
336+
it('on:select', async () => {
328337
expect(images[0].hasAttribute('selected')).to.be.false;
329338
expect(images[1].hasAttribute('selected')).to.be.false;
330339
expect(images[2].hasAttribute('selected')).to.be.false;
331340
expect(selectedText.textContent).to.equal('');
332341
images[1].click();
333-
yield poll('[text]', () => selectedText.textContent === '1');
342+
await poll('[text]', () => selectedText.textContent === '1').should.be
343+
.fulfilled;
334344
expect(images[0].hasAttribute('selected')).to.be.false;
335345
expect(images[1].hasAttribute('selected')).to.be.true;
336346
expect(images[2].hasAttribute('selected')).to.be.false;
337347
});
338348

339-
it('[selected]', function* () {
349+
it('[selected]', async () => {
340350
const button = doc.querySelector('button');
341351
expect(images[0].hasAttribute('selected')).to.be.false;
342352
expect(images[1].hasAttribute('selected')).to.be.false;
343353
expect(images[2].hasAttribute('selected')).to.be.false;
344354
expect(selectedText.textContent).to.equal('');
345355
button.click();
346-
yield poll('[text]', () => selectedText.textContent === '2');
356+
await poll('[text]', () => selectedText.textContent === '2').should.be
357+
.fulfilled;
347358
expect(images[0].hasAttribute('selected')).to.be.false;
348359
expect(images[1].hasAttribute('selected')).to.be.false;
349360
expect(images[2].hasAttribute('selected')).to.be.true;

0 commit comments

Comments
 (0)