Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a67955e

Browse files
authoredMar 24, 2020
Release Beta
2 parents 41d674f + e10d04f commit a67955e

40 files changed

+4720
-1932
lines changed
 

‎.circleci/config.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
key: *cache_key
4242
- run:
4343
name: test
44-
command: yarn test
44+
command: yarn test --maxWorkers=1 --ci
4545

4646
build-lib:
4747
<<: *job_defaults
@@ -67,7 +67,7 @@ jobs:
6767
key: *dist_key
6868
- run:
6969
name: test
70-
command: yarn test:app
70+
command: yarn test:app --maxWorkers=1 --ci
7171

7272
release:
7373
<<: *job_defaults
@@ -81,7 +81,7 @@ jobs:
8181
name: release
8282
command: yarn semantic-release || true
8383

84-
release-next:
84+
release-beta:
8585
<<: *job_defaults
8686
steps:
8787
- checkout
@@ -91,7 +91,7 @@ jobs:
9191
key: *dist_key
9292
- run:
9393
name: release
94-
command: yarn semantic-release --branch next || true
94+
command: yarn semantic-release || true
9595

9696
workflows:
9797
version: 2
@@ -118,10 +118,10 @@ workflows:
118118
branches:
119119
only:
120120
- master
121-
- release-next:
121+
- release-beta:
122122
requires:
123123
- test-app
124124
filters:
125125
branches:
126126
only:
127-
- next
127+
- beta

‎README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,20 +117,20 @@ export class CounterComponent {
117117
counter.component.spec.ts
118118

119119
```typescript
120-
import { render } from '@testing-library/angular';
120+
import { render, screen } from '@testing-library/angular';
121121
import CounterComponent from './counter.component.ts';
122122

123123
describe('Counter', () => {
124124
test('should render counter', async () => {
125-
const { getByText } = await render(CounterComponent, { componentProperties: { counter: 5 } });
125+
await render(CounterComponent, { componentProperties: { counter: 5 } });
126126

127-
expect(getByText('Current Count: 5'));
127+
expect(screen.getByText('Current Count: 5'));
128128
});
129129

130130
test('should increment the counter on click', async () => {
131-
const { getByText, click } = await render(CounterComponent, { componentProperties: { counter: 5 } });
131+
const { click } = await render(CounterComponent, { componentProperties: { counter: 5 } });
132132

133-
click(getByText('+'));
133+
click(screen.getByText('+'));
134134

135135
expect(getByText('Current Count: 6'));
136136
});
@@ -194,6 +194,7 @@ Thanks goes to these people ([emoji key][emojis]):
194194

195195
<!-- markdownlint-enable -->
196196
<!-- prettier-ignore-end -->
197+
197198
<!-- ALL-CONTRIBUTORS-LIST:END -->
198199

199200
This project follows the [all-contributors][all-contributors] specification.

‎angular.json

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"build": {
1414
"builder": "@angular-devkit/build-angular:browser",
1515
"options": {
16+
"aot": true,
1617
"outputPath": "dist/testing-library-app",
1718
"index": "src/index.html",
1819
"main": "src/main.ts",
@@ -24,6 +25,12 @@
2425
},
2526
"configurations": {
2627
"production": {
28+
"budgets": [
29+
{
30+
"type": "anyComponentStyle",
31+
"maximumWarning": "6kb"
32+
}
33+
],
2734
"fileReplacements": [
2835
{
2936
"replace": "src/environments/environment.ts",
@@ -82,7 +89,8 @@
8289
},
8390
"configurations": {
8491
"production": {
85-
"project": "projects/testing-library/ng-package.prod.json"
92+
"project": "projects/testing-library/ng-package.prod.json",
93+
"tsConfig": "projects/testing-library/tsconfig.lib.prod.json"
8694
}
8795
}
8896
},
@@ -109,7 +117,8 @@
109117
},
110118
"configurations": {
111119
"production": {
112-
"project": "projects/jest-utils/ng-package.prod.json"
120+
"project": "projects/jest-utils/ng-package.prod.json",
121+
"tsConfig": "projects/jest-utils/tsconfig.lib.prod.json"
113122
}
114123
}
115124
},

‎package.json

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,49 +22,46 @@
2222
"git add"
2323
]
2424
},
25-
"release": {
26-
"pkgRoot": "dist/@testing-library/angular"
27-
},
2825
"dependencies": {
29-
"@angular/animations": "^8.0.0",
30-
"@angular/cdk": "^8.1.4",
31-
"@angular/common": "^8.0.0",
32-
"@angular/compiler": "^8.0.0",
33-
"@angular/core": "^8.0.0",
34-
"@angular/forms": "^8.0.0",
35-
"@angular/material": "^8.1.4",
36-
"@angular/platform-browser": "^8.0.0",
37-
"@angular/platform-browser-dynamic": "^8.0.0",
38-
"@angular/router": "^8.0.0",
39-
"@ngrx/store": "^8.0.0-rc.0",
26+
"@angular/animations": "^9.0.3",
27+
"@angular/cdk": "^9.1.0",
28+
"@angular/common": "^9.0.3",
29+
"@angular/compiler": "^9.0.3",
30+
"@angular/core": "^9.0.3",
31+
"@angular/forms": "^9.0.3",
32+
"@angular/material": "^9.1.0",
33+
"@angular/platform-browser": "^9.0.3",
34+
"@angular/platform-browser-dynamic": "^9.0.3",
35+
"@angular/router": "^9.0.3",
36+
"@ngrx/store": "^9.0.0-rc.0",
4037
"@phenomnomnominal/tsquery": "^3.0.0",
41-
"@testing-library/dom": "^5.0.1",
38+
"@testing-library/dom": "^7.1.1",
39+
"@testing-library/user-event": "^8.1.0",
4240
"core-js": "^3.1.3",
43-
"rxjs": "^6.5.2",
41+
"rxjs": "^6.5.4",
42+
"tslib": "^1.10.0",
4443
"tslint": "^5.16.0",
45-
"zone.js": "~0.9.1"
44+
"zone.js": "~0.10.2"
4645
},
4746
"devDependencies": {
48-
"@angular-devkit/build-angular": "~0.800.0",
49-
"@angular-devkit/build-ng-packagr": "~0.800.0",
50-
"@angular/cli": "~8.0.0",
51-
"@angular/compiler-cli": "^8.0.0",
52-
"@angular/language-service": "^8.0.0",
47+
"@angular-devkit/build-angular": "~0.900.3",
48+
"@angular-devkit/build-ng-packagr": "~0.900.3",
49+
"@angular/cli": "~9.0.3",
50+
"@angular/compiler-cli": "^9.0.3",
51+
"@angular/language-service": "^9.0.3",
5352
"@testing-library/jest-dom": "^4.1.0",
5453
"@types/jest": "~24.0.11",
55-
"@types/node": "~12.0.3",
56-
"codelyzer": "^5.0.1",
54+
"@types/node": "^13.7.6",
55+
"codelyzer": "^5.1.2",
5756
"husky": "^2.3.0",
5857
"jest": "^24.1.0",
5958
"jest-preset-angular": "^7.1.1",
6059
"lint-staged": "^8.1.7",
61-
"ng-packagr": "^5.2.0",
60+
"ng-packagr": "^9.0.0",
6261
"prettier": "^1.17.1",
6362
"rimraf": "^2.6.3",
64-
"semantic-release": "^15.13.12",
63+
"semantic-release": "^17.0.2",
6564
"ts-node": "~8.2.0",
66-
"tsickle": "0.35.0",
67-
"tslib": "^1.9.0",
68-
"typescript": "~3.4.5"
65+
"typescript": "~3.7.5"
6966
}
7067
}

‎projects/jest-utils/src/lib/configure-test-suite.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

‎projects/jest-utils/src/lib/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
export * from './configure-test-suite';
21
export * from './create-mock';

‎projects/jest-utils/tests/create-mock.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ it('provides a mock service', async () => {
3535
const { click, getByText } = await render(FixtureComponent, {
3636
providers: [provideMock(FixtureService)],
3737
});
38-
const service = TestBed.get<FixtureService>(FixtureService);
38+
const service = TestBed.inject(FixtureService);
3939

4040
click(getByText('Print'));
4141
expect(service.print).toHaveBeenCalledTimes(1);
@@ -46,7 +46,7 @@ it('is possible to write a mock implementation', async done => {
4646
providers: [provideMock(FixtureService)],
4747
});
4848

49-
const service = TestBed.get<FixtureService>(FixtureService) as Mock<FixtureService>;
49+
const service = TestBed.inject(FixtureService) as Mock<FixtureService>;
5050
service.print.mockImplementation(() => done());
5151

5252
click(getByText('Print'));

‎projects/jest-utils/tsconfig.lib.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@
1212
"experimentalDecorators": true,
1313
"importHelpers": true,
1414
"allowSyntheticDefaultImports": true,
15-
"types": [],
15+
"types": ["@types/jest"],
1616
"lib": ["dom", "es2015"]
1717
},
1818
"angularCompilerOptions": {
19-
"annotateForClosureCompiler": true,
2019
"skipTemplateCodegen": true,
2120
"strictMetadataEmit": true,
2221
"fullTemplateTypeCheck": true,
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "./tsconfig.lib.json",
3+
"angularCompilerOptions": {
4+
"enableIvy": false
5+
}
6+
}

‎projects/testing-library/ng-package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,10 @@
55
"lib": {
66
"entryFile": "src/public_api.ts"
77
},
8-
"whitelistedNonPeerDependencies": ["@testing-library/dom", "@phenomnomnominal/tsquery", "tslint"]
8+
"whitelistedNonPeerDependencies": [
9+
"@testing-library/dom",
10+
"@testing-library/user-event",
11+
"@phenomnomnominal/tsquery",
12+
"tslint"
13+
]
914
}

‎projects/testing-library/ng-package.prod.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,10 @@
55
"lib": {
66
"entryFile": "src/public_api.ts"
77
},
8-
"whitelistedNonPeerDependencies": ["@testing-library/dom", "@phenomnomnominal/tsquery", "tslint"]
8+
"whitelistedNonPeerDependencies": [
9+
"@testing-library/dom",
10+
"@testing-library/user-event",
11+
"@phenomnomnominal/tsquery",
12+
"tslint"
13+
]
914
}

‎projects/testing-library/package.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@
2222
},
2323
"homepage": "https://github.com/testing-library/angular-testing-library#readme",
2424
"peerDependencies": {
25-
"@angular/common": "^8.0.0",
26-
"@angular/platform-browser": "^8.0.0",
27-
"@angular/animations": "^8.0.0",
28-
"@angular/router": "^8.0.0",
29-
"@angular/core": "^8.0.0"
25+
"@angular/common": "^9.0.0",
26+
"@angular/platform-browser": "^9.0.0",
27+
"@angular/animations": "^9.0.0",
28+
"@angular/router": "^9.0.0",
29+
"@angular/core": "^9.0.0"
3030
},
3131
"dependencies": {
32-
"@testing-library/dom": "^5.1.0",
32+
"@testing-library/dom": "^7.1.0",
33+
"@testing-library/user-event": "^8.1.0",
3334
"@phenomnomnominal/tsquery": "^3.0.0",
3435
"tslint": "^5.16.0"
3536
},

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

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
11
import { Type, DebugElement } from '@angular/core';
22
import { ComponentFixture } from '@angular/core/testing';
33
import { Routes } from '@angular/router';
4-
import {
5-
BoundFunction,
6-
FireObject,
7-
Queries,
8-
queries,
9-
waitForElement,
10-
waitForElementToBeRemoved,
11-
waitForDomChange,
12-
} from '@testing-library/dom';
4+
import { BoundFunction, FireObject, Queries, queries, waitFor, waitForElementToBeRemoved } from '@testing-library/dom';
135
import { UserEvents } from './user-events';
146

157
export type RenderResultQueries<Q extends Queries = typeof queries> = { [P in keyof Q]: BoundFunction<Q[P]> };
@@ -68,25 +60,18 @@ export interface RenderResult<ComponentType, WrapperType = ComponentType>
6860
rerender: (componentProperties: Partial<ComponentType>) => void;
6961
/**
7062
* @description
71-
* Wait for the DOM to change.
72-
*
73-
* For more info see https://testing-library.com/docs/dom-testing-library/api-async#waitfordomchange
74-
*/
75-
waitForDomChange: typeof waitForDomChange;
76-
/**
77-
* @description
78-
* Wait for DOM elements to appear, disappear, or change.
63+
* Wait for the removal of element(s) from the DOM.
7964
*
80-
* For more info see https://testing-library.com/docs/dom-testing-library/api-async#waitforelement
65+
* For more info see https://testing-library.com/docs/dom-testing-library/api-async#waitforelementtoberemoved
8166
*/
82-
waitForElement: typeof waitForElement;
67+
waitForElementToBeRemoved: typeof waitForElementToBeRemoved;
8368
/**
8469
* @description
85-
* Wait for the removal of element(s) from the DOM.
70+
* When in need to wait for any period of time you can use waitFor, to wait for your expectations to pass.
8671
*
87-
* For more info see https://testing-library.com/docs/dom-testing-library/api-async#waitforelementtoberemoved
72+
* For more info see https://testing-library.com/docs/dom-testing-library/api-async#waitFor
8873
*/
89-
waitForElementToBeRemoved: typeof waitForElementToBeRemoved;
74+
waitFor: typeof waitFor;
9075
}
9176

9277
export interface RenderComponentOptions<ComponentType, Q extends Queries = typeof queries> {
@@ -263,6 +248,20 @@ export interface RenderComponentOptions<ComponentType, Q extends Queries = typeo
263248
* })
264249
*/
265250
routes?: Routes;
251+
252+
/**
253+
* @description
254+
* Removes the Angular attributes (ng-version, and root-id) from the fixture.
255+
*
256+
* @default
257+
* `false`
258+
*
259+
* @example
260+
* const component = await render(AppComponent, {
261+
* removeAngularAttributes: true
262+
* })
263+
*/
264+
removeAngularAttributes?: boolean;
266265
}
267266

268267
export interface RenderDirectiveOptions<DirectiveType, WrapperType, Q extends Queries = typeof queries>

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

Lines changed: 65 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, ElementRef, OnInit, Type, NgZone } from '@angular/core';
1+
import { Component, Type, NgZone } from '@angular/core';
22
import { ComponentFixture, TestBed } from '@angular/core/testing';
33
import { By } from '@angular/platform-browser';
44
import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations';
@@ -10,21 +10,16 @@ import {
1010
FireObject,
1111
getQueriesForElement,
1212
prettyDOM,
13-
waitForDomChange,
14-
waitForElement,
13+
waitFor,
1514
waitForElementToBeRemoved,
1615
} from '@testing-library/dom';
1716
import { RenderComponentOptions, RenderDirectiveOptions, RenderResult } from './models';
18-
import { createSelectOptions, createType } from './user-events';
17+
import { createSelectOptions, createType, tab } from './user-events';
1918

2019
@Component({ selector: 'wrapper-component', template: '' })
21-
class WrapperComponent implements OnInit {
22-
constructor(private elementRef: ElementRef) {}
20+
class WrapperComponent {}
2321

24-
ngOnInit() {
25-
this.elementRef.nativeElement.removeAttribute('ng-version');
26-
}
27-
}
22+
const mountedContainers = new Set();
2823

2924
export async function render<ComponentType>(
3025
component: Type<ComponentType>,
@@ -52,6 +47,7 @@ export async function render<SutType, WrapperType = SutType>(
5247
componentProviders = [],
5348
excludeComponentDeclaration = false,
5449
routes,
50+
removeAngularAttributes = false,
5551
} = renderOptions as RenderDirectiveOptions<SutType, WrapperType>;
5652

5753
TestBed.configureTestingModule({
@@ -73,6 +69,15 @@ export async function render<SutType, WrapperType = SutType>(
7369
const fixture = createComponentFixture(sut, { template, wrapper });
7470
setComponentProperties(fixture, { componentProperties });
7571

72+
if (removeAngularAttributes) {
73+
fixture.nativeElement.removeAttribute('ng-version');
74+
const idAttribute = fixture.nativeElement.getAttribute('id');
75+
if (idAttribute && idAttribute.startsWith('root')) {
76+
fixture.nativeElement.removeAttribute('id');
77+
}
78+
mountedContainers.add(fixture.nativeElement);
79+
}
80+
7681
await TestBed.compileComponents();
7782

7883
let isAlive = true;
@@ -105,11 +110,11 @@ export async function render<SutType, WrapperType = SutType>(
105110
detectChanges();
106111
};
107112

108-
let router = routes ? (TestBed.get<Router>(Router) as Router) : null;
109-
const zone = TestBed.get<NgZone>(NgZone) as NgZone;
113+
let router = routes ? TestBed.inject(Router) : null;
114+
const zone = TestBed.inject(NgZone);
110115
const navigate = async (elementOrPath: Element | string, basePath = '') => {
111116
if (!router) {
112-
router = TestBed.get<Router>(Router) as Router;
117+
router = TestBed.inject(Router);
113118
}
114119

115120
const href = typeof elementOrPath === 'string' ? elementOrPath : elementOrPath.getAttribute('href');
@@ -120,43 +125,40 @@ export async function render<SutType, WrapperType = SutType>(
120125
return result;
121126
};
122127

123-
function componentWaitForDomChange<Result>(options?: {
124-
container?: HTMLElement;
125-
timeout?: number;
126-
mutationObserverOptions?: MutationObserverInit;
127-
}): Promise<Result> {
128-
const interval = setInterval(detectChanges, 10);
129-
return waitForDomChange<Result>({ container: fixture.nativeElement, ...options }).finally(() =>
130-
clearInterval(interval),
131-
);
132-
}
133-
134-
function componentWaitForElement<Result>(
135-
callback: () => Result,
136-
options?: {
128+
function componentWaitFor<T>(
129+
callback,
130+
options: {
137131
container?: HTMLElement;
138132
timeout?: number;
139-
mutationObserverOptions?: MutationObserverInit;
140-
},
141-
): Promise<Result> {
142-
const interval = setInterval(detectChanges, 10);
143-
return waitForElement(callback, { container: fixture.nativeElement, ...options }).finally(() =>
144-
clearInterval(interval),
145-
);
133+
interval?: number;
134+
mutationObserverOptions?: {
135+
subtree: boolean;
136+
childList: boolean;
137+
attributes: boolean;
138+
characterData: boolean;
139+
};
140+
} = { container: fixture.nativeElement, interval: 50 },
141+
): Promise<T> {
142+
const interval = setInterval(detectChanges, options.interval);
143+
return waitFor<T>(callback, options).finally(() => clearInterval(interval));
146144
}
147145

148-
function componentWaitForElementToBeRemoved<Result>(
149-
callback: () => Result,
150-
options?: {
146+
function componentWaitForElementToBeRemoved<T>(
147+
callback: () => T,
148+
options: {
151149
container?: HTMLElement;
152150
timeout?: number;
153-
mutationObserverOptions?: MutationObserverInit;
154-
},
155-
): Promise<Result> {
156-
const interval = setInterval(detectChanges, 10);
157-
return waitForElementToBeRemoved(callback, { container: fixture.nativeElement, ...options }).finally(() =>
158-
clearInterval(interval),
159-
);
151+
interval?: number;
152+
mutationObserverOptions?: {
153+
subtree: boolean;
154+
childList: boolean;
155+
attributes: boolean;
156+
characterData: boolean;
157+
};
158+
} = { container: fixture.nativeElement, interval: 50 },
159+
): Promise<T> {
160+
const interval = setInterval(detectChanges, options.interval);
161+
return waitForElementToBeRemoved<T>(callback, options).finally(() => clearInterval(interval));
160162
}
161163

162164
return {
@@ -169,8 +171,8 @@ export async function render<SutType, WrapperType = SutType>(
169171
debug: (element = fixture.nativeElement) => console.log(prettyDOM(element)),
170172
type: createType(eventsWithDetectChanges),
171173
selectOptions: createSelectOptions(eventsWithDetectChanges),
172-
waitForDomChange: componentWaitForDomChange,
173-
waitForElement: componentWaitForElement,
174+
tab,
175+
waitFor: componentWaitFor,
174176
waitForElementToBeRemoved: componentWaitForElementToBeRemoved,
175177
...getQueriesForElement(fixture.nativeElement, queries),
176178
...eventsWithDetectChanges,
@@ -234,3 +236,20 @@ function addAutoImports({ imports, routes }: Pick<RenderComponentOptions<any>, '
234236

235237
return [...imports, ...animations(), ...routing()];
236238
}
239+
240+
function cleanup() {
241+
mountedContainers.forEach(cleanupAtContainer);
242+
}
243+
244+
function cleanupAtContainer(container) {
245+
if (container.parentNode === document.body) {
246+
document.body.removeChild(container);
247+
}
248+
mountedContainers.delete(container);
249+
}
250+
251+
if (typeof afterEach === 'function' && !process.env.ATL_SKIP_AUTO_CLEANUP) {
252+
afterEach(async () => {
253+
cleanup();
254+
});
255+
}

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { fireEvent } from '@testing-library/dom';
22
import { createType } from './type';
33
import { createSelectOptions } from './selectOptions';
4+
import { tab } from './tab';
45

56
export interface UserEvents {
67
/**
@@ -31,9 +32,22 @@ export interface UserEvents {
3132
* component.selectOptions(component.getByLabelText('Fruit'), ['Blueberry'. 'Grape'])
3233
*/
3334
selectOptions: ReturnType<typeof createSelectOptions>;
35+
36+
/**
37+
* @description
38+
* Fires a tab event changing the document.activeElement in the same way the browser does.
39+
*
40+
* @argument
41+
* shift: can be set to true to invert tab direction (default false)
42+
* focusTrap: a container element to restrict the tabbing within (default document)
43+
*
44+
* @example
45+
* component.tab()
46+
*/
47+
tab: typeof tab;
3448
}
3549

3650
const type = createType(fireEvent);
3751
const selectOptions = createSelectOptions(fireEvent);
3852

39-
export { createType, type, createSelectOptions, selectOptions };
53+
export { createType, type, createSelectOptions, selectOptions, tab };
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import userEvent from '@testing-library/user-event';
2+
3+
export interface ITabUserOptions {
4+
shift?: boolean;
5+
focusTrap?: Document | Element;
6+
}
7+
8+
export function tab(options?: ITabUserOptions) {
9+
return userEvent.tab(options);
10+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { Component, Input } from '@angular/core';
2+
import { render } from '../src/public_api';
3+
4+
@Component({
5+
selector: 'fixture',
6+
template: `
7+
Hello {{ name }}!
8+
`,
9+
})
10+
class FixtureComponent {
11+
@Input() name: string;
12+
}
13+
14+
describe('Angular auto clean up - previous components only get cleanup up on init (based on root-id)', () => {
15+
test('first', async () => {
16+
await render(FixtureComponent, {
17+
componentProperties: {
18+
name: 'first',
19+
},
20+
});
21+
});
22+
23+
test('second', async () => {
24+
await render(FixtureComponent, {
25+
componentProperties: {
26+
name: 'second',
27+
},
28+
});
29+
expect(document.body.innerHTML).not.toContain('first');
30+
});
31+
});
32+
33+
describe('ATL auto clean up - after each test the containers get removed', () => {
34+
test('first', async () => {
35+
await render(FixtureComponent, {
36+
removeAngularAttributes: true,
37+
});
38+
});
39+
40+
test('second', () => {
41+
expect(document.body.innerHTML).toEqual('');
42+
});
43+
});

‎projects/testing-library/tests/directive.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,24 @@ test('overrides output properties', async () => {
7777
component.click(component.getByText('on'));
7878
expect(clicked).toHaveBeenCalledWith('off');
7979
});
80+
81+
describe('removeAngularAttributes', () => {
82+
test('should remove angular attributes', async () => {
83+
await render(OnOffDirective, {
84+
template: '<div onOff (clicked)="clicked($event)"></div>',
85+
removeAngularAttributes: true,
86+
});
87+
88+
expect(document.querySelector('[ng-version]')).toBeNull();
89+
expect(document.querySelector('[id]')).toBeNull();
90+
});
91+
92+
test('is disabled by default', async () => {
93+
await render(OnOffDirective, {
94+
template: '<div onOff (clicked)="clicked($event)"></div>',
95+
});
96+
97+
expect(document.querySelector('[ng-version]')).not.toBeNull();
98+
expect(document.querySelector('[id]')).not.toBeNull();
99+
});
100+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// https://github.com/testing-library/angular-testing-library/issues/67
2+
import { Component } from '@angular/core';
3+
import { render } from '../../src/public_api';
4+
5+
@Component({
6+
template: `
7+
<div>
8+
<!-- if remove for="name" no error happens -->
9+
<label for="name">
10+
<input type="checkbox" id="name" data-testid="checkbox" />
11+
TEST
12+
</label>
13+
</div>
14+
`,
15+
})
16+
export class BugGetByLabelTextComponent {}
17+
18+
it('first step to reproduce the bug: skip this test to avoid the error or remove the for attribute of label', async () => {
19+
expect(await render(BugGetByLabelTextComponent)).toBeDefined();
20+
});
21+
22+
it('second step: bug happens :`(', async () => {
23+
const { getByLabelText, getByTestId } = await render(BugGetByLabelTextComponent);
24+
25+
const checkboxByTestId = getByTestId('checkbox');
26+
const checkboxByLabelTest = getByLabelText('TEST');
27+
28+
expect(checkboxByTestId).toBe(checkboxByLabelTest);
29+
});

‎projects/testing-library/tests/render.spec.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,26 @@ test('creates queries and events', async () => {
2020
component.click(component.getByText('button'));
2121
});
2222

23+
describe('removeAngularAttributes', () => {
24+
test('should remove angular attribute', async () => {
25+
await render(FixtureComponent, {
26+
removeAngularAttributes: true,
27+
});
28+
29+
expect(document.querySelector('[ng-version]')).toBeNull();
30+
expect(document.querySelector('[id]')).toBeNull();
31+
});
32+
33+
test('is disabled by default', async () => {
34+
await render(FixtureComponent, {
35+
removeAngularAttributes: false,
36+
});
37+
38+
expect(document.querySelector('[ng-version]')).not.toBeNull();
39+
expect(document.querySelector('[id]')).not.toBeNull();
40+
});
41+
});
42+
2343
@NgModule({
2444
declarations: [FixtureComponent],
2545
})
@@ -36,7 +56,7 @@ describe('excludeComponentDeclaration', () => {
3656
describe('animationModule', () => {
3757
test('adds NoopAnimationsModule by default', async () => {
3858
await render(FixtureComponent);
39-
const noopAnimationsModule = TestBed.get<NoopAnimationsModule>(NoopAnimationsModule);
59+
const noopAnimationsModule = TestBed.inject(NoopAnimationsModule);
4060
expect(noopAnimationsModule).toBeDefined();
4161
});
4262

@@ -45,9 +65,9 @@ describe('animationModule', () => {
4565
imports: [BrowserAnimationsModule],
4666
});
4767

48-
const browserAnimationsModule = TestBed.get<BrowserAnimationsModule>(BrowserAnimationsModule);
68+
const browserAnimationsModule = TestBed.inject(BrowserAnimationsModule);
4969
expect(browserAnimationsModule).toBeDefined();
5070

51-
expect(() => TestBed.get<NoopAnimationsModule>(NoopAnimationsModule)).toThrow();
71+
expect(() => TestBed.inject(NoopAnimationsModule)).toThrow();
5272
});
5373
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Component } from '@angular/core';
2+
import { render } from '../../src/public_api';
3+
4+
test('cycles through elements in document tab order', async () => {
5+
@Component({
6+
selector: 'fixture',
7+
template: `
8+
<div>
9+
<input data-testid="element" type="checkbox" />
10+
<input data-testid="element" type="radio" />
11+
<input data-testid="element" type="number" />
12+
</div>
13+
`,
14+
})
15+
class FixtureComponent {}
16+
17+
const component = await render(FixtureComponent);
18+
const [checkbox, radio, number] = component.getAllByTestId('element');
19+
20+
expect(document.body).toHaveFocus();
21+
22+
component.tab();
23+
24+
expect(checkbox).toHaveFocus();
25+
26+
component.tab();
27+
28+
expect(radio).toHaveFocus();
29+
30+
component.tab();
31+
32+
expect(number).toHaveFocus();
33+
34+
component.tab();
35+
36+
// cycle goes back to first element
37+
expect(checkbox).toHaveFocus();
38+
});

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

Lines changed: 0 additions & 40 deletions
This file was deleted.

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

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

55
@Component({
66
selector: 'fixture',
@@ -17,21 +17,23 @@ class FixtureComponent {
1717
}
1818
}
1919

20-
test('waits for element to be visible', async () => {
21-
const { getByTestId, click, waitForElement, getByText } = await render(FixtureComponent);
20+
test('waits for assertion to become true', async () => {
21+
const { queryByText, getByTestId, click, waitFor, getByText } = await render(FixtureComponent);
22+
23+
expect(queryByText('Success')).toBeNull();
2224

2325
click(getByTestId('button'));
2426

25-
await waitForElement(() => getByText('Success'));
27+
await waitFor(() => getByText('Success'));
2628
getByText('Success');
2729
});
2830

2931
test('allows to override options', async () => {
30-
const { getByTestId, click, waitForElement, getByText } = await render(FixtureComponent);
32+
const { getByTestId, click, waitFor, getByText } = await render(FixtureComponent);
3133

3234
click(getByTestId('button'));
3335

34-
await expect(waitForElement(() => getByText('Success'), { timeout: 200 })).rejects.toThrow(
36+
await expect(waitFor(() => getByText('Success'), { timeout: 200 })).rejects.toThrow(
3537
/Unable to find an element with the text: Success/i,
3638
);
3739
});

‎projects/testing-library/tsconfig.lib.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@
1111
"emitDecoratorMetadata": true,
1212
"experimentalDecorators": true,
1313
"importHelpers": true,
14-
"types": [],
14+
"types": ["@types/jest", "@types/node"],
1515
"lib": ["dom", "es2015", "es2018.promise"]
1616
},
1717
"angularCompilerOptions": {
18-
"annotateForClosureCompiler": true,
1918
"skipTemplateCodegen": true,
2019
"strictMetadataEmit": true,
2120
"fullTemplateTypeCheck": true,
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "./tsconfig.lib.json",
3+
"angularCompilerOptions": {
4+
"enableIvy": false
5+
}
6+
}

‎release.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
pkgRoot: 'dist/@testing-library/angular',
3+
branches: ['master', { name: 'beta', prerelease: true }],
4+
};

‎src/app/app.module.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ import { WithNgRxStoreComponent, reducer } from './examples/06-with-ngrx-store';
2222
import { WithNgRxMockStoreComponent } from './examples/07-with-ngrx-mock-store';
2323
import { MasterComponent, DetailComponent, HiddenDetailComponent } from './examples/09-router';
2424

25+
function reducerItems() {
26+
return ['One', 'Two', 'Three'];
27+
}
28+
2529
@NgModule({
2630
declarations: [
2731
AppComponent,
@@ -51,9 +55,7 @@ import { MasterComponent, DetailComponent, HiddenDetailComponent } from './examp
5155
AppRoutingModule,
5256
StoreModule.forRoot({
5357
value: reducer,
54-
items: function() {
55-
return ['One', 'Two', 'Three'];
56-
},
58+
items: reducerItems,
5759
}),
5860
],
5961
bootstrap: [AppComponent],
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
import { render } from '@testing-library/angular';
1+
import { render, screen } 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 component = await render(SingleComponent);
6+
const { click } = await render(SingleComponent);
77

8-
const incrementControl = component.getByText('Increment');
9-
const decrementControl = component.getByText('Decrement');
10-
const valueControl = component.getByTestId('value');
8+
const incrementControl = screen.getByText('Increment');
9+
const decrementControl = screen.getByText('Decrement');
10+
const valueControl = screen.getByTestId('value');
1111

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

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

18-
component.click(decrementControl);
18+
click(decrementControl);
1919
expect(valueControl.textContent).toBe('1');
2020
});
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
import { render } from '@testing-library/angular';
1+
import { render, screen } 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 component = await render(NestedContainerComponent, {
6+
const { click } = await render(NestedContainerComponent, {
77
declarations: [NestedButtonComponent, NestedValueComponent],
88
});
99

10-
const incrementControl = component.getByText('Increment');
11-
const decrementControl = component.getByText('Decrement');
12-
const valueControl = component.getByTestId('value');
10+
const incrementControl = screen.getByText('Increment');
11+
const decrementControl = screen.getByText('Decrement');
12+
const valueControl = screen.getByTestId('value');
1313

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

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

20-
component.click(decrementControl);
20+
click(decrementControl);
2121
expect(valueControl.textContent).toBe('1');
2222
});
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { render } from '@testing-library/angular';
1+
import { render, screen } 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 component = await render(InputOutputComponent, {
8+
const { click } = await render(InputOutputComponent, {
99
componentProperties: {
1010
value: 47,
1111
sendValue: {
@@ -14,18 +14,18 @@ test('is possible to set input and listen for output', async () => {
1414
},
1515
});
1616

17-
const incrementControl = component.getByText('Increment');
18-
const valueControl = component.getByTestId('value');
19-
const sendControl = component.getByText('Send');
17+
const incrementControl = screen.getByText('Increment');
18+
const valueControl = screen.getByTestId('value');
19+
const sendControl = screen.getByText('Send');
2020

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

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

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

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

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,35 @@
11
import { ReactiveFormsModule } from '@angular/forms';
2-
import { render } from '@testing-library/angular';
2+
import { render, screen } 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 component = await render(FormsComponent, {
7+
const { type, blur, selectOptions } = await render(FormsComponent, {
88
imports: [ReactiveFormsModule],
99
});
1010

11-
const nameControl = component.getByLabelText('Name');
12-
const scoreControl = component.getByLabelText(/score/i);
13-
const colorControl = component.getByLabelText('color', { exact: false });
14-
const errors = component.getByRole('alert');
11+
const nameControl = screen.getByLabelText('Name');
12+
const scoreControl = screen.getByLabelText(/score/i);
13+
const colorControl = screen.getByLabelText('color', { exact: false });
14+
const errors = screen.getByRole('alert');
1515

16-
expect(errors).toContainElement(component.queryByText('name is required'));
17-
expect(errors).toContainElement(component.queryByText('score must be greater than 1'));
18-
expect(errors).toContainElement(component.queryByText('color is required'));
16+
expect(errors).toContainElement(screen.queryByText('name is required'));
17+
expect(errors).toContainElement(screen.queryByText('score must be greater than 1'));
18+
expect(errors).toContainElement(screen.queryByText('color is required'));
1919

2020
expect(nameControl).toBeInvalid();
21-
component.type(nameControl, 'Tim');
22-
component.type(scoreControl, '12');
23-
component.blur(scoreControl);
24-
component.selectOptions(colorControl, 'Green');
21+
type(nameControl, 'Tim');
22+
type(scoreControl, '12');
23+
blur(scoreControl);
24+
selectOptions(colorControl, 'Green');
2525

26-
expect(component.queryByText('name is required')).not.toBeInTheDocument();
27-
expect(component.queryByText('score must be lesser than 10')).toBeInTheDocument();
28-
expect(component.queryByText('color is required')).not.toBeInTheDocument();
26+
expect(screen.queryByText('name is required')).not.toBeInTheDocument();
27+
expect(screen.queryByText('score must be lesser than 10')).toBeInTheDocument();
28+
expect(screen.queryByText('color is required')).not.toBeInTheDocument();
2929

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

3535
expect(errors).not.toBeInTheDocument();
@@ -38,7 +38,7 @@ test('is possible to fill in a form and verify error messages (with the help of
3838
expect(scoreControl).toHaveValue(7);
3939
expect(colorControl).toHaveValue('G');
4040

41-
const form = component.getByTestId('my-form');
41+
const form = screen.getByTestId('my-form');
4242
expect(form).toHaveFormValues({
4343
name: 'Tim',
4444
score: 7,
Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
11
import { ReactiveFormsModule } from '@angular/forms';
2-
import { render } from '@testing-library/angular';
2+
import { render, screen } from '@testing-library/angular';
33

44
import { MaterialModule } from '../material.module';
55
import { MaterialFormsComponent } from './04-forms-with-material';
66

77
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 () => {
8-
const component = await render(MaterialFormsComponent, {
8+
const { type, selectOptions, fixture } = await render(MaterialFormsComponent, {
99
imports: [ReactiveFormsModule, MaterialModule],
1010
});
1111

12-
const nameControl = component.getByPlaceholderText('Name');
13-
const scoreControl = component.getByPlaceholderText(/score/i);
14-
const colorControl = component.getByPlaceholderText('color', { exact: false });
15-
const errors = component.getByRole('alert');
12+
const nameControl = screen.getByPlaceholderText('Name');
13+
const scoreControl = screen.getByPlaceholderText(/score/i);
14+
const colorControl = screen.getByPlaceholderText('color', { exact: false });
15+
const errors = screen.getByRole('alert');
1616

17-
expect(errors).toContainElement(component.queryByText('name is required'));
18-
expect(errors).toContainElement(component.queryByText('score must be greater than 1'));
19-
expect(errors).toContainElement(component.queryByText('color is required'));
17+
expect(errors).toContainElement(screen.queryByText('name is required'));
18+
expect(errors).toContainElement(screen.queryByText('score must be greater than 1'));
19+
expect(errors).toContainElement(screen.queryByText('color is required'));
2020

21-
component.type(nameControl, 'Tim');
22-
component.type(scoreControl, 12);
23-
component.selectOptions(colorControl, 'Green');
21+
type(nameControl, 'Tim');
22+
type(scoreControl, 12);
23+
selectOptions(colorControl, 'Green');
2424

25-
expect(component.queryByText('name is required')).not.toBeInTheDocument();
26-
expect(component.queryByText('score must be lesser than 10')).toBeInTheDocument();
27-
expect(component.queryByText('color is required')).not.toBeInTheDocument();
25+
expect(screen.queryByText('name is required')).not.toBeInTheDocument();
26+
expect(screen.queryByText('score must be lesser than 10')).toBeInTheDocument();
27+
expect(screen.queryByText('color is required')).not.toBeInTheDocument();
2828

2929
expect(scoreControl).toBeInvalid();
30-
component.type(scoreControl, 7);
30+
type(scoreControl, 7);
3131
expect(scoreControl).toBeValid();
3232

3333
expect(errors).not.toBeInTheDocument();
3434

3535
expect(nameControl).toHaveValue('Tim');
3636
expect(scoreControl).toHaveValue(7);
3737

38-
const form = component.getByTestId('my-form');
38+
const form = screen.getByTestId('my-form');
3939
expect(form).toHaveFormValues({
4040
name: 'Tim',
4141
score: 7,
4242
});
4343

4444
// not added to the form?
45-
expect((component.fixture.componentInstance as MaterialFormsComponent).form.get('color').value).toBe('G');
45+
expect((fixture.componentInstance as MaterialFormsComponent).form.get('color').value).toBe('G');
4646
});
Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { TestBed } from '@angular/core/testing';
2-
import { render } from '@testing-library/angular';
2+
import { render, screen } 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 component = await render(ComponentWithProviderComponent, {
8+
const { click } = await render(ComponentWithProviderComponent, {
99
componentProviders: [
1010
{
1111
provide: CounterService,
@@ -14,17 +14,17 @@ test('renders the current value and can increment and decrement', async () => {
1414
],
1515
});
1616

17-
const incrementControl = component.getByText('Increment');
18-
const decrementControl = component.getByText('Decrement');
19-
const valueControl = component.getByTestId('value');
17+
const incrementControl = screen.getByText('Increment');
18+
const decrementControl = screen.getByText('Decrement');
19+
const valueControl = screen.getByTestId('value');
2020

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

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

27-
component.click(decrementControl);
27+
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 component = await render(ComponentWithProviderComponent, {
38+
const { click } = await render(ComponentWithProviderComponent, {
3939
componentProviders: [
4040
{
4141
provide: CounterService,
@@ -44,33 +44,33 @@ test('renders the current value and can increment and decrement with a mocked je
4444
],
4545
});
4646

47-
const incrementControl = component.getByText('Increment');
48-
const decrementControl = component.getByText('Decrement');
49-
const valueControl = component.getByTestId('value');
47+
const incrementControl = screen.getByText('Increment');
48+
const decrementControl = screen.getByText('Decrement');
49+
const valueControl = screen.getByTestId('value');
5050

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

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

57-
component.click(decrementControl);
57+
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 component = await render(ComponentWithProviderComponent, {
62+
const { click } = await render(ComponentWithProviderComponent, {
6363
componentProviders: [provideMock(CounterService)],
6464
});
6565

66-
const incrementControl = component.getByText('Increment');
67-
const decrementControl = component.getByText('Decrement');
66+
const incrementControl = screen.getByText('Increment');
67+
const decrementControl = screen.getByText('Decrement');
6868

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

73-
const counterService = TestBed.get<CounterService>(CounterService) as Mock<CounterService>;
73+
const counterService = TestBed.inject(CounterService) as Mock<CounterService>;
7474
expect(counterService.increment).toHaveBeenCalledTimes(2);
7575
expect(counterService.decrement).toHaveBeenCalledTimes(1);
7676
});
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { render } from '@testing-library/angular';
1+
import { render, screen } 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 component = await render(WithNgRxStoreComponent, {
7+
const { click } = await render(WithNgRxStoreComponent, {
88
imports: [
99
StoreModule.forRoot(
1010
{
@@ -17,16 +17,16 @@ test('works with ngrx store', async () => {
1717
],
1818
});
1919

20-
const incrementControl = component.getByText('Increment');
21-
const decrementControl = component.getByText('Decrement');
22-
const valueControl = component.getByTestId('value');
20+
const incrementControl = screen.getByText('Increment');
21+
const decrementControl = screen.getByText('Decrement');
22+
const valueControl = screen.getByTestId('value');
2323

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

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

30-
component.click(decrementControl);
30+
click(decrementControl);
3131
expect(valueControl.textContent).toBe('10');
3232
});
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { render } from '@testing-library/angular';
1+
import { TestBed } from '@angular/core/testing';
2+
import { Store } from '@ngrx/store';
23
import { provideMockStore, MockStore } from '@ngrx/store/testing';
4+
import { render, screen } from '@testing-library/angular';
35

46
import { WithNgRxMockStoreComponent, selectItems } from './07-with-ngrx-mock-store';
5-
import { TestBed } from '@angular/core/testing';
6-
import { Store } from '@ngrx/store';
77

88
test('works with provideMockStore', async () => {
9-
const component = await render(WithNgRxMockStoreComponent, {
9+
const { click } = await render(WithNgRxMockStoreComponent, {
1010
providers: [
1111
provideMockStore({
1212
selectors: [
@@ -19,11 +19,11 @@ test('works with provideMockStore', async () => {
1919
],
2020
});
2121

22-
const store = TestBed.get(Store) as MockStore<any>;
22+
const store = TestBed.inject(MockStore);
2323
store.dispatch = jest.fn();
2424

25-
component.getByText('Four');
26-
component.click(component.getByText('Seven'));
25+
screen.getByText('Four');
26+
click(screen.getByText('Seven'));
2727

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

‎src/app/examples/08-directive.spec.ts

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

33
import { SpoilerDirective } from './08-directive';
44

55
test('it is possible to test directives', async () => {
6-
const component = await render(SpoilerDirective, {
6+
const { mouseOver, mouseLeave, debugElement } = await render(SpoilerDirective, {
77
template: `<div appSpoiler></div>`,
88
});
99

10-
expect(component.queryByText('I am visible now...')).not.toBeInTheDocument();
11-
expect(component.queryByText('SPOILER')).toBeInTheDocument();
10+
expect(screen.queryByText('I am visible now...')).not.toBeInTheDocument();
11+
expect(screen.queryByText('SPOILER')).toBeInTheDocument();
1212

13-
component.mouseOver(component.debugElement.nativeElement);
14-
expect(component.queryByText('SPOILER')).not.toBeInTheDocument();
15-
expect(component.queryByText('I am visible now...')).toBeInTheDocument();
13+
mouseOver(debugElement.nativeElement);
14+
expect(screen.queryByText('SPOILER')).not.toBeInTheDocument();
15+
expect(screen.queryByText('I am visible now...')).toBeInTheDocument();
1616

17-
component.mouseLeave(component.debugElement.nativeElement);
18-
expect(component.queryByText('SPOILER')).toBeInTheDocument();
19-
expect(component.queryByText('I am visible now...')).not.toBeInTheDocument();
17+
mouseLeave(debugElement.nativeElement);
18+
expect(screen.queryByText('SPOILER')).toBeInTheDocument();
19+
expect(screen.queryByText('I am visible now...')).not.toBeInTheDocument();
2020
});
2121

2222
test('it is possible to test directives with props', async () => {
2323
const hidden = 'SPOILER ALERT';
2424
const visible = 'There is nothing to see here ...';
2525

26-
const component = await render(SpoilerDirective, {
26+
const { mouseOver, mouseLeave } = await render(SpoilerDirective, {
2727
template: `<div appSpoiler [hidden]="hidden" [visible]="visible"></div>`,
2828
componentProperties: {
2929
hidden,
3030
visible,
3131
},
3232
});
3333

34-
expect(component.queryByText(visible)).not.toBeInTheDocument();
35-
expect(component.queryByText(hidden)).toBeInTheDocument();
34+
expect(screen.queryByText(visible)).not.toBeInTheDocument();
35+
expect(screen.queryByText(hidden)).toBeInTheDocument();
3636

37-
component.mouseOver(component.queryByText(hidden));
38-
expect(component.queryByText(hidden)).not.toBeInTheDocument();
39-
expect(component.queryByText(visible)).toBeInTheDocument();
37+
mouseOver(screen.queryByText(hidden));
38+
expect(screen.queryByText(hidden)).not.toBeInTheDocument();
39+
expect(screen.queryByText(visible)).toBeInTheDocument();
4040

41-
component.mouseLeave(component.queryByText(visible));
42-
expect(component.queryByText(hidden)).toBeInTheDocument();
43-
expect(component.queryByText(visible)).not.toBeInTheDocument();
41+
mouseLeave(screen.queryByText(visible));
42+
expect(screen.queryByText(hidden)).toBeInTheDocument();
43+
expect(screen.queryByText(visible)).not.toBeInTheDocument();
4444
});
4545

4646
test('it is possible to test directives with props in template', async () => {
4747
const hidden = 'SPOILER ALERT';
4848
const visible = 'There is nothing to see here ...';
4949

50-
const component = await render(SpoilerDirective, {
50+
const { mouseLeave, mouseOver } = await render(SpoilerDirective, {
5151
template: `<div appSpoiler hidden="${hidden}" visible="${visible}"></div>`,
5252
});
5353

54-
expect(component.queryByText(visible)).not.toBeInTheDocument();
55-
expect(component.queryByText(hidden)).toBeInTheDocument();
54+
expect(screen.queryByText(visible)).not.toBeInTheDocument();
55+
expect(screen.queryByText(hidden)).toBeInTheDocument();
5656

57-
component.mouseOver(component.queryByText(hidden));
58-
expect(component.queryByText(hidden)).not.toBeInTheDocument();
59-
expect(component.queryByText(visible)).toBeInTheDocument();
57+
mouseOver(screen.queryByText(hidden));
58+
expect(screen.queryByText(hidden)).not.toBeInTheDocument();
59+
expect(screen.queryByText(visible)).toBeInTheDocument();
6060

61-
component.mouseLeave(component.queryByText(visible));
62-
expect(component.queryByText(hidden)).toBeInTheDocument();
63-
expect(component.queryByText(visible)).not.toBeInTheDocument();
61+
mouseLeave(screen.queryByText(visible));
62+
expect(screen.queryByText(hidden)).toBeInTheDocument();
63+
expect(screen.queryByText(visible)).not.toBeInTheDocument();
6464
});

‎src/app/examples/09-router.spec.ts

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

33
import { DetailComponent, MasterComponent, HiddenDetailComponent } from './09-router';
4-
import { TestBed } from '@angular/core/testing';
5-
import { Router } from '@angular/router';
64

75
test('it can navigate to routes', async () => {
8-
const component = await render(MasterComponent, {
6+
const { navigate } = await render(MasterComponent, {
97
declarations: [DetailComponent, HiddenDetailComponent],
108
routes: [
119
{
@@ -24,27 +22,27 @@ test('it can navigate to routes', async () => {
2422
],
2523
});
2624

27-
expect(component.queryByText(/Detail one/i)).not.toBeInTheDocument();
25+
expect(screen.queryByText(/Detail one/i)).not.toBeInTheDocument();
2826

29-
await component.navigate(component.getByText(/Load one/));
30-
expect(component.queryByText(/Detail one/i)).toBeInTheDocument();
27+
await navigate(screen.getByText(/Load one/));
28+
expect(screen.queryByText(/Detail one/i)).toBeInTheDocument();
3129

32-
await component.navigate(component.getByText(/Load three/));
33-
expect(component.queryByText(/Detail one/i)).not.toBeInTheDocument();
34-
expect(component.queryByText(/Detail three/i)).toBeInTheDocument();
30+
await navigate(screen.getByText(/Load three/));
31+
expect(screen.queryByText(/Detail one/i)).not.toBeInTheDocument();
32+
expect(screen.queryByText(/Detail three/i)).toBeInTheDocument();
3533

36-
await component.navigate(component.getByText(/Back to parent/));
37-
expect(component.queryByText(/Detail three/i)).not.toBeInTheDocument();
34+
await navigate(screen.getByText(/Back to parent/));
35+
expect(screen.queryByText(/Detail three/i)).not.toBeInTheDocument();
3836

39-
await component.navigate(component.getByText(/Load two/));
40-
expect(component.queryByText(/Detail two/i)).toBeInTheDocument();
41-
await component.navigate(component.getByText(/hidden x/));
42-
expect(component.queryByText(/You found the treasure!/i)).toBeInTheDocument();
37+
await navigate(screen.getByText(/Load two/));
38+
expect(screen.queryByText(/Detail two/i)).toBeInTheDocument();
39+
await navigate(screen.getByText(/hidden x/));
40+
expect(screen.queryByText(/You found the treasure!/i)).toBeInTheDocument();
4341
});
4442

4543
test('it can navigate to routes with a base path', async () => {
4644
const basePath = 'base';
47-
const component = await render(MasterComponent, {
45+
const { navigate } = await render(MasterComponent, {
4846
declarations: [DetailComponent, HiddenDetailComponent],
4947
routes: [
5048
{
@@ -63,20 +61,20 @@ test('it can navigate to routes with a base path', async () => {
6361
],
6462
});
6563

66-
expect(component.queryByText(/Detail one/i)).not.toBeInTheDocument();
64+
expect(screen.queryByText(/Detail one/i)).not.toBeInTheDocument();
6765

68-
await component.navigate(component.getByText(/Load one/), basePath);
69-
expect(component.queryByText(/Detail one/i)).toBeInTheDocument();
66+
await navigate(screen.getByText(/Load one/), basePath);
67+
expect(screen.queryByText(/Detail one/i)).toBeInTheDocument();
7068

71-
await component.navigate(component.getByText(/Load three/), basePath);
72-
expect(component.queryByText(/Detail one/i)).not.toBeInTheDocument();
73-
expect(component.queryByText(/Detail three/i)).toBeInTheDocument();
69+
await navigate(screen.getByText(/Load three/), basePath);
70+
expect(screen.queryByText(/Detail one/i)).not.toBeInTheDocument();
71+
expect(screen.queryByText(/Detail three/i)).toBeInTheDocument();
7472

75-
await component.navigate(component.getByText(/Back to parent/));
76-
expect(component.queryByText(/Detail three/i)).not.toBeInTheDocument();
73+
await navigate(screen.getByText(/Back to parent/));
74+
expect(screen.queryByText(/Detail three/i)).not.toBeInTheDocument();
7775

78-
await component.navigate('base/detail/two'); // possible to just use strings
79-
expect(component.queryByText(/Detail two/i)).toBeInTheDocument();
80-
await component.navigate('/hidden-detail', basePath);
81-
expect(component.queryByText(/You found the treasure!/i)).toBeInTheDocument();
76+
await navigate('base/detail/two'); // possible to just use strings
77+
expect(screen.queryByText(/Detail two/i)).toBeInTheDocument();
78+
await navigate('/hidden-detail', basePath);
79+
expect(screen.queryByText(/You found the treasure!/i)).toBeInTheDocument();
8280
});
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { render } from '@testing-library/angular';
1+
import { render, screen } from '@testing-library/angular';
22

33
import { DataInjectedComponent, DATA } from './10-inject-token-dependency';
44

55
test('injects data into the component', async () => {
6-
const component = await render(DataInjectedComponent, {
6+
await render(DataInjectedComponent, {
77
providers: [
88
{
99
provide: DATA,
@@ -12,5 +12,5 @@ test('injects data into the component', async () => {
1212
],
1313
});
1414

15-
expect(component.getByText(/Hello boys and girls/i)).toBeInTheDocument();
15+
expect(screen.getByText(/Hello boys and girls/i)).toBeInTheDocument();
1616
});

‎src/tsconfig.app.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"extends": "../tsconfig.json",
33
"compilerOptions": {
44
"outDir": "../out-tsc/app",
5-
"types": []
5+
"types": [],
6+
"allowJs": true
67
},
7-
"exclude": ["**/test.ts", "**/*.spec.ts"]
8+
"files": ["main.ts", "polyfills.ts"]
89
}

‎yarn.lock

Lines changed: 4194 additions & 1567 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.