Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4b269bc

Browse files
fix: infinite loop in waitFor when DOM is mutating (testing-library#231)
1 parent 7a64a6b commit 4b269bc

File tree

6 files changed

+44
-8
lines changed

6 files changed

+44
-8
lines changed

‎apps/example-app/src/app/examples/13-scrolling.component.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ test('should scroll to load more items', async () => {
1212
expect(item0).toBeVisible();
1313

1414
screen.getByTestId('scroll-viewport').scrollTop = 500;
15-
await waitForElementToBeRemoved(() => screen.getByText(/Item#0/i));
15+
await waitForElementToBeRemoved(() => screen.queryByText(/Item#0/i));
1616

1717
const item12 = await screen.findByText(/Item#12/i);
1818
expect(item12).toBeVisible();

‎projects/testing-library/src/lib/testing-library.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,16 +303,21 @@ function addAutoImports({ imports, routes }: Pick<RenderComponentOptions<any>, '
303303
}
304304

305305
/**
306-
* Wrap waitFor to poke the Angular change detection cycle before invoking the callback
306+
* Wrap waitFor to invoke the Angular change detection cycle before invoking the callback
307307
*/
308308
async function waitForWrapper<T>(
309309
detectChanges: () => void,
310310
callback: () => T extends Promise<any> ? never : T,
311311
options?: dtlWaitForOptions,
312312
): Promise<T> {
313+
detectChanges();
313314
return await dtlWaitFor(() => {
314-
detectChanges();
315-
return callback();
315+
try {
316+
return callback();
317+
} catch (error) {
318+
setImmediate(() => detectChanges());
319+
throw error;
320+
}
316321
}, options);
317322
}
318323

@@ -340,8 +345,10 @@ async function waitForElementToBeRemovedWrapper<T>(
340345
}
341346

342347
return await dtlWaitForElementToBeRemoved(() => {
348+
const result = cb();
343349
detectChanges();
344-
return cb();
350+
setImmediate(() => detectChanges());
351+
return result;
345352
}, options);
346353
}
347354

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Component } from '@angular/core';
2+
import { render, waitFor, screen } from '@testing-library/angular';
3+
4+
@Component({
5+
template: ` <button [ngClass]="classes">Load</button> `,
6+
})
7+
class LoopComponent {
8+
get classes() {
9+
return {
10+
someClass: true,
11+
};
12+
}
13+
}
14+
15+
test('wait does not end up in a loop', async () => {
16+
await render(LoopComponent);
17+
18+
await expect(
19+
waitFor(() => {
20+
expect(true).toEqual(false);
21+
}),
22+
).rejects.toThrow();
23+
});
24+
25+
test('find does not end up in a loop', async () => {
26+
await render(LoopComponent);
27+
28+
await expect(screen.findByText('foo')).rejects.toThrow();
29+
});

‎projects/testing-library/tests/wait-for.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Component } from '@angular/core';
22
import { timer } from 'rxjs';
3-
import { render, screen, fireEvent, waitFor aswaitForATL} from '../src/public_api';
3+
import { render, screen, fireEvent, waitFor } from '../src/public_api';
44

55
@Component({
66
selector: 'atl-fixture',
@@ -24,7 +24,7 @@ test('waits for assertion to become true', async () => {
2424

2525
fireEvent.click(screen.getByTestId('button'));
2626

27-
await waitForATL(() => screen.getByText('Success'));
27+
await waitFor(() => screen.getByText('Success'));
2828
screen.getByText('Success');
2929
});
3030

@@ -33,7 +33,7 @@ test('allows to override options', async () => {
3333

3434
fireEvent.click(screen.getByTestId('button'));
3535

36-
await expect(waitForATL(() => screen.getByText('Success'), { timeout: 200 })).rejects.toThrow(
36+
await expect(waitFor(() => screen.getByText('Success'), { timeout: 200 })).rejects.toThrow(
3737
/Unabletofindanelementwiththetext:Success/i,
3838
);
3939
});

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /