Skip to content

Commit 758cbb1

Browse files
committed
fix: configure fireEvent to run a change detection cycle
Deprecate custom userEvent methods in favor of @testing-library/user-event
1 parent 95f7de0 commit 758cbb1

File tree

9 files changed

+1231
-943
lines changed

9 files changed

+1231
-943
lines changed

jest.base.config.js

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,10 @@ module.exports = {
22
preset: 'jest-preset-angular',
33
rootDir: '../',
44
setupFilesAfterEnv: ['<rootDir>/test.ts'],
5-
testURL: 'http://localhost',
6-
globals: {
7-
'ts-jest': {
8-
tsConfig: './tsconfig.spec.json',
9-
stringifyContentPathRegex: '\\.html$',
10-
astTransformers: [require.resolve('jest-preset-angular/InlineHtmlStripStylesTransformer')],
11-
},
12-
},
13-
transform: {
14-
'^.+\\.(ts|js|html)$': 'ts-jest',
15-
},
165
transformIgnorePatterns: ['node_modules/(?!@ngrx)'],
176
snapshotSerializers: [
18-
'jest-preset-angular/AngularSnapshotSerializer.js',
19-
'jest-preset-angular/HTMLCommentSerializer.js',
7+
'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js',
8+
'jest-preset-angular/build/AngularSnapshotSerializer.js',
9+
'jest-preset-angular/build/HTMLCommentSerializer.js',
2010
],
2111
};

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
"@angular/router": "^9.0.3",
3636
"@ngrx/store": "^9.0.0-rc.0",
3737
"@phenomnomnominal/tsquery": "^3.0.0",
38-
"@testing-library/dom": "^7.7.3",
39-
"@testing-library/user-event": "^8.1.0",
38+
"@testing-library/dom": "^7.9.0",
39+
"@testing-library/user-event": "^11.0.0",
4040
"core-js": "^3.1.3",
4141
"rxjs": "^6.5.4",
4242
"tslib": "^1.11.1",
@@ -50,13 +50,13 @@
5050
"@angular/compiler-cli": "^9.0.3",
5151
"@angular/language-service": "^9.0.3",
5252
"@testing-library/jest-dom": "^4.1.0",
53-
"@types/jest": "~24.0.11",
53+
"@types/jest": "~25.2.3",
5454
"@types/node": "^13.7.6",
5555
"codelyzer": "^5.1.2",
5656
"cpy-cli": "^3.1.0",
5757
"husky": "^2.3.0",
58-
"jest": "^24.1.0",
59-
"jest-preset-angular": "^7.1.1",
58+
"jest": "^26.0.1",
59+
"jest-preset-angular": "^8.2.0",
6060
"lint-staged": "^8.1.7",
6161
"ng-packagr": "^9.0.0",
6262
"prettier": "^1.17.1",

