Skip to content

Commit 76adbb2

Browse files
committed
feat: expose firEvent with detectChanges
1 parent f7f5971 commit 76adbb2

13 files changed

+230
-76
lines changed

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
"build": "npm run build:library && npm run build:library:jest-utils && npm run build:migrations && npm run build:readme",
99
"build:library": "ng build --prod testing-library",
1010
"build:library:jest-utils": "ng build --prod jest-utils",
11-
"build:migrations": "tsc -p ./projects/testing-library/migrations/tsconfig.migrations.json && cp ./projects/testing-library/migrations/migration.json ./dist/@testing-library/angular/migrations",
12-
"build:readme": "cp ./README.md ./dist/@testing-library/angular",
11+
"build:migrations": "tsc -p ./projects/testing-library/migrations/tsconfig.migrations.json && cpy ./projects/testing-library/migrations/migration.json ./dist/@testing-library/angular/migrations",
12+
"build:readme": "cpy ./README.md ./dist/@testing-library/angular",
1313
"test": "jest --config ./projects/jest.lib.config.js",
1414
"test:app": "jest --config ./src/jest.app.config.js",
1515
"precommit": "lint-staged",
@@ -39,7 +39,7 @@
3939
"@testing-library/user-event": "^8.1.0",
4040
"core-js": "^3.1.3",
4141
"rxjs": "^6.5.4",
42-
"tslib": "^1.10.0",
42+
"tslib": "^1.11.1",
4343
"tslint": "^5.16.0",
4444
"zone.js": "~0.10.2"
4545
},
@@ -53,6 +53,7 @@
5353
"@types/jest": "~24.0.11",
5454
"@types/node": "^13.7.6",
5555
"codelyzer": "^5.1.2",
56+
"cpy-cli": "^3.1.0",
5657
"husky": "^2.3.0",
5758
"jest": "^24.1.0",
5859
"jest-preset-angular": "^7.1.1",

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

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,20 @@ import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform
55
import { Router } from '@angular/router';
66
import { RouterTestingModule } from '@angular/router/testing';
77
import {
8-
fireEvent,
98
FireFunction,
109
FireObject,
1110
getQueriesForElement,
1211
prettyDOM,
1312
waitFor,
1413
waitForElementToBeRemoved,
14+
fireEvent as dtlFireEvent,
1515
} from '@testing-library/dom';
1616
import { RenderComponentOptions, RenderDirectiveOptions, RenderResult } from './models';
1717
import { createSelectOptions, createType, tab } from './user-events';
18-
1918
@Component({ selector: 'wrapper-component', template: '' })
2019
class WrapperComponent {}
2120

22-
const mountedContainers = new Set();
21+
const mountedFixtures = new Set<ComponentFixture<any>>();
2322