projects/testing-library/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"@angular/core": "^9.0.0"
3030
},
3131
"dependencies": {
32-
"@testing-library/dom": "^7.7.3",
32+
"@testing-library/dom": "^7.9.0",
3333
"@testing-library/user-event": "^8.1.0",
3434
"@phenomnomnominal/tsquery": "^3.0.0",
3535
"tslint": "^5.16.0"

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

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,29 @@ import { RouterTestingModule } from '@angular/router/testing';
77
import {
88
FireFunction,
99
FireObject,
10-
getQueriesForElement,
11-
prettyDOM,
10+
getQueriesForElement as dtlGetQueriesForElement,
11+
prettyDOM as dtlPrettyDOM,
1212
waitFor as dtlWaitFor,
1313
waitForElementToBeRemoved as dtlWaitForElementToBeRemoved,
1414
fireEvent as dtlFireEvent,
1515
screen as dtlScreen,
1616
queries as dtlQueries,
17-
waitForOptions,
17+
waitForOptions as dtlWaitForOptions,
18+
configure as dtlConfigure,
1819
} from '@testing-library/dom';
1920
import { RenderComponentOptions, RenderDirectiveOptions, RenderResult } from './models';
2021
import { createSelectOptions, createType, tab } from './user-events';
2122

22-
@Component({ selector: 'wrapper-component', template: '' })
23-
class WrapperComponent {}
24-
2523
const mountedFixtures = new Set<ComponentFixture<any>>();
2624

25+
dtlConfigure({
26+
eventWrapper: cb => {
27+
const result = cb();
28+
detectChangesForMountedFixtures();
29+
return result;
30+
},
31+
});
32+
2733
export async function render<ComponentType>(
2834
component: Type<ComponentType>,
2935
renderOptions?: RenderComponentOptions<ComponentType>,
@@ -148,13 +154,16 @@ export async function render<SutType, WrapperType = SutType>(
148154
return result;
149155
};
150156

151-
function componentWaitFor<T>(callback, options: waitForOptions = { container: fixture.nativeElement }): Promise<T> {
157+
function componentWaitFor<T>(
158+
callback,
159+
options: dtlWaitForOptions = { container: fixture.nativeElement },
160+
): Promise<T> {
152161
return waitForWrapper(detectChanges, callback, options);
153162
}
154163

155164
function componentWaitForElementToBeRemoved<T>(
156165
callback: (() => T) | T,
157-
options: waitForOptions = { container: fixture.nativeElement },
166+
options: dtlWaitForOptions = { container: fixture.nativeElement },
158167
): Promise<T> {
159168
return waitForElementToBeRemovedWrapper(detectChanges, callback, options);
160169
}
@@ -168,14 +177,17 @@ export async function render<SutType, WrapperType = SutType>(
168177
container: fixture.nativeElement,
169178
debug: (element = fixture.nativeElement, maxLength, options) =>
170179
Array.isArray(element)
171-
? element.forEach(e => console.log(prettyDOM(e, maxLength, options)))
172-
: console.log(prettyDOM(element, maxLength, options)),
180+
? element.forEach(e => console.log(dtlPrettyDOM(e, maxLength, options)))
181+
: console.log(dtlPrettyDOM(element, maxLength, options)),
173182
type: createType(eventsWithDetectChanges),
174183
selectOptions: createSelectOptions(eventsWithDetectChanges),
175184
tab,
176185
waitFor: componentWaitFor,
177186
waitForElementToBeRemoved: componentWaitForElementToBeRemoved,
178-
...replaceFindWithFindAndDetectChanges(fixture.nativeElement, getQueriesForElement(fixture.nativeElement, queries)),
187+
...replaceFindWithFindAndDetectChanges(
188+
fixture.nativeElement,
189+
dtlGetQueriesForElement(fixture.nativeElement, queries),
190+
),
179191
...eventsWithDetectChanges,
180192
};
181193
}
@@ -244,7 +256,7 @@ function addAutoImports({ imports, routes }: Pick<RenderComponentOptions<any>, '
244256
async function waitForWrapper<T>(
245257
detectChanges: () => void,
246258
callback: () => T extends Promise<any> ? never : T,
247-
options?: waitForOptions,
259+
options?: dtlWaitForOptions,
248260
): Promise<T> {
249261
return await dtlWaitFor(() => {
250262
detectChanges();
@@ -258,7 +270,7 @@ async function waitForWrapper<T>(
258270
async function waitForElementToBeRemovedWrapper<T>(
259271
detectChanges: () => void,
260272
callback: (() => T) | T,
261-
options?: waitForOptions,
273+
options?: dtlWaitForOptions,
262274
): Promise<T> {
263275
let cb;
264276
if (typeof callback !== 'function') {
@@ -298,6 +310,9 @@ if (typeof afterEach === 'function' && !process.env.ATL_SKIP_AUTO_CLEANUP) {
298310
});
299311
}
300312

313+
@Component({ selector: 'wrapper-component', template: '' })
314+
class WrapperComponent {}
315+
301316
/**
302317
* Wrap findBy queries to poke the Angular change detection cycle
303318
*/
@@ -355,14 +370,14 @@ const screen = replaceFindWithFindAndDetectChanges(document.body, dtlScreen);
355370
/**
356371
* Re-export waitFor with patched waitFor
357372
*/
358-
async function waitFor<T>(callback: () => T extends Promise<any> ? never : T, options?: waitForOptions): Promise<T> {
373+
async function waitFor<T>(callback: () => T extends Promise<any> ? never : T, options?: dtlWaitForOptions): Promise<T> {
359374
return waitForWrapper(detectChangesForMountedFixtures, callback, options);
360375
}
361376

362377
/**
363378
* Re-export waitForElementToBeRemoved with patched waitForElementToBeRemoved
364379
*/
365-
async function waitForElementToBeRemoved<T>(callback: (() => T) | T, options?: waitForOptions): Promise<T> {
380+
async function waitForElementToBeRemoved<T>(callback: (() => T) | T, options?: dtlWaitForOptions): Promise<T> {
366381
return waitForElementToBeRemovedWrapper(detectChangesForMountedFixtures, callback, options);
367382
}
368383

projects/testing-library/src/lib/user-events/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import { tab } from './tab';
44

55
export interface UserEvents {
66
/**
7+
* @deprecated
8+
* Use `userEvents.type` from @testing-library/user-event
9+
*
710
* @description
811
* Types a value in an input field with the same interactions as the user would do.
912
*
@@ -19,6 +22,9 @@ export interface UserEvents {
1922
type: ReturnType<typeof createType>;
2023

2124
/**
25+
* @deprecated
26+
* Use `userEvents.selectOptions` from @testing-library/user-event
27+
*
2228
* @description
2329
* Select an option(s) from a select field with the same interactions as the user would do.
2430
*
@@ -33,6 +39,9 @@ export interface UserEvents {
3339
selectOptions: ReturnType<typeof createSelectOptions>;
3440

3541
/**
42+
* @deprecated
43+
* Use `userEvents.tab` from @testing-library/user-event
44+
*
3645
* @description
3746
* Fires a tab event changing the document.activeElement in the same way the browser does.
3847
*

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ReactiveFormsModule } from '@angular/forms';
2-
import { render, screen, fireEvent, userEvent } from '@testing-library/angular';
2+
import { render, screen, fireEvent } from '@testing-library/angular';
3+
import userEvent from '@testing-library/user-event';
34

45
import { FormsComponent } from './03-forms';
56

@@ -19,16 +20,18 @@ test('is possible to fill in a form and verify error messages (with the help of
1920

2021
expect(nameControl).toBeInvalid();
2122
userEvent.type(nameControl, 'Tim');
23+
userEvent.clear(scoreControl);
2224
userEvent.type(scoreControl, '12');
2325
fireEvent.blur(scoreControl);
24-
userEvent.selectOptions(colorControl, 'Green');
26+
userEvent.selectOptions(colorControl, 'G');
2527

2628
expect(screen.queryByText('name is required')).not.toBeInTheDocument();
2729
expect(screen.queryByText('score must be lesser than 10')).toBeInTheDocument();
2830
expect(screen.queryByText('color is required')).not.toBeInTheDocument();
2931

3032
expect(scoreControl).toBeInvalid();
31-
userEvent.type(scoreControl, 7);
33+
userEvent.clear(scoreControl);
34+
userEvent.type(scoreControl, '7');
3235
fireEvent.blur(scoreControl);
3336
expect(scoreControl).toBeValid();
3437

src/app/examples/04-forms-with-material.spec.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ReactiveFormsModule } from '@angular/forms';
2-
import { render, screen, userEvent } from '@testing-library/angular';
2+
import { render, screen } from '@testing-library/angular';
3+
import userEvent from '@testing-library/user-event';
34

45
import { MaterialModule } from '../material.module';
56
import { MaterialFormsComponent } from './04-forms-with-material';
@@ -19,15 +20,18 @@ test('is possible to fill in a form and verify error messages (with the help of
1920
expect(errors).toContainElement(screen.queryByText('color is required'));
2021

2122
userEvent.type(nameControl, 'Tim');
22-
userEvent.type(scoreControl, 12);
23-
userEvent.selectOptions(colorControl, 'Green');
23+
userEvent.clear(scoreControl);
24+
userEvent.type(scoreControl, '12');
25+
userEvent.click(colorControl);
26+
userEvent.click(screen.getByText(/green/i));
2427

2528
expect(screen.queryByText('name is required')).not.toBeInTheDocument();
2629
expect(screen.queryByText('score must be lesser than 10')).toBeInTheDocument();
2730
expect(screen.queryByText('color is required')).not.toBeInTheDocument();
2831

2932
expect(scoreControl).toBeInvalid();
30-
userEvent.type(scoreControl, 7);
33+
userEvent.clear(scoreControl);
34+
userEvent.type(scoreControl, '7');
3135
expect(scoreControl).toBeValid();
3236

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

tslint.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"no-trailing-whitespace": true,
4343
"no-unnecessary-initializer": true,
4444
"no-unused-expression": true,
45-
"no-use-before-declare": true,
45+
"no-use-before-declare": false,
4646
"no-var-keyword": true,
4747
"object-literal-sort-keys": false,
4848
"one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"],

0 commit comments

Comments
 (0)