2423
export async function render<ComponentType>(
2524
component: Type<ComponentType>,
@@ -75,9 +74,10 @@ export async function render<SutType, WrapperType = SutType>(
7574
if (idAttribute && idAttribute.startsWith('root')) {
7675
fixture.nativeElement.removeAttribute('id');
7776
}
78-
mountedContainers.add(fixture.nativeElement);
7977
}
8078

79+
mountedFixtures.add(fixture);
80+
8181
await TestBed.compileComponents();
8282

8383
let isAlive = true;
@@ -93,10 +93,10 @@ export async function render<SutType, WrapperType = SutType>(
9393
detectChanges();
9494
}
9595

96-
const eventsWithDetectChanges = Object.keys(fireEvent).reduce(
96+
const eventsWithDetectChanges = Object.keys(dtlFireEvent).reduce(
9797
(events, key) => {
9898
events[key] = (element: HTMLElement, options?: {}) => {
99-
const result = fireEvent[key](element, options);
99+
const result = dtlFireEvent[key](element, options);
100100
detectChanges();
101101
return result;
102102
};
@@ -238,18 +238,36 @@ function addAutoImports({ imports, routes }: Pick<RenderComponentOptions<any>, '
238238
}
239239

240240
function cleanup() {
241-
mountedContainers.forEach(cleanupAtContainer);
241+
mountedFixtures.forEach(cleanupAtFixture);
242242
}
243243

244-
function cleanupAtContainer(container) {
245-
if (container.parentNode === document.body) {
246-
document.body.removeChild(container);
244+
function cleanupAtFixture(fixture) {
245+
if (!fixture.nativeElement.getAttribute('ng-version') && fixture.nativeElement.parentNode === document.body) {
246+
document.body.removeChild(fixture.nativeElement);
247247
}
248-
mountedContainers.delete(container);
248+
mountedFixtures.delete(fixture);
249249
}
250250

251251
if (typeof afterEach === 'function' && !process.env.ATL_SKIP_AUTO_CLEANUP) {
252252
afterEach(async () => {
253253
cleanup();
254254
});
255255
}
256+
257+
export * from '@testing-library/dom';
258+
259+
const fireEvent = Object.keys(dtlFireEvent).reduce(
260+
(events, key) => {
261+
events[key] = (element: HTMLElement, options?: {}) => {
262+
const result = dtlFireEvent[key](element, options);
263+
mountedFixtures.forEach(fixture => {
264+
fixture.detectChanges();
265+
});
266+
return result;
267+
};
268+
return events;
269+
},
270+
{} as FireFunction & FireObject,
271+
);
272+
273+
export { fireEvent };

projects/testing-library/src/public_api.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,3 @@
55
export * from './lib/models';
66
export * from './lib/testing-library';
77
export * from './lib/user-events';
8-
export * from '@testing-library/dom';

projects/testing-library/tsconfig.lib.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
"compilerOptions": {
44
"outDir": "../../out-tsc/lib",
55
"target": "es2015",
6-
"module": "es2015",
6+
"module": "CommonJS",
77
"moduleResolution": "node",
88
"declaration": true,
99
"sourceMap": true,
1010
"inlineSources": true,
1111
"emitDecoratorMetadata": true,
1212
"experimentalDecorators": true,
13-
"importHelpers": true,
13+
"importHelpers": false,
1414
"types": ["@types/jest", "@types/node"],
1515
"lib": ["dom", "es2015", "es2018.promise"]
1616
},
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
import { render, screen } from '@testing-library/angular';
1+
import { render, screen, fireEvent } from '@testing-library/angular';
22

33
import { SingleComponent } from './00-single-component';
44

55
test('renders the current value and can increment and decrement', async () => {
6-
const { click } = await render(SingleComponent);
6+
await render(SingleComponent);
77

88
const incrementControl = screen.getByText('Increment');
99
const decrementControl = screen.getByText('Decrement');
1010
const valueControl = screen.getByTestId('value');
1111

1212
expect(valueControl.textContent).toBe('0');
1313

14-
click(incrementControl);
15-
click(incrementControl);
14+
fireEvent.click(incrementControl);
15+
fireEvent.click(incrementControl);
1616
expect(valueControl.textContent).toBe('2');
1717

18-
click(decrementControl);
18+
fireEvent.click(decrementControl);
1919
expect(valueControl.textContent).toBe('1');
2020
});
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { render, screen } from '@testing-library/angular';
1+
import { render, screen, fireEvent } from '@testing-library/angular';
22

33
import { NestedButtonComponent, NestedValueComponent, NestedContainerComponent } from './01-nested-component';
44

55
test('renders the current value and can increment and decrement', async () => {
6-
const { click } = await render(NestedContainerComponent, {
6+
await render(NestedContainerComponent, {
77
declarations: [NestedButtonComponent, NestedValueComponent],
88
});
99

@@ -13,10 +13,10 @@ test('renders the current value and can increment and decrement', async () => {
1313

1414
expect(valueControl.textContent).toBe('0');
1515

16-
click(incrementControl);
17-
click(incrementControl);
16+
fireEvent.click(incrementControl);
17+
fireEvent.click(incrementControl);
1818
expect(valueControl.textContent).toBe('2');
1919

20-
click(decrementControl);
20+
fireEvent.click(decrementControl);
2121
expect(valueControl.textContent).toBe('1');
2222
});

src/app/examples/02-input-output.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { render, screen } from '@testing-library/angular';
1+
import { render, screen, fireEvent } from '@testing-library/angular';
22

33
import { InputOutputComponent } from './02-input-output';
44

55
test('is possible to set input and listen for output', async () => {
66
const sendValue = jest.fn();
77

8-
const { click } = await render(InputOutputComponent, {
8+
await render(InputOutputComponent, {
99
componentProperties: {
1010
value: 47,
1111
sendValue: {
@@ -20,12 +20,12 @@ test('is possible to set input and listen for output', async () => {
2020

2121
expect(valueControl.textContent).toBe('47');
2222

23-
click(incrementControl);
24-
click(incrementControl);
25-
click(incrementControl);
23+
fireEvent.click(incrementControl);
24+
fireEvent.click(incrementControl);
25+
fireEvent.click(incrementControl);
2626
expect(valueControl.textContent).toBe('50');
2727

28-
click(sendControl);
28+
fireEvent.click(sendControl);
2929
expect(sendValue).toHaveBeenCalledTimes(1);
3030
expect(sendValue).toHaveBeenCalledWith(50);
3131
});

src/app/examples/03-forms.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { ReactiveFormsModule } from '@angular/forms';
2-
import { render, screen } from '@testing-library/angular';
2+
import { render, screen, fireEvent } from '@testing-library/angular';
33

44
import { FormsComponent } from './03-forms';
55

66
test('is possible to fill in a form and verify error messages (with the help of jest-dom https://testing-library.com/docs/ecosystem-jest-dom)', async () => {
7-
const { type, blur, selectOptions } = await render(FormsComponent, {
7+
const { type, selectOptions } = await render(FormsComponent, {
88
imports: [ReactiveFormsModule],
99
});
1010

@@ -20,7 +20,7 @@ test('is possible to fill in a form and verify error messages (with the help of
2020
expect(nameControl).toBeInvalid();
2121
type(nameControl, 'Tim');
2222
type(scoreControl, '12');
23-
blur(scoreControl);
23+
fireEvent.blur(scoreControl);
2424
selectOptions(colorControl, 'Green');
2525

2626
expect(screen.queryByText('name is required')).not.toBeInTheDocument();
@@ -29,7 +29,7 @@ test('is possible to fill in a form and verify error messages (with the help of
2929

3030
expect(scoreControl).toBeInvalid();
3131
type(scoreControl, 7);
32-
blur(scoreControl);
32+
fireEvent.blur(scoreControl);
3333
expect(scoreControl).toBeValid();
3434

3535
expect(errors).not.toBeInTheDocument();

src/app/examples/05-component-provider.spec.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { TestBed } from '@angular/core/testing';
2-
import { render, screen } from '@testing-library/angular';
2+
import { render, screen, fireEvent } from '@testing-library/angular';
33
import { provideMock, Mock, createMock } from '@testing-library/angular/jest-utils';
44

55
import { ComponentWithProviderComponent, CounterService } from './05-component-provider';
66

77
test('renders the current value and can increment and decrement', async () => {
8-
const { click } = await render(ComponentWithProviderComponent, {
8+
await render(ComponentWithProviderComponent, {
99
componentProviders: [
1010
{
1111
provide: CounterService,
@@ -20,11 +20,11 @@ test('renders the current value and can increment and decrement', async () => {
2020

2121
expect(valueControl.textContent).toBe('0');
2222

23-
click(incrementControl);
24-
click(incrementControl);
23+
fireEvent.click(incrementControl);
24+
fireEvent.click(incrementControl);
2525
expect(valueControl.textContent).toBe('2');
2626

27-
click(decrementControl);
27+
fireEvent.click(decrementControl);
2828
expect(valueControl.textContent).toBe('1');
2929
});
3030

@@ -35,7 +35,7 @@ test('renders the current value and can increment and decrement with a mocked je
3535
counter.decrement.mockImplementation(() => (fakeCounterValue -= 10));
3636
counter.value.mockImplementation(() => fakeCounterValue);
3737

38-
const { click } = await render(ComponentWithProviderComponent, {
38+
await render(ComponentWithProviderComponent, {
3939
componentProviders: [
4040
{
4141
provide: CounterService,
@@ -50,25 +50,25 @@ test('renders the current value and can increment and decrement with a mocked je
5050

5151
expect(valueControl.textContent).toBe('50');
5252

53-
click(incrementControl);
54-
click(incrementControl);
53+
fireEvent.click(incrementControl);
54+
fireEvent.click(incrementControl);
5555
expect(valueControl.textContent).toBe('70');
5656

57-
click(decrementControl);
57+
fireEvent.click(decrementControl);
5858
expect(valueControl.textContent).toBe('60');
5959
});
6060

6161
test('renders the current value and can increment and decrement with provideMocked from jest-utils', async () => {
62-
const { click } = await render(ComponentWithProviderComponent, {
62+
await render(ComponentWithProviderComponent, {
6363
componentProviders: [provideMock(CounterService)],
6464
});
6565

6666
const incrementControl = screen.getByText('Increment');
6767
const decrementControl = screen.getByText('Decrement');
6868

69-
click(incrementControl);
70-
click(incrementControl);
71-
click(decrementControl);
69+
fireEvent.click(incrementControl);
70+
fireEvent.click(incrementControl);
71+
fireEvent.click(decrementControl);
7272

7373
const counterService = TestBed.inject(CounterService) as Mock<CounterService>;
7474
expect(counterService.increment).toHaveBeenCalledTimes(2);

src/app/examples/06-with-ngrx-store.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { render, screen } from '@testing-library/angular';
1+
import { render, screen, fireEvent } from '@testing-library/angular';
22
import { StoreModule } from '@ngrx/store';
33

44
import { WithNgRxStoreComponent, reducer } from './06-with-ngrx-store';
55

66
test('works with ngrx store', async () => {
7-
const { click } = await render(WithNgRxStoreComponent, {
7+
await render(WithNgRxStoreComponent, {
88
imports: [
99
StoreModule.forRoot(
1010
{
@@ -23,10 +23,10 @@ test('works with ngrx store', async () => {
2323

2424
expect(valueControl.textContent).toBe('0');
2525

26-
click(incrementControl);
27-
click(incrementControl);
26+
fireEvent.click(incrementControl);
27+
fireEvent.click(incrementControl);
2828
expect(valueControl.textContent).toBe('20');
2929

30-
click(decrementControl);
30+
fireEvent.click(decrementControl);
3131
expect(valueControl.textContent).toBe('10');
3232
});

src/app/examples/07-with-ngrx-mock-store.spec.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import { TestBed } from '@angular/core/testing';
2-
import { Store } from '@ngrx/store';
32
import { provideMockStore, MockStore } from '@ngrx/store/testing';
4-
import { render, screen } from '@testing-library/angular';
3+
import { render, screen, fireEvent } from '@testing-library/angular';
54

65
import { WithNgRxMockStoreComponent, selectItems } from './07-with-ngrx-mock-store';
76

87
test('works with provideMockStore', async () => {
9-
const { click } = await render(WithNgRxMockStoreComponent, {
8+
await render(WithNgRxMockStoreComponent, {
109
providers: [
1110
provideMockStore({
1211
selectors: [
@@ -23,7 +22,7 @@ test('works with provideMockStore', async () => {
2322
store.dispatch = jest.fn();
2423

2524
screen.getByText('Four');
26-
click(screen.getByText('Seven'));
25+
fireEvent.click(screen.getByText('Seven'));
2726

2827
expect(store.dispatch).toBeCalledWith({ type: '[Item List] send', item: 'Seven' });
2928
});

0 commit comments

Comments
 (0)