From a9237f22dd6586e1c7b012fae74ce5a2e03c5abc Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Thu, 9 Dec 2021 15:53:14 +0100
Subject: [PATCH 1/9] test: add test case for #269 (#271)
Closes #269
---
.../src/app/examples/18-html-as-input.spec.ts | 36 +++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 apps/example-app/src/app/examples/18-html-as-input.spec.ts
diff --git a/apps/example-app/src/app/examples/18-html-as-input.spec.ts b/apps/example-app/src/app/examples/18-html-as-input.spec.ts
new file mode 100644
index 00000000..5a56b412
--- /dev/null
+++ b/apps/example-app/src/app/examples/18-html-as-input.spec.ts
@@ -0,0 +1,36 @@
+import { render, screen } from '@testing-library/angular';
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+ name: 'stripHTML',
+})
+class StripHTMLPipe implements PipeTransform {
+ transform(stringValueWithHTML: string): string {
+ return stringValueWithHTML.replace(/<[^>]*>?/gm, '');
+ }
+}
+
+const STRING_WITH_HTML =
+ 'Some database field
with stripped HTML
';
+
+// https://github.com/testing-library/angular-testing-library/pull/271
+test('passes HTML as component properties', async () => {
+ await render(`{{ stringWithHtml | stripHTML }}
`, {
+ componentProperties: {
+ stringWithHtml: STRING_WITH_HTML,
+ },
+ declarations: [StripHTMLPipe],
+ });
+
+ expect(screen.getByText('Some database field with stripped HTML')).toBeInTheDocument();
+});
+
+
+test('throws when passed HTML is passed in directly', async () => {
+ await expect(() =>
+ render(` {{ '${STRING_WITH_HTML}' | stripHTML }}
`, {
+ declarations: [StripHTMLPipe],
+ }),
+ ).rejects.toThrow();
+});
+
From c9af6efaab15fa9571c6902f56c7ba81bb281386 Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Thu, 9 Dec 2021 15:54:03 +0100
Subject: [PATCH 2/9] refactor: enable strict mode (#274)
Closes #261
---
apps/example-app-karma/src/test.ts | 6 +-
.../src/app/examples/01-nested-component.ts | 4 +-
apps/example-app/src/app/examples/03-forms.ts | 6 +-
.../examples/04-forms-with-material.spec.ts | 3 +-
.../app/examples/04-forms-with-material.ts | 6 +-
.../src/app/examples/06-with-ngrx-store.ts | 6 +-
.../src/app/examples/08-directive.spec.ts | 8 +-
.../src/app/examples/12-service-component.ts | 4 +-
.../app/examples/15-dialog.component.spec.ts | 4 +-
.../app/examples/16-input-getter-setter.ts | 4 +-
.../src/app/issues/issue-254.spec.ts | 45 ++++++------
projects/testing-library/.eslintrc.json | 7 ++
projects/testing-library/src/lib/models.ts | 4 +-
.../src/lib/testing-library.ts | 73 ++++++++++---------
.../tests/auto-cleanup.spec.ts | 2 +-
projects/testing-library/tests/change.spec.ts | 6 +-
projects/testing-library/tests/config.spec.ts | 6 +-
.../testing-library/tests/integration.spec.ts | 6 +-
.../tests/issues/issue-188.spec.ts | 4 +-
.../testing-library/tests/rerender.spec.ts | 2 +-
tsconfig.base.json | 7 +-
21 files changed, 108 insertions(+), 105 deletions(-)
diff --git a/apps/example-app-karma/src/test.ts b/apps/example-app-karma/src/test.ts
index 0a45adb5..827caf48 100644
--- a/apps/example-app-karma/src/test.ts
+++ b/apps/example-app-karma/src/test.ts
@@ -2,11 +2,7 @@
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
-import JasmineDOM from '@testing-library/jasmine-dom/dist';
-
-beforeAll(() => {
- (jasmine.getEnv() as any).addMatchers(JasmineDOM);
-});
+import '@testing-library/jasmine-dom';
declare const require: any;
diff --git a/apps/example-app/src/app/examples/01-nested-component.ts b/apps/example-app/src/app/examples/01-nested-component.ts
index 5b0faeb2..51087b44 100644
--- a/apps/example-app/src/app/examples/01-nested-component.ts
+++ b/apps/example-app/src/app/examples/01-nested-component.ts
@@ -5,7 +5,7 @@ import { Component, Input, Output, EventEmitter } from '@angular/core';
template: ' ',
})
export class NestedButtonComponent {
- @Input() name: string;
+ @Input() name = '';
@Output() raise = new EventEmitter();
}
@@ -14,7 +14,7 @@ export class NestedButtonComponent {
template: ' {{ value }} ',
})
export class NestedValueComponent {
- @Input() value: number;
+ @Input() value?: number;
}
@Component({
diff --git a/apps/example-app/src/app/examples/03-forms.ts b/apps/example-app/src/app/examples/03-forms.ts
index bc035a14..f68766e4 100644
--- a/apps/example-app/src/app/examples/03-forms.ts
+++ b/apps/example-app/src/app/examples/03-forms.ts
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
-import { FormBuilder, Validators, ValidationErrors } from '@angular/forms';
+import { FormBuilder, Validators } from '@angular/forms';
@Component({
selector: 'app-fixture',
@@ -46,8 +46,8 @@ export class FormsComponent {
get formErrors() {
return Object.keys(this.form.controls)
.map((formKey) => {
- const controlErrors: ValidationErrors = this.form.get(formKey).errors;
- if (controlErrors != null) {
+ const controlErrors = this.form.get(formKey)?.errors;
+ if (controlErrors) {
return Object.keys(controlErrors).map((keyError) => {
const error = controlErrors[keyError];
switch (keyError) {
diff --git a/apps/example-app/src/app/examples/04-forms-with-material.spec.ts b/apps/example-app/src/app/examples/04-forms-with-material.spec.ts
index c215d9c4..ee4209b9 100644
--- a/apps/example-app/src/app/examples/04-forms-with-material.spec.ts
+++ b/apps/example-app/src/app/examples/04-forms-with-material.spec.ts
@@ -44,6 +44,5 @@ test('is possible to fill in a form and verify error messages (with the help of
score: 7,
});
- // not added to the form?
- expect((fixture.componentInstance as MaterialFormsComponent).form.get('color').value).toBe('G');
+ expect((fixture.componentInstance as MaterialFormsComponent).form?.get('color')?.value).toBe('G');
});
diff --git a/apps/example-app/src/app/examples/04-forms-with-material.ts b/apps/example-app/src/app/examples/04-forms-with-material.ts
index 2718e389..a672380c 100644
--- a/apps/example-app/src/app/examples/04-forms-with-material.ts
+++ b/apps/example-app/src/app/examples/04-forms-with-material.ts
@@ -1,5 +1,5 @@
import { Component } from '@angular/core';
-import { FormBuilder, Validators, ValidationErrors } from '@angular/forms';
+import { FormBuilder, Validators } from '@angular/forms';
@Component({
selector: 'app-fixture',
@@ -68,8 +68,8 @@ export class MaterialFormsComponent {
get formErrors() {
return Object.keys(this.form.controls)
.map((formKey) => {
- const controlErrors: ValidationErrors = this.form.get(formKey).errors;
- if (controlErrors != null) {
+ const controlErrors = this.form.get(formKey)?.errors;
+ if (controlErrors) {
return Object.keys(controlErrors).map((keyError) => {
const error = controlErrors[keyError];
switch (keyError) {
diff --git a/apps/example-app/src/app/examples/06-with-ngrx-store.ts b/apps/example-app/src/app/examples/06-with-ngrx-store.ts
index f260b978..470f52d9 100644
--- a/apps/example-app/src/app/examples/06-with-ngrx-store.ts
+++ b/apps/example-app/src/app/examples/06-with-ngrx-store.ts
@@ -3,16 +3,12 @@ import { createSelector, Store, createAction, createReducer, on, select } from '
const increment = createAction('increment');
const decrement = createAction('decrement');
-const counterReducer = createReducer(
+export const reducer = createReducer(
0,
on(increment, (state) => state + 1),
on(decrement, (state) => state - 1),
);
-export function reducer(state, action) {
- return counterReducer(state, action);
-}
-
const selectValue = createSelector(
(state: any) => state.value,
(value) => value * 10,
diff --git a/apps/example-app/src/app/examples/08-directive.spec.ts b/apps/example-app/src/app/examples/08-directive.spec.ts
index 5df9413a..ea3332b4 100644
--- a/apps/example-app/src/app/examples/08-directive.spec.ts
+++ b/apps/example-app/src/app/examples/08-directive.spec.ts
@@ -36,11 +36,11 @@ test('it is possible to test directives with props', async () => {
expect(screen.queryByText(visible)).not.toBeInTheDocument();
expect(screen.queryByText(hidden)).toBeInTheDocument();
- fireEvent.mouseOver(screen.queryByText(hidden));
+ fireEvent.mouseOver(screen.getByText(hidden));
expect(screen.queryByText(hidden)).not.toBeInTheDocument();
expect(screen.queryByText(visible)).toBeInTheDocument();
- fireEvent.mouseLeave(screen.queryByText(visible));
+ fireEvent.mouseLeave(screen.getByText(visible));
expect(screen.queryByText(hidden)).toBeInTheDocument();
expect(screen.queryByText(visible)).not.toBeInTheDocument();
});
@@ -56,11 +56,11 @@ test('it is possible to test directives with props in template', async () => {
expect(screen.queryByText(visible)).not.toBeInTheDocument();
expect(screen.queryByText(hidden)).toBeInTheDocument();
- fireEvent.mouseOver(screen.queryByText(hidden));
+ fireEvent.mouseOver(screen.getByText(hidden));
expect(screen.queryByText(hidden)).not.toBeInTheDocument();
expect(screen.queryByText(visible)).toBeInTheDocument();
- fireEvent.mouseLeave(screen.queryByText(visible));
+ fireEvent.mouseLeave(screen.getByText(visible));
expect(screen.queryByText(hidden)).toBeInTheDocument();
expect(screen.queryByText(visible)).not.toBeInTheDocument();
});
diff --git a/apps/example-app/src/app/examples/12-service-component.ts b/apps/example-app/src/app/examples/12-service-component.ts
index af35f10a..d272e270 100644
--- a/apps/example-app/src/app/examples/12-service-component.ts
+++ b/apps/example-app/src/app/examples/12-service-component.ts
@@ -2,8 +2,8 @@ import { Component, Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
export class Customer {
- id: string;
- name: string;
+ id!: string;
+ name!: string;
}
@Injectable({
diff --git a/apps/example-app/src/app/examples/15-dialog.component.spec.ts b/apps/example-app/src/app/examples/15-dialog.component.spec.ts
index f0fbd465..8a0ccd88 100644
--- a/apps/example-app/src/app/examples/15-dialog.component.spec.ts
+++ b/apps/example-app/src/app/examples/15-dialog.component.spec.ts
@@ -37,8 +37,8 @@ test('closes the dialog via the backdrop', async () => {
// using fireEvent because of:
// unable to click element as it has or inherits pointer-events set to "none"
- // eslint-disable-next-line testing-library/no-node-access
- fireEvent.click(document.querySelector('.cdk-overlay-backdrop'));
+ // eslint-disable-next-line testing-library/no-node-access, @typescript-eslint/no-non-null-assertion
+ fireEvent.click(document.querySelector('.cdk-overlay-backdrop')!);
await waitForElementToBeRemoved(() => screen.getByRole('dialog'));
diff --git a/apps/example-app/src/app/examples/16-input-getter-setter.ts b/apps/example-app/src/app/examples/16-input-getter-setter.ts
index 11f8c949..22d9641a 100644
--- a/apps/example-app/src/app/examples/16-input-getter-setter.ts
+++ b/apps/example-app/src/app/examples/16-input-getter-setter.ts
@@ -18,6 +18,6 @@ export class InputGetterSetter {
return 'I am value from getter ' + this.originalValue;
}
- private originalValue: string;
- derivedValue: string;
+ private originalValue?: string;
+ derivedValue?: string;
}
diff --git a/apps/example-app/src/app/issues/issue-254.spec.ts b/apps/example-app/src/app/issues/issue-254.spec.ts
index 01960b4f..74e90fbb 100644
--- a/apps/example-app/src/app/issues/issue-254.spec.ts
+++ b/apps/example-app/src/app/issues/issue-254.spec.ts
@@ -1,12 +1,11 @@
-/* eslint-disable @typescript-eslint/naming-convention */
import { Component, Inject, OnInit } from '@angular/core';
import { render, screen } from '@testing-library/angular';
import { createMock } from '@testing-library/angular/jest-utils';
interface Division {
- JobType: string;
- JobBullets: string[];
- Description: string;
+ jobType?: string;
+ jobBullets?: string[];
+ description?: string;
}
@Inject({
@@ -21,25 +20,25 @@ class JobsService {
@Component({
selector: 'app-home-career-oportunities',
template: ` `,
})
class CareerOportunitiesComponent implements OnInit {
- dedicated = {} as Division;
- intermodal = {} as Division;
- noCdl = {} as Division;
- otr = {} as Division;
+ dedicated?: Division;
+ intermodal?: Division;
+ noCdl?: Division;
+ otr?: Division;
constructor(private jobsService: JobsService) {}
ngOnInit(): void {
this.jobsService.divisions().then((apiDivisions) => {
- this.dedicated = apiDivisions.find((c) => c.JobType === 'DEDICATED');
- this.intermodal = apiDivisions.find((c) => c.JobType === 'INTERMODAL');
- this.noCdl = apiDivisions.find((c) => c.JobType === 'NO_CDL');
- this.otr = apiDivisions.find((c) => c.JobType === 'OVER_THE_ROAD');
+ this.dedicated = apiDivisions.find((c) => c.jobType === 'DEDICATED');
+ this.intermodal = apiDivisions.find((c) => c.jobType === 'INTERMODAL');
+ this.noCdl = apiDivisions.find((c) => c.jobType === 'NO_CDL');
+ this.otr = apiDivisions.find((c) => c.jobType === 'OVER_THE_ROAD');
});
}
}
@@ -47,20 +46,20 @@ class CareerOportunitiesComponent implements OnInit {
test('Render Component', async () => {
const divisions2: Division[] = [
{
- JobType: 'INTERMODAL',
- JobBullets: ['Local Routes', 'Flexible Schedules', 'Competitive Pay'],
- Description: '',
+ jobType: 'INTERMODAL',
+ jobBullets: ['Local Routes', 'Flexible Schedules', 'Competitive Pay'],
+ description: '',
},
- { JobType: 'NO_CDL', JobBullets: ['We Train', 'We Hire', 'We Pay'], Description: '' },
+ { jobType: 'NO_CDL', jobBullets: ['We Train', 'We Hire', 'We Pay'], description: '' },
{
- JobType: 'OVER_THE_ROAD',
- JobBullets: ['Great Miles', 'Competitive Pay', 'Explore the Country'],
- Description: '',
+ jobType: 'OVER_THE_ROAD',
+ jobBullets: ['Great Miles', 'Competitive Pay', 'Explore the Country'],
+ description: '',
},
{
- JobType: 'DEDICATED',
- JobBullets: ['Regular Routes', 'Consistent Miles', 'Great Pay'],
- Description: '',
+ jobType: 'DEDICATED',
+ jobBullets: ['Regular Routes', 'Consistent Miles', 'Great Pay'],
+ description: '',
},
];
const jobService = createMock(JobsService);
diff --git a/projects/testing-library/.eslintrc.json b/projects/testing-library/.eslintrc.json
index 4089aa79..918e7859 100644
--- a/projects/testing-library/.eslintrc.json
+++ b/projects/testing-library/.eslintrc.json
@@ -2,6 +2,12 @@
"extends": "../../.eslintrc.json",
"ignorePatterns": ["!**/*"],
"overrides": [
+ {
+ "files": ["*.ts"],
+ "rules": {
+ "@typescript-eslint/ban-ts-comment": "off"
+ }
+ },
{
"files": ["*.ts"],
"extends": ["plugin:@nrwl/nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
@@ -9,6 +15,7 @@
"project": ["projects/testing-library/tsconfig.*?.json"]
},
"rules": {
+ "@typescript-eslint/ban-ts-comment": "off",
"@angular-eslint/directive-selector": [
"error",
{
diff --git a/projects/testing-library/src/lib/models.ts b/projects/testing-library/src/lib/models.ts
index 7f5a02a7..9320fb6a 100644
--- a/projects/testing-library/src/lib/models.ts
+++ b/projects/testing-library/src/lib/models.ts
@@ -268,8 +268,8 @@ export interface RenderTemplateOptions`
+ * const component = await render(``, {
+ * declarations: [SpoilerDirective]
* wrapper: CustomWrapperComponent
* })
*/
diff --git a/projects/testing-library/src/lib/testing-library.ts b/projects/testing-library/src/lib/testing-library.ts
index 1a517aa2..1197cf8e 100644
--- a/projects/testing-library/src/lib/testing-library.ts
+++ b/projects/testing-library/src/lib/testing-library.ts
@@ -53,8 +53,7 @@ export async function render(
providers = [],
schemas = [],
queries,
- template = undefined,
- wrapper = WrapperComponent,
+ wrapper = WrapperComponent as Type,
componentProperties = {},
componentProviders = [],
excludeComponentDeclaration = false,
@@ -89,13 +88,13 @@ export async function render(
await TestBed.compileComponents();
componentProviders
- .reduce((acc, provider) => acc.concat(provider), [])
- .forEach((p) => {
+ .reduce((acc, provider) => acc.concat(provider), [] as any[])
+ .forEach((p: any) => {
const { provide, ...provider } = p;
TestBed.overrideProvider(provide, provider);
});
- const componentContainer = createComponentFixture(sut, { wrapper });
+ const componentContainer = createComponentFixture(sut, wrapper);
let fixture: ComponentFixture;
let detectChanges: () => void;
@@ -120,7 +119,7 @@ export async function render(
let router = routes ? inject(Router) : null;
const zone = inject(NgZone);
- const navigate = async (elementOrPath: Element | string, basePath = '') => {
+ const navigate = async (elementOrPath: Element | string, basePath = ''): Promise => {
if (!router) {
router = inject(Router);
}
@@ -139,16 +138,18 @@ export async function render(
qp[key] = [currentValue, value];
}
return qp;
- }, {})
+ }, {} as Record)
: undefined;
- const navigateOptions: NavigationExtras = queryParams
+ const navigateOptions: NavigationExtras | undefined = queryParams
? {
queryParams,
}
: undefined;
- const doNavigate = () => (navigateOptions ? router.navigate([path], navigateOptions) : router.navigate([path]));
+ const doNavigate = () => {
+ return navigateOptions ? router?.navigate([path], navigateOptions) : router?.navigate([path]);
+ };
let result;
@@ -159,21 +160,25 @@ export async function render(
}
detectChanges();
- return result;
+ return result ?? false;
};
return {
+ // @ts-ignore: fixture assigned
fixture,
detectChanges: () => detectChanges(),
navigate,
rerender,
change,
+ // @ts-ignore: fixture assigned
debugElement: typeof sut === 'string' ? fixture.debugElement : fixture.debugElement.query(By.directive(sut)),
+ // @ts-ignore: fixture assigned
container: fixture.nativeElement,
debug: (element = fixture.nativeElement, maxLength, options) =>
Array.isArray(element)
? element.forEach((e) => console.log(dtlPrettyDOM(e, maxLength, options)))
: console.log(dtlPrettyDOM(element, maxLength, options)),
+ // @ts-ignore: fixture assigned
...replaceFindWithFindAndDetectChanges(dtlGetQueriesForElement(fixture.nativeElement, queries)),
};
@@ -220,9 +225,9 @@ async function createComponent(component: Type): Promise(
+function createComponentFixture(
sut: Type | string,
- { wrapper }: Pick, 'wrapper'>,
+ wrapper: Type,
): Type {
if (typeof sut === 'string') {
TestBed.overrideTemplate(wrapper, sut);
@@ -236,13 +241,10 @@ function setComponentProperties(
{ componentProperties = {} }: Pick, 'componentProperties'>,
) {
for (const key of Object.keys(componentProperties)) {
- const descriptor: PropertyDescriptor = Object.getOwnPropertyDescriptor(
- fixture.componentInstance.constructor.prototype,
- key,
- );
+ const descriptor = Object.getOwnPropertyDescriptor((fixture.componentInstance as any).constructor.prototype, key);
let _value = componentProperties[key];
const defaultGetter = () => _value;
- const extendedSetter = (value) => {
+ const extendedSetter = (value: any) => {
_value = value;
descriptor?.set?.call(fixture.componentInstance, _value);
fixture.detectChanges();
@@ -268,21 +270,24 @@ function hasOnChangesHook(componentInstance: SutType): componentInstanc
);
}
-function getChangesObj(oldProps: Partial | null, newProps: Partial) {
+function getChangesObj>(
+ oldProps: Partial | null,
+ newProps: Partial,
+) {
const isFirstChange = oldProps === null;
return Object.keys(newProps).reduce(
(changes, key) => ({
...changes,
[key]: new SimpleChange(isFirstChange ? null : oldProps[key], newProps[key], isFirstChange),
}),
- {},
+ {} as SutType,
);
}
function addAutoDeclarations(
sut: Type | string,
{
- declarations,
+ declarations = [],
excludeComponentDeclaration,
wrapper,
}: Pick, 'declarations' | 'excludeComponentDeclaration' | 'wrapper'>,
@@ -295,7 +300,7 @@ function addAutoDeclarations(
return [...declarations, ...components()];
}
-function addAutoImports({ imports, routes }: Pick, 'imports' | 'routes'>) {
+function addAutoImports({ imports = [], routes }: Pick, 'imports' | 'routes'>) {
const animations = () => {
const animationIsDefined =
imports.indexOf(NoopAnimationsModule) > -1 || imports.indexOf(BrowserAnimationsModule) > -1;
@@ -341,19 +346,19 @@ async function waitForElementToBeRemovedWrapper(
callback: (() => T) | T,
options?: dtlWaitForOptions,
): Promise {
- let cb;
+ let cb: () => T;
if (typeof callback !== 'function') {
const elements = (Array.isArray(callback) ? callback : [callback]) as Element[];
const getRemainingElements = elements.map((element) => {
- let parent = element.parentElement;
+ let parent = element.parentElement as Element;
while (parent.parentElement) {
parent = parent.parentElement;
}
return () => (parent.contains(element) ? element : null);
});
- cb = () => getRemainingElements.map((c) => c()).filter(Boolean);
+ cb = () => getRemainingElements.map((c) => c()).find(Boolean) as unknown as T;
} else {
- cb = callback;
+ cb = callback as () => T;
}
return await dtlWaitForElementToBeRemoved(() => {
@@ -367,7 +372,7 @@ function cleanup() {
mountedFixtures.forEach(cleanupAtFixture);
}
-function cleanupAtFixture(fixture) {
+function cleanupAtFixture(fixture: ComponentFixture) {
fixture.destroy();
if (!fixture.nativeElement.getAttribute('ng-version') && fixture.nativeElement.parentNode === document.body) {
@@ -394,25 +399,21 @@ class WrapperComponent {}
/**
* Wrap findBy queries to poke the Angular change detection cycle
*/
-function replaceFindWithFindAndDetectChanges(originalQueriesForContainer: T): T {
+function replaceFindWithFindAndDetectChanges>(originalQueriesForContainer: T): T {
return Object.keys(originalQueriesForContainer).reduce((newQueries, key) => {
const getByQuery = originalQueriesForContainer[key.replace('find', 'get')];
if (key.startsWith('find') && getByQuery) {
- newQueries[key] = async (text, options, waitOptions) => {
+ newQueries[key] = async (...queryOptions: any[]) => {
+ const waitOptions = queryOptions.length === 3 ? queryOptions.pop() : undefined;
// original implementation at https://github.com/testing-library/dom-testing-library/blob/main/src/query-helpers.js
- const result = await waitForWrapper(
- detectChangesForMountedFixtures,
- () => getByQuery(text, options),
- waitOptions,
- );
- return result;
+ return await waitForWrapper(detectChangesForMountedFixtures, () => getByQuery(...queryOptions), waitOptions);
};
} else {
newQueries[key] = originalQueriesForContainer[key];
}
return newQueries;
- }, {} as T);
+ }, {} as Record) as T;
}
/**
@@ -422,7 +423,7 @@ function detectChangesForMountedFixtures() {
mountedFixtures.forEach((fixture) => {
try {
fixture.detectChanges();
- } catch (err) {
+ } catch (err: any) {
if (!err.message.startsWith('ViewDestroyedError')) {
throw err;
}
diff --git a/projects/testing-library/tests/auto-cleanup.spec.ts b/projects/testing-library/tests/auto-cleanup.spec.ts
index c69eda62..1e37f242 100644
--- a/projects/testing-library/tests/auto-cleanup.spec.ts
+++ b/projects/testing-library/tests/auto-cleanup.spec.ts
@@ -6,7 +6,7 @@ import { render } from '../src/public_api';
template: `Hello {{ name }}!`,
})
class FixtureComponent {
- @Input() name: string;
+ @Input() name = '';
}
describe('Angular auto clean up - previous components only get cleanup up on init (based on root-id)', () => {
diff --git a/projects/testing-library/tests/change.spec.ts b/projects/testing-library/tests/change.spec.ts
index 85cc3667..1ba67513 100644
--- a/projects/testing-library/tests/change.spec.ts
+++ b/projects/testing-library/tests/change.spec.ts
@@ -7,7 +7,7 @@ import { render, screen } from '../src/public_api';
})
class FixtureComponent {
@Input() firstName = 'Sarah';
- @Input() lastName;
+ @Input() lastName?: string;
}
test('changes the component with updated props', async () => {
@@ -44,7 +44,7 @@ test('changes the component with updated props while keeping other props untouch
})
class FixtureWithNgOnChangesComponent implements OnChanges {
@Input() name = 'Sarah';
- @Input() nameChanged: (name: string, isFirstChange: boolean) => void;
+ @Input() nameChanged?: (name: string, isFirstChange: boolean) => void;
ngOnChanges(changes: SimpleChanges) {
if (changes.name && this.nameChanged) {
@@ -72,7 +72,7 @@ test('will call ngOnChanges on change', async () => {
template: ` Number
`,
})
class FixtureWithOnPushComponent {
- @Input() activeField: string;
+ @Input() activeField = '';
}
test('update properties on change', async () => {
diff --git a/projects/testing-library/tests/config.spec.ts b/projects/testing-library/tests/config.spec.ts
index ccd004f5..bb8c61fc 100644
--- a/projects/testing-library/tests/config.spec.ts
+++ b/projects/testing-library/tests/config.spec.ts
@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { TestBed } from '@angular/core/testing';
-import { render, configure } from '../src/public_api';
+import { render, configure, Config } from '../src/public_api';
import { ReactiveFormsModule, FormBuilder } from '@angular/forms';
@Component({
@@ -22,12 +22,12 @@ class FormsComponent {
constructor(private formBuilder: FormBuilder) {}
}
-let originalConfig;
+let originalConfig: Config;
beforeEach(() => {
// Grab the existing configuration so we can restore
// it at the end of the test
configure((existingConfig) => {
- originalConfig = existingConfig;
+ originalConfig = existingConfig as Config;
// Don't change the existing config
return {};
});
diff --git a/projects/testing-library/tests/integration.spec.ts b/projects/testing-library/tests/integration.spec.ts
index afd56698..112177e1 100644
--- a/projects/testing-library/tests/integration.spec.ts
+++ b/projects/testing-library/tests/integration.spec.ts
@@ -36,7 +36,9 @@ class EntitiesComponent {
query = new BehaviorSubject('');
readonly entities = this.query.pipe(
debounceTime(DEBOUNCE_TIME),
- switchMap((q) => this.entitiesService.fetchAll().pipe(map((ent) => ent.filter((e) => e.name.includes(q))))),
+ switchMap((q) =>
+ this.entitiesService.fetchAll().pipe(map((ent: any) => ent.filter((e: any) => e.name.includes(q)))),
+ ),
startWith(entities),
);
@@ -65,7 +67,7 @@ class EntitiesComponent {
`,
})
class TableComponent {
- @Input() entities: any[];
+ @Input() entities: any[] = [];
@Output() edit = new EventEmitter();
}
diff --git a/projects/testing-library/tests/issues/issue-188.spec.ts b/projects/testing-library/tests/issues/issue-188.spec.ts
index 8077358a..b150dacc 100644
--- a/projects/testing-library/tests/issues/issue-188.spec.ts
+++ b/projects/testing-library/tests/issues/issue-188.spec.ts
@@ -6,9 +6,9 @@ import { render, screen } from '../../src/public_api';
template: `Hello {{ formattedName }}
`,
})
class BugOnChangeComponent implements OnChanges {
- @Input() name: string;
+ @Input() name?: string;
- formattedName: string;
+ formattedName?: string;
ngOnChanges(changes: SimpleChanges) {
if (changes.name) {
diff --git a/projects/testing-library/tests/rerender.spec.ts b/projects/testing-library/tests/rerender.spec.ts
index 443560a2..0edf69ea 100644
--- a/projects/testing-library/tests/rerender.spec.ts
+++ b/projects/testing-library/tests/rerender.spec.ts
@@ -7,7 +7,7 @@ import { render, screen } from '../src/public_api';
})
class FixtureComponent {
@Input() firstName = 'Sarah';
- @Input() lastName;
+ @Input() lastName?: string;
}
test('rerenders the component with updated props', async () => {
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 0ad01d03..59f62014 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -13,9 +13,12 @@
"sourceMap": true,
"target": "es2015",
"typeRoots": ["node_modules/@types"],
- "forceConsistentCasingInFileNames": true,
- "noImplicitReturns": true,
+ "strict": true,
"noFallthroughCasesInSwitch": true,
+ "noImplicitReturns": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "forceConsistentCasingInFileNames": true,
"paths": {
"@testing-library/angular": ["projects/testing-library"],
"@testing-library/angular/jest-utils": ["projects/jest-utils"]
From 20ae40dd58ddf5ffa614311789352e1e3ed03bd3 Mon Sep 17 00:00:00 2001
From: mleimer
Date: Wed, 5 Jan 2022 20:46:11 +0100
Subject: [PATCH 3/9] docs: add example that presets form values (#276)
---
.../examples/04-forms-with-material.spec.ts | 31 ++++++++++++++++++-
.../app/examples/04-forms-with-material.ts | 10 +++++-
2 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/apps/example-app/src/app/examples/04-forms-with-material.spec.ts b/apps/example-app/src/app/examples/04-forms-with-material.spec.ts
index ee4209b9..06f14ea8 100644
--- a/apps/example-app/src/app/examples/04-forms-with-material.spec.ts
+++ b/apps/example-app/src/app/examples/04-forms-with-material.spec.ts
@@ -4,6 +4,7 @@ import userEvent from '@testing-library/user-event';
import { MaterialModule } from '../material.module';
import { MaterialFormsComponent } from './04-forms-with-material';
+
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 () => {
const { fixture } = await render(MaterialFormsComponent, {
imports: [MaterialModule],
@@ -37,12 +38,40 @@ test('is possible to fill in a form and verify error messages (with the help of
expect(nameControl).toHaveValue('Tim');
expect(scoreControl).toHaveValue(7);
+ expect(colorControl).toHaveTextContent('Green');
const form = screen.getByRole('form');
expect(form).toHaveFormValues({
name: 'Tim',
score: 7,
});
-
expect((fixture.componentInstance as MaterialFormsComponent).form?.get('color')?.value).toBe('G');
});
+
+test('set and show pre-set form values', async () => {
+ const { fixture, detectChanges } = await render(MaterialFormsComponent, {
+ imports: [MaterialModule],
+ });
+
+ fixture.componentInstance.form.setValue({
+ name: 'Max',
+ score: 4,
+ color: 'B'
+ })
+ detectChanges();
+
+ const nameControl = screen.getByLabelText(/name/i);
+ const scoreControl = screen.getByRole('spinbutton', { name: /score/i });
+ const colorControl = screen.getByRole('combobox', { name: /color/i });
+
+ expect(nameControl).toHaveValue('Max');
+ expect(scoreControl).toHaveValue(4);
+ expect(colorControl).toHaveTextContent('Blue');
+
+ const form = screen.getByRole('form');
+ expect(form).toHaveFormValues({
+ name: 'Max',
+ score: 4,
+ });
+ expect((fixture.componentInstance as MaterialFormsComponent).form?.get('color')?.value).toBe('B');
+});
diff --git a/apps/example-app/src/app/examples/04-forms-with-material.ts b/apps/example-app/src/app/examples/04-forms-with-material.ts
index a672380c..f27f4f1e 100644
--- a/apps/example-app/src/app/examples/04-forms-with-material.ts
+++ b/apps/example-app/src/app/examples/04-forms-with-material.ts
@@ -24,6 +24,9 @@ import { FormBuilder, Validators } from '@angular/forms';
+
+ {{ colorControlDisplayValue }}
+
---
{{ color.value }}
@@ -60,11 +63,16 @@ export class MaterialFormsComponent {
form = this.formBuilder.group({
name: ['', Validators.required],
score: [0, [Validators.min(1), Validators.max(10)]],
- color: ['', Validators.required],
+ color: [null, Validators.required],
});
constructor(private formBuilder: FormBuilder) {}
+ get colorControlDisplayValue(): string | undefined {
+ const selectedId = this.form.get('color')?.value;
+ return this.colors.filter(color => color.id === selectedId)[0]?.value;
+ }
+
get formErrors() {
return Object.keys(this.form.controls)
.map((formKey) => {
From 11105d0ee8bcb2b7bcb186143158734ed8b7cff0 Mon Sep 17 00:00:00 2001
From: Arjen
Date: Fri, 7 Jan 2022 22:17:39 +0100
Subject: [PATCH 4/9] chore: improve dependencies and lint (#277)
---
.husky/_/husky.sh | 7 +-
angular.json | 297 +-----------------
.../src/app/examples/03-forms.spec.ts | 2 +-
.../examples/04-forms-with-material.spec.ts | 7 +-
.../src/app/examples/08-directive.spec.ts | 18 +-
.../src/app/examples/09-router.spec.ts | 16 +-
.../app/examples/15-dialog.component.spec.ts | 16 +-
.../src/app/issues/issue-106.spec.ts | 6 +-
.../src/app/issues/issue-254.spec.ts | 11 +-
apps/example-app/tsconfig.app.json | 3 +-
package.json | 90 +++---
projects/jest-utils/tsconfig.json | 4 +-
projects/jest-utils/tsconfig.lib.json | 5 +-
projects/jest-utils/tsconfig.lib.prod.json | 9 +
projects/testing-library/package.json | 6 +-
projects/testing-library/project.json | 6 +-
.../src/lib/testing-library.ts | 2 +-
projects/testing-library/tsconfig.json | 4 +-
projects/testing-library/tsconfig.lib.json | 5 +-
.../testing-library/tsconfig.lib.prod.json | 9 +
tsconfig.base.json | 4 +-
workspace.json | 9 -
22 files changed, 136 insertions(+), 400 deletions(-)
create mode 100644 projects/jest-utils/tsconfig.lib.prod.json
create mode 100644 projects/testing-library/tsconfig.lib.prod.json
delete mode 100644 workspace.json
diff --git a/.husky/_/husky.sh b/.husky/_/husky.sh
index ca2720e0..6809ccca 100644
--- a/.husky/_/husky.sh
+++ b/.husky/_/husky.sh
@@ -1,7 +1,9 @@
#!/bin/sh
if [ -z "$husky_skip_init" ]; then
debug () {
- [ "$HUSKY_DEBUG" = "1" ] && echo "husky (debug) - $1"
+ if [ "$HUSKY_DEBUG" = "1" ]; then
+ echo "husky (debug) - $1"
+ fi
}
readonly hook_name="$(basename "$0")"
@@ -23,8 +25,7 @@ if [ -z "$husky_skip_init" ]; then
if [ $exitCode != 0 ]; then
echo "husky - $hook_name hook exited with code $exitCode (error)"
- exit $exitCode
fi
- exit 0
+ exit $exitCode
fi
diff --git a/angular.json b/angular.json
index 50afdec9..dfd6bcf1 100644
--- a/angular.json
+++ b/angular.json
@@ -1,296 +1,9 @@
{
- "version": 1,
- "cli": {
- "analytics": false
- },
- "defaultProject": "example-app",
+ "version": 2,
"projects": {
- "example-app": {
- "projectType": "application",
- "root": "apps/example-app",
- "sourceRoot": "apps/example-app/src",
- "prefix": "app",
- "schematics": {},
- "architect": {
- "build": {
- "builder": "@angular-devkit/build-angular:browser",
- "options": {
- "outputPath": "dist/apps/example-app",
- "index": "apps/example-app/src/index.html",
- "main": "apps/example-app/src/main.ts",
- "polyfills": "apps/example-app/src/polyfills.ts",
- "tsConfig": "apps/example-app/tsconfig.app.json",
- "assets": ["apps/example-app/src/favicon.ico", "apps/example-app/src/assets"],
- "styles": ["apps/example-app/src/styles.css"],
- "scripts": [],
- "vendorChunk": true,
- "extractLicenses": false,
- "buildOptimizer": false,
- "sourceMap": true,
- "optimization": false,
- "namedChunks": true
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "anyComponentStyle",
- "maximumWarning": "6kb"
- }
- ],
- "fileReplacements": [
- {
- "replace": "apps/example-app/src/environments/environment.ts",
- "with": "apps/example-app/src/environments/environment.prod.ts"
- }
- ],
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "namedChunks": false,
- "extractLicenses": true,
- "vendorChunk": false,
- "buildOptimizer": true
- }
- },
- "outputs": ["{options.outputPath}"]
- },
- "serve": {
- "builder": "@angular-devkit/build-angular:dev-server",
- "options": {
- "browserTarget": "example-app:build"
- },
- "configurations": {
- "production": {
- "browserTarget": "example-app:build:production"
- }
- }
- },
- "extract-i18n": {
- "builder": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "browserTarget": "example-app:build"
- }
- },
- "lint": {
- "builder": "@nrwl/linter:eslint",
- "options": {
- "lintFilePatterns": [
- "apps/example-app/**/*.ts",
- "apps/example-app/**/*.html",
- "apps/example-app/src/**/*.html",
- "apps/example-app/src/**/*.html",
- "apps/example-app/src/**/*.html"
- ]
- },
- "outputs": ["{options.outputFile}"]
- },
- "test": {
- "builder": "@nrwl/jest:jest",
- "options": {
- "jestConfig": "apps/example-app/jest.config.js"
- },
- "outputs": ["coverage/"]
- }
- }
- },
- "example-app-karma": {
- "projectType": "application",
- "root": "apps/example-app-karma",
- "sourceRoot": "apps/example-app-karma/src",
- "prefix": "app",
- "schematics": {},
- "architect": {
- "build": {
- "builder": "@angular-devkit/build-angular:browser",
- "options": {
- "outputPath": "dist/apps/example-app-karma",
- "index": "apps/example-app-karma/src/index.html",
- "main": "apps/example-app-karma/src/main.ts",
- "polyfills": "apps/example-app-karma/src/polyfills.ts",
- "tsConfig": "apps/example-app-karma/tsconfig.app.json",
- "assets": ["apps/example-app-karma/src/favicon.ico", "apps/example-app-karma/src/assets"],
- "styles": [],
- "scripts": [],
- "vendorChunk": true,
- "extractLicenses": false,
- "buildOptimizer": false,
- "sourceMap": true,
- "optimization": false,
- "namedChunks": true
- },
- "configurations": {
- "production": {
- "budgets": [
- {
- "type": "anyComponentStyle",
- "maximumWarning": "6kb"
- }
- ],
- "fileReplacements": [
- {
- "replace": "apps/example-app-karma/src/environments/environment.ts",
- "with": "apps/example-app-karma/src/environments/environment.prod.ts"
- }
- ],
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "namedChunks": false,
- "extractLicenses": true,
- "vendorChunk": false,
- "buildOptimizer": true
- }
- },
- "outputs": ["{options.outputPath}"]
- },
- "serve": {
- "builder": "@angular-devkit/build-angular:dev-server",
- "options": {
- "browserTarget": "example-app-karma:build"
- },
- "configurations": {
- "production": {
- "browserTarget": "example-app-karma:build:production"
- }
- }
- },
- "lint": {
- "builder": "@nrwl/linter:eslint",
- "options": {
- "lintFilePatterns": [
- "apps/example-app-karma/**/*.ts",
- "apps/example-app-karma/**/*.html",
- "apps/example-app-karma/src/**/*.html",
- "apps/example-app-karma/src/**/*.html",
- "apps/example-app-karma/src/**/*.html"
- ]
- },
- "outputs": ["{options.outputFile}"]
- },
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "apps/example-app-karma/src/test.ts",
- "tsConfig": "apps/example-app-karma/tsconfig.spec.json",
- "polyfills": "apps/example-app-karma/src/polyfills.ts",
- "karmaConfig": "apps/example-app-karma/karma.conf.js",
- "styles": [],
- "scripts": [],
- "assets": []
- }
- }
- }
- },
- "jest-utils": {
- "root": "projects/jest-utils",
- "sourceRoot": "projects/jest-utils/src",
- "projectType": "library",
- "prefix": "lib",
- "architect": {
- "build-package": {
- "builder": "@angular-devkit/build-angular:ng-packagr",
- "options": {
- "tsConfig": "projects/jest-utils/tsconfig.lib.json",
- "project": "projects/jest-utils/ng-package.json"
- },
- "configurations": {
- "production": {
- "project": "projects/jest-utils/ng-package.json",
- "tsConfig": "projects/jest-utils/tsconfig.lib.json"
- }
- }
- },
- "lint": {
- "builder": "@nrwl/linter:eslint",
- "options": {
- "lintFilePatterns": [
- "projects/jest-utils/**/*.ts",
- "projects/jest-utils/**/*.html",
- "projects/jest-utils/src/**/*.html",
- "projects/jest-utils/src/**/*.html",
- "projects/jest-utils/src/**/*.html"
- ]
- },
- "outputs": ["{options.outputFile}"]
- },
- "build": {
- "builder": "@nrwl/workspace:run-commands",
- "options": {
- "parallel": false,
- "commands": [
- {
- "command": "ng run jest-utils:build-package"
- }
- ]
- }
- },
- "test": {
- "builder": "@nrwl/jest:jest",
- "options": {
- "jestConfig": "projects/jest-utils/jest.config.js"
- },
- "outputs": ["coverage/projects/jest-utils"]
- }
- }
- },
- "testing-library": {
- "root": "projects/testing-library",
- "sourceRoot": "projects/testing-library/src",
- "projectType": "library",
- "prefix": "lib",
- "architect": {
- "build-package": {
- "builder": "@angular-devkit/build-angular:ng-packagr",
- "options": {
- "tsConfig": "projects/testing-library/tsconfig.lib.json",
- "project": "projects/testing-library/ng-package.json"
- },
- "configurations": {
- "production": {
- "project": "projects/testing-library/ng-package.json",
- "tsConfig": "projects/testing-library/tsconfig.lib.json"
- }
- }
- },
- "lint": {
- "builder": "@nrwl/linter:eslint",
- "options": {
- "lintFilePatterns": [
- "projects/testing-library/**/*.ts",
- "projects/testing-library/**/*.html",
- "projects/testing-library/src/**/*.html",
- "projects/testing-library/src/**/*.html",
- "projects/testing-library/src/**/*.html"
- ]
- },
- "outputs": ["{options.outputFile}"]
- },
- "build": {
- "builder": "@nrwl/workspace:run-commands",
- "options": {
- "parallel": false,
- "commands": [
- {
- "command": "ng run testing-library:build-package"
- },
- {
- "command": "npm run build:schematics"
- },
- {
- "command": "cpy ./README.md ./dist/@testing-library/angular"
- }
- ]
- }
- },
- "test": {
- "builder": "@nrwl/jest:jest",
- "options": {
- "jestConfig": "projects/testing-library/jest.config.js"
- },
- "outputs": ["coverage/projects/testing-library"]
- }
- }
- }
+ "example-app": "apps/example-app",
+ "example-app-karma": "apps/example-app-karma",
+ "jest-utils": "projects/jest-utils",
+ "testing-library": "projects/testing-library"
}
}
diff --git a/apps/example-app/src/app/examples/03-forms.spec.ts b/apps/example-app/src/app/examples/03-forms.spec.ts
index 6be38a45..2a53a5f0 100644
--- a/apps/example-app/src/app/examples/03-forms.spec.ts
+++ b/apps/example-app/src/app/examples/03-forms.spec.ts
@@ -23,7 +23,7 @@ test('is possible to fill in a form and verify error messages (with the help of
userEvent.selectOptions(colorControl, 'G');
expect(screen.queryByText('name is required')).not.toBeInTheDocument();
- expect(screen.queryByText('score must be lesser than 10')).toBeInTheDocument();
+ expect(screen.getByText('score must be lesser than 10')).toBeInTheDocument();
expect(screen.queryByText('color is required')).not.toBeInTheDocument();
expect(scoreControl).toBeInvalid();
diff --git a/apps/example-app/src/app/examples/04-forms-with-material.spec.ts b/apps/example-app/src/app/examples/04-forms-with-material.spec.ts
index 06f14ea8..6d7e1e18 100644
--- a/apps/example-app/src/app/examples/04-forms-with-material.spec.ts
+++ b/apps/example-app/src/app/examples/04-forms-with-material.spec.ts
@@ -4,7 +4,6 @@ import userEvent from '@testing-library/user-event';
import { MaterialModule } from '../material.module';
import { MaterialFormsComponent } from './04-forms-with-material';
-
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 () => {
const { fixture } = await render(MaterialFormsComponent, {
imports: [MaterialModule],
@@ -26,7 +25,7 @@ test('is possible to fill in a form and verify error messages (with the help of
userEvent.click(screen.getByText(/green/i));
expect(screen.queryByText('name is required')).not.toBeInTheDocument();
- expect(screen.queryByText('score must be lesser than 10')).toBeInTheDocument();
+ expect(screen.getByText('score must be lesser than 10')).toBeInTheDocument();
expect(screen.queryByText('color is required')).not.toBeInTheDocument();
expect(scoreControl).toBeInvalid();
@@ -56,8 +55,8 @@ test('set and show pre-set form values', async () => {
fixture.componentInstance.form.setValue({
name: 'Max',
score: 4,
- color: 'B'
- })
+ color: 'B',
+ });
detectChanges();
const nameControl = screen.getByLabelText(/name/i);
diff --git a/apps/example-app/src/app/examples/08-directive.spec.ts b/apps/example-app/src/app/examples/08-directive.spec.ts
index ea3332b4..efd2a5b9 100644
--- a/apps/example-app/src/app/examples/08-directive.spec.ts
+++ b/apps/example-app/src/app/examples/08-directive.spec.ts
@@ -10,14 +10,14 @@ test('it is possible to test directives', async () => {
const directive = screen.getByTestId('dir');
expect(screen.queryByText('I am visible now...')).not.toBeInTheDocument();
- expect(screen.queryByText('SPOILER')).toBeInTheDocument();
+ expect(screen.getByText('SPOILER')).toBeInTheDocument();
fireEvent.mouseOver(directive);
expect(screen.queryByText('SPOILER')).not.toBeInTheDocument();
- expect(screen.queryByText('I am visible now...')).toBeInTheDocument();
+ expect(screen.getByText('I am visible now...')).toBeInTheDocument();
fireEvent.mouseLeave(directive);
- expect(screen.queryByText('SPOILER')).toBeInTheDocument();
+ expect(screen.getByText('SPOILER')).toBeInTheDocument();
expect(screen.queryByText('I am visible now...')).not.toBeInTheDocument();
});
@@ -34,14 +34,14 @@ test('it is possible to test directives with props', async () => {
});
expect(screen.queryByText(visible)).not.toBeInTheDocument();
- expect(screen.queryByText(hidden)).toBeInTheDocument();
+ expect(screen.getByText(hidden)).toBeInTheDocument();
fireEvent.mouseOver(screen.getByText(hidden));
expect(screen.queryByText(hidden)).not.toBeInTheDocument();
- expect(screen.queryByText(visible)).toBeInTheDocument();
+ expect(screen.getByText(visible)).toBeInTheDocument();
fireEvent.mouseLeave(screen.getByText(visible));
- expect(screen.queryByText(hidden)).toBeInTheDocument();
+ expect(screen.getByText(hidden)).toBeInTheDocument();
expect(screen.queryByText(visible)).not.toBeInTheDocument();
});
@@ -54,13 +54,13 @@ test('it is possible to test directives with props in template', async () => {
});
expect(screen.queryByText(visible)).not.toBeInTheDocument();
- expect(screen.queryByText(hidden)).toBeInTheDocument();
+ expect(screen.getByText(hidden)).toBeInTheDocument();
fireEvent.mouseOver(screen.getByText(hidden));
expect(screen.queryByText(hidden)).not.toBeInTheDocument();
- expect(screen.queryByText(visible)).toBeInTheDocument();
+ expect(screen.getByText(visible)).toBeInTheDocument();
fireEvent.mouseLeave(screen.getByText(visible));
- expect(screen.queryByText(hidden)).toBeInTheDocument();
+ expect(screen.getByText(hidden)).toBeInTheDocument();
expect(screen.queryByText(visible)).not.toBeInTheDocument();
});
diff --git a/apps/example-app/src/app/examples/09-router.spec.ts b/apps/example-app/src/app/examples/09-router.spec.ts
index cb6743fc..16f037fc 100644
--- a/apps/example-app/src/app/examples/09-router.spec.ts
+++ b/apps/example-app/src/app/examples/09-router.spec.ts
@@ -25,19 +25,19 @@ test('it can navigate to routes', async () => {
expect(screen.queryByText(/Detail one/i)).not.toBeInTheDocument();
await navigate(screen.getByRole('link', { name: /load one/i }));
- expect(screen.queryByRole('heading', { name: /Detail one/i })).toBeInTheDocument();
+ expect(screen.getByRole('heading', { name: /Detail one/i })).toBeInTheDocument();
await navigate(screen.getByRole('link', { name: /load three/i }));
expect(screen.queryByRole('heading', { name: /Detail one/i })).not.toBeInTheDocument();
- expect(screen.queryByRole('heading', { name: /Detail three/i })).toBeInTheDocument();
+ expect(screen.getByRole('heading', { name: /Detail three/i })).toBeInTheDocument();
await navigate(screen.getByRole('link', { name: /back to parent/i }));
expect(screen.queryByRole('heading', { name: /Detail three/i })).not.toBeInTheDocument();
await navigate(screen.getByRole('link', { name: /load two/i }));
- expect(screen.queryByRole('heading', { name: /Detail two/i })).toBeInTheDocument();
+ expect(screen.getByRole('heading', { name: /Detail two/i })).toBeInTheDocument();
await navigate(screen.getByRole('link', { name: /hidden x/i }));
- expect(screen.queryByText(/You found the treasure!/i)).toBeInTheDocument();
+ expect(screen.getByText(/You found the treasure!/i)).toBeInTheDocument();
});
test('it can navigate to routes with a base path', async () => {
@@ -64,20 +64,20 @@ test('it can navigate to routes with a base path', async () => {
expect(screen.queryByRole('heading', { name: /Detail one/i })).not.toBeInTheDocument();
await navigate(screen.getByRole('link', { name: /load one/i }), basePath);
- expect(screen.queryByRole('heading', { name: /Detail one/i })).toBeInTheDocument();
+ expect(screen.getByRole('heading', { name: /Detail one/i })).toBeInTheDocument();
await navigate(screen.getByRole('link', { name: /load three/i }), basePath);
expect(screen.queryByRole('heading', { name: /Detail one/i })).not.toBeInTheDocument();
- expect(screen.queryByRole('heading', { name: /Detail three/i })).toBeInTheDocument();
+ expect(screen.getByRole('heading', { name: /Detail three/i })).toBeInTheDocument();
await navigate(screen.getByRole('link', { name: /back to parent/i }));
expect(screen.queryByRole('heading', { name: /Detail three/i })).not.toBeInTheDocument();
// It's possible to just use strings
await navigate('base/detail/two?text=Hello&subtext=World');
- expect(screen.queryByRole('heading', { name: /Detail two/i })).toBeInTheDocument();
+ expect(screen.getByRole('heading', { name: /Detail two/i })).toBeInTheDocument();
expect(screen.getByText(/Hello World/i)).toBeInTheDocument();
await navigate('/hidden-detail', basePath);
- expect(screen.queryByText(/You found the treasure!/i)).toBeInTheDocument();
+ expect(screen.getByText(/You found the treasure!/i)).toBeInTheDocument();
});
diff --git a/apps/example-app/src/app/examples/15-dialog.component.spec.ts b/apps/example-app/src/app/examples/15-dialog.component.spec.ts
index 8a0ccd88..31cf2fba 100644
--- a/apps/example-app/src/app/examples/15-dialog.component.spec.ts
+++ b/apps/example-app/src/app/examples/15-dialog.component.spec.ts
@@ -32,15 +32,17 @@ test('closes the dialog via the backdrop', async () => {
const openDialogButton = await screen.findByRole('button', { name: /open dialog/i });
userEvent.click(openDialogButton);
- await screen.findByRole('dialog');
- await screen.findByRole('heading', { name: /dialog title/i });
+ const dialogControl = await screen.findByRole('dialog');
+ expect(dialogControl).toBeInTheDocument();
+ const dialogTitleControl = await screen.findByRole('heading', { name: /dialog title/i });
+ expect(dialogTitleControl).toBeInTheDocument();
// using fireEvent because of:
// unable to click element as it has or inherits pointer-events set to "none"
// eslint-disable-next-line testing-library/no-node-access, @typescript-eslint/no-non-null-assertion
fireEvent.click(document.querySelector('.cdk-overlay-backdrop')!);
- await waitForElementToBeRemoved(() => screen.getByRole('dialog'));
+ await waitForElementToBeRemoved(() => screen.queryByRole('dialog'));
const dialogTitle = screen.queryByRole('heading', { name: /dialog title/i });
expect(dialogTitle).not.toBeInTheDocument();
@@ -54,13 +56,15 @@ test('opens and closes the dialog with buttons', async () => {
const openDialogButton = await screen.findByRole('button', { name: /open dialog/i });
userEvent.click(openDialogButton);
- await screen.findByRole('dialog');
- await screen.findByRole('heading', { name: /dialog title/i });
+ const dialogControl = await screen.findByRole('dialog');
+ expect(dialogControl).toBeInTheDocument();
+ const dialogTitleControl = await screen.findByRole('heading', { name: /dialog title/i });
+ expect(dialogTitleControl).toBeInTheDocument();
const cancelButton = await screen.findByRole('button', { name: /cancel/i });
userEvent.click(cancelButton);
- await waitForElementToBeRemoved(() => screen.getByRole('dialog'));
+ await waitForElementToBeRemoved(() => screen.queryByRole('dialog'));
const dialogTitle = screen.queryByRole('heading', { name: /dialog title/i });
expect(dialogTitle).not.toBeInTheDocument();
diff --git a/apps/example-app/src/app/issues/issue-106.spec.ts b/apps/example-app/src/app/issues/issue-106.spec.ts
index b1f6cc2c..56097a83 100644
--- a/apps/example-app/src/app/issues/issue-106.spec.ts
+++ b/apps/example-app/src/app/issues/issue-106.spec.ts
@@ -1,6 +1,7 @@
import { Component } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
-import { render, screen, fireEvent, waitFor } from '@testing-library/angular';
+import { render, screen, fireEvent } from '@testing-library/angular';
+import { waitFor } from '@testing-library/dom';
@Component({
template: `
@@ -27,6 +28,9 @@ test('https://github.com/testing-library/angular-testing-library/issues/106', as
// await waitFor(() => expect(hiddenText).not.toBeNull());
// succeeds
+ /// Next line is disabled, because we wish to test the behavior of the library and test the bug/issue #106
+ /// @see https://github.com/testing-library/angular-testing-library/pull/277/files#r779743116
+ // eslint-disable-next-line testing-library/prefer-presence-queries, testing-library/prefer-find-by
await waitFor(() => expect(screen.queryByTestId('getme')).toBeInTheDocument());
});
diff --git a/apps/example-app/src/app/issues/issue-254.spec.ts b/apps/example-app/src/app/issues/issue-254.spec.ts
index 74e90fbb..917f35de 100644
--- a/apps/example-app/src/app/issues/issue-254.spec.ts
+++ b/apps/example-app/src/app/issues/issue-254.spec.ts
@@ -26,10 +26,10 @@ class JobsService {
`,
})
class CareerOportunitiesComponent implements OnInit {
- dedicated?: Division;
- intermodal?: Division;
- noCdl?: Division;
- otr?: Division;
+ dedicated: Division | undefined;
+ intermodal: Division | undefined;
+ noCdl: Division | undefined;
+ otr: Division | undefined;
constructor(private jobsService: JobsService) {}
@@ -73,5 +73,6 @@ test('Render Component', async () => {
},
],
});
- await screen.findAllByRole('listitem');
+ const listItemControl = await screen.findAllByRole('listitem');
+ expect(listItemControl).toHaveLength(3);
});
diff --git a/apps/example-app/tsconfig.app.json b/apps/example-app/tsconfig.app.json
index 4de7101b..a009fad9 100644
--- a/apps/example-app/tsconfig.app.json
+++ b/apps/example-app/tsconfig.app.json
@@ -3,7 +3,8 @@
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": [],
- "allowJs": true
+ "allowJs": true,
+ "target": "ES2017"
},
"files": ["src/main.ts", "src/polyfills.ts"],
"include": ["src/**/*.d.ts"],
diff --git a/package.json b/package.json
index 3c7c74ec..7b514db6 100644
--- a/package.json
+++ b/package.json
@@ -28,75 +28,75 @@
"prepare": "husky install"
},
"dependencies": {
- "@angular/animations": "13.0.2",
- "@angular/cdk": "13.0.2",
- "@angular/common": "13.0.2",
- "@angular/compiler": "13.0.2",
- "@angular/core": "13.0.2",
- "@angular/forms": "13.0.2",
- "@angular/material": "13.0.2",
- "@angular/platform-browser": "13.0.2",
- "@angular/platform-browser-dynamic": "13.0.2",
- "@angular/router": "13.0.2",
- "@ngrx/store": "13.0.1",
- "@nrwl/angular": "13.2.2",
- "@nrwl/nx-cloud": "12.5.4",
+ "@angular/animations": "13.1.1",
+ "@angular/cdk": "13.1.1",
+ "@angular/common": "13.1.1",
+ "@angular/compiler": "13.1.1",
+ "@angular/core": "13.1.1",
+ "@angular/material": "13.1.1",
+ "@angular/platform-browser": "13.1.1",
+ "@angular/platform-browser-dynamic": "13.1.1",
+ "@angular/router": "13.1.1",
+ "@ngrx/store": "13.0.2",
+ "@nrwl/angular": "13.4.3",
+ "@nrwl/nx-cloud": "13.0.2",
"@testing-library/dom": "^8.11.1",
- "@testing-library/user-event": "^13.5.0",
- "rxjs": "^7.4.0",
+ "rxjs": "^7.5.1",
"tslib": "~2.3.1",
"zone.js": "~0.11.4"
},
"devDependencies": {
- "@angular-devkit/build-angular": "13.0.3",
- "@angular-eslint/eslint-plugin": "12.6.1",
- "@angular-eslint/eslint-plugin-template": "12.6.1",
- "@angular-eslint/template-parser": "12.6.1",
- "@angular/cli": "13.0.3",
- "@angular/compiler-cli": "13.0.2",
- "@angular/language-service": "13.0.2",
- "@nrwl/cli": "13.2.2",
- "@nrwl/eslint-plugin-nx": "13.2.2",
- "@nrwl/jest": "13.2.2",
- "@nrwl/linter": "13.2.2",
- "@nrwl/node": "13.2.2",
- "@nrwl/nx-plugin": "13.2.2",
- "@nrwl/workspace": "13.2.2",
+ "@angular-devkit/build-angular": "13.1.2",
+ "@angular-eslint/eslint-plugin": "13.0.1",
+ "@angular-eslint/eslint-plugin-template": "13.0.1",
+ "@angular-eslint/template-parser": "13.0.1",
+ "@angular/cli": "13.1.2",
+ "@angular/compiler-cli": "13.1.1",
+ "@angular/forms": "13.1.1",
+ "@angular/language-service": "13.1.1",
+ "@nrwl/cli": "13.4.3",
+ "@nrwl/eslint-plugin-nx": "13.4.3",
+ "@nrwl/jest": "13.4.3",
+ "@nrwl/linter": "13.4.3",
+ "@nrwl/node": "13.4.3",
+ "@nrwl/nx-plugin": "13.4.3",
+ "@nrwl/workspace": "13.4.3",
"@testing-library/jasmine-dom": "^1.2.0",
"@testing-library/jest-dom": "^5.15.1",
+ "@testing-library/user-event": "^13.5.0",
"@types/jasmine": "^3.10.2",
- "@types/jest": "27.0.3",
+ "@types/jest": "27.4.0",
"@types/node": "14.14.37",
- "@typescript-eslint/eslint-plugin": "4.33.0",
- "@typescript-eslint/parser": "4.33.0",
+ "@typescript-eslint/eslint-plugin": "~5.3.0",
+ "@typescript-eslint/parser": "~5.3.0",
"cpy-cli": "^3.1.1",
- "eslint": "7.32.0",
+ "eslint": "~8.6.0",
"eslint-config-prettier": "8.3.0",
- "eslint-plugin-import": "2.23.4",
- "eslint-plugin-jasmine": "^4.1.2",
- "eslint-plugin-jest": "24.3.6",
- "eslint-plugin-jest-dom": "3.9.0",
- "eslint-plugin-testing-library": "4.9.0",
+ "eslint-plugin-import": "~2.25.4",
+ "eslint-plugin-jasmine": "~4.1.3",
+ "eslint-plugin-jest": "~25.3.4",
+ "eslint-plugin-jest-dom": "~4.0.1",
+ "eslint-plugin-testing-library": "~5.0.1",
"husky": "^7.0.0",
"jasmine-core": "^3.10.1",
"jasmine-spec-reporter": "^7.0.0",
- "jest": "27.3.1",
+ "jest": "27.4.7",
"jest-preset-angular": "11.0.1",
"karma": "^6.3.9",
"karma-chrome-launcher": "^3.1.0",
"karma-jasmine": "^4.0.1",
"karma-jasmine-html-reporter": "^1.7.0",
- "lint-staged": "^12.1.2",
- "ng-packagr": "~13.0.7",
- "postcss": "^8.3.11",
+ "lint-staged": "^12.1.6",
+ "ng-packagr": "13.1.2",
+ "postcss": "^8.4.5",
"postcss-import": "^14.0.2",
- "postcss-preset-env": "^7.0.1",
+ "postcss-preset-env": "^7.2.0",
"postcss-url": "^10.1.3",
"prettier": "^2.4.1",
"rimraf": "^3.0.2",
"semantic-release": "^18.0.0",
- "ts-jest": "27.0.7",
+ "ts-jest": "27.1.2",
"ts-node": "~10.4.0",
- "typescript": "4.4.4"
+ "typescript": "4.5.4"
}
}
diff --git a/projects/jest-utils/tsconfig.json b/projects/jest-utils/tsconfig.json
index fd77caf1..24663f6f 100644
--- a/projects/jest-utils/tsconfig.json
+++ b/projects/jest-utils/tsconfig.json
@@ -6,13 +6,15 @@
{
"path": "./tsconfig.lib.json"
},
+ {
+ "path": "./tsconfig.lib.prod.json"
+ },
{
"path": "./tsconfig.spec.json"
}
],
"compilerOptions": {},
"angularCompilerOptions": {
- "compilationMode": "partial",
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true,
diff --git a/projects/jest-utils/tsconfig.lib.json b/projects/jest-utils/tsconfig.lib.json
index 22fef254..0566ff84 100644
--- a/projects/jest-utils/tsconfig.lib.json
+++ b/projects/jest-utils/tsconfig.lib.json
@@ -1,11 +1,12 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
- "outDir": "../../out-tsc/lib",
+ "outDir": "../../dist/out-tsc",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": ["jest"]
},
- "exclude": ["src/test.ts", "**/*.spec.ts", "**/*.test.ts"]
+ "exclude": ["src/test.ts", "**/*.spec.ts", "**/*.test.ts"],
+ "include": ["**/*.ts"]
}
diff --git a/projects/jest-utils/tsconfig.lib.prod.json b/projects/jest-utils/tsconfig.lib.prod.json
new file mode 100644
index 00000000..2a2faa88
--- /dev/null
+++ b/projects/jest-utils/tsconfig.lib.prod.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.lib.json",
+ "compilerOptions": {
+ "declarationMap": false
+ },
+ "angularCompilerOptions": {
+ "compilationMode": "partial"
+ }
+}
diff --git a/projects/testing-library/package.json b/projects/testing-library/package.json
index e41389cf..7d14c654 100644
--- a/projects/testing-library/package.json
+++ b/projects/testing-library/package.json
@@ -31,13 +31,13 @@
"peerDependencies": {
"@angular/common": ">= 13.0.0",
"@angular/platform-browser": ">= 13.0.0",
- "@angular/animations": ">= 13.0.0",
"@angular/router": ">= 13.0.0",
- "@angular/core": ">= 13.0.0"
+ "@angular/core": ">= 13.0.0",
+ "rxjs": ">= 7.4.0"
},
"dependencies": {
"@testing-library/dom": "^8.0.0",
- "tslib": "^2.0.0"
+ "tslib": "^2.3.1"
},
"publishConfig": {
"access": "public"
diff --git a/projects/testing-library/project.json b/projects/testing-library/project.json
index fe6d0834..1caa86ee 100644
--- a/projects/testing-library/project.json
+++ b/projects/testing-library/project.json
@@ -23,11 +23,7 @@
"lint": {
"executor": "@nrwl/linter:eslint",
"options": {
- "lintFilePatterns": [
- "projects/testing-library/**/*.ts",
- "projects/testing-library/**/*.html",
- "projects/testing-library/src/**/*.html"
- ]
+ "lintFilePatterns": ["projects/testing-library/**/*.ts", "projects/testing-library/**/*.html"]
},
"outputs": ["{options.outputFile}"]
},
diff --git a/projects/testing-library/src/lib/testing-library.ts b/projects/testing-library/src/lib/testing-library.ts
index 1197cf8e..65877ef3 100644
--- a/projects/testing-library/src/lib/testing-library.ts
+++ b/projects/testing-library/src/lib/testing-library.ts
@@ -57,7 +57,7 @@ export async function render(
componentProperties = {},
componentProviders = [],
excludeComponentDeclaration = false,
- routes,
+ routes = [],
removeAngularAttributes = false,
defaultImports = [],
} = { ...globalConfig, ...renderOptions };
diff --git a/projects/testing-library/tsconfig.json b/projects/testing-library/tsconfig.json
index fd77caf1..24663f6f 100644
--- a/projects/testing-library/tsconfig.json
+++ b/projects/testing-library/tsconfig.json
@@ -6,13 +6,15 @@
{
"path": "./tsconfig.lib.json"
},
+ {
+ "path": "./tsconfig.lib.prod.json"
+ },
{
"path": "./tsconfig.spec.json"
}
],
"compilerOptions": {},
"angularCompilerOptions": {
- "compilationMode": "partial",
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true,
diff --git a/projects/testing-library/tsconfig.lib.json b/projects/testing-library/tsconfig.lib.json
index f7b1b9ca..7d77d4c9 100644
--- a/projects/testing-library/tsconfig.lib.json
+++ b/projects/testing-library/tsconfig.lib.json
@@ -1,11 +1,12 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
- "outDir": "../../out-tsc/lib",
+ "outDir": "../../dist/out-tsc",
"declaration": true,
"declarationMap": true,
"inlineSources": true,
"types": ["node", "jest"]
},
- "exclude": ["src/test.ts", "**/*.spec.ts", "**/*.test.ts"]
+ "exclude": ["src/test-setup.ts", "**/*.spec.ts", "**/*.test.ts"],
+ "include": ["**/*.ts"]
}
diff --git a/projects/testing-library/tsconfig.lib.prod.json b/projects/testing-library/tsconfig.lib.prod.json
new file mode 100644
index 00000000..2a2faa88
--- /dev/null
+++ b/projects/testing-library/tsconfig.lib.prod.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.lib.json",
+ "compilerOptions": {
+ "declarationMap": false
+ },
+ "angularCompilerOptions": {
+ "compilationMode": "partial"
+ }
+}
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 59f62014..1e0de6e1 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -14,11 +14,13 @@
"target": "es2015",
"typeRoots": ["node_modules/@types"],
"strict": true,
+ "exactOptionalPropertyTypes": true,
+ "forceConsistentCasingInFileNames": true,
+ "noImplicitOverride": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
- "forceConsistentCasingInFileNames": true,
"paths": {
"@testing-library/angular": ["projects/testing-library"],
"@testing-library/angular/jest-utils": ["projects/jest-utils"]
diff --git a/workspace.json b/workspace.json
deleted file mode 100644
index dfd6bcf1..00000000
--- a/workspace.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "version": 2,
- "projects": {
- "example-app": "apps/example-app",
- "example-app-karma": "apps/example-app-karma",
- "jest-utils": "projects/jest-utils",
- "testing-library": "projects/testing-library"
- }
-}
From c6b864c18606732fecea9d1d7fdc2eba2df52eff Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Thu, 10 Feb 2022 08:28:22 +0100
Subject: [PATCH 5/9] chore: update TL types (#282)
---
projects/testing-library/src/lib/models.ts | 2 +-
projects/testing-library/src/lib/testing-library.ts | 10 ++++------
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/projects/testing-library/src/lib/models.ts b/projects/testing-library/src/lib/models.ts
index 9320fb6a..7799c3ce 100644
--- a/projects/testing-library/src/lib/models.ts
+++ b/projects/testing-library/src/lib/models.ts
@@ -20,7 +20,7 @@ export interface RenderResult extend
* element: The to be printed HTML element, if not provided it will log the whole component's DOM
*/
debug: (
- element?: Element | HTMLDocument | (Element | HTMLDocument)[],
+ element?: Element | Document | (Element | Document)[],
maxLength?: number,
options?: PrettyDOMOptions,
) => void;
diff --git a/projects/testing-library/src/lib/testing-library.ts b/projects/testing-library/src/lib/testing-library.ts
index 65877ef3..b1c8c16d 100644
--- a/projects/testing-library/src/lib/testing-library.ts
+++ b/projects/testing-library/src/lib/testing-library.ts
@@ -22,10 +22,9 @@ import {
within as dtlWithin,
waitForOptions as dtlWaitForOptions,
configure as dtlConfigure,
- Queries,
- getQueriesForElement,
queries as dtlQueries,
} from '@testing-library/dom';
+import type { Queries, BoundFunctions } from '@testing-library/dom';
import { RenderComponentOptions, RenderTemplateOptions, RenderResult } from './models';
import { getConfig } from './config';
@@ -439,12 +438,11 @@ const screen = replaceFindWithFindAndDetectChanges(dtlScreen);
/**
* Re-export within with patched queries
*/
-
-const within: typeof getQueriesForElement = (
+const within = (
element: HTMLElement,
queriesToBind?: T,
-) => {
- const container = dtlWithin(element, queriesToBind);
+): BoundFunctions => {
+ const container = dtlWithin(element, queriesToBind);
return replaceFindWithFindAndDetectChanges(container);
};
From 21b119ef01e26847bb2ca6475c1ad672b43e71ac Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Thu, 10 Feb 2022 08:43:33 +0100
Subject: [PATCH 6/9] chore: add .node-version and remove husky (#281)
---
.githooks/pre-commit | 3 +++
.github/workflows/ci.yml | 5 ++++-
.husky/_/husky.sh | 31 -------------------------------
.husky/pre-commit | 4 ----
.node-version | 1 +
lint-staged.config.js | 4 ++--
package.json | 3 +--
7 files changed, 11 insertions(+), 40 deletions(-)
create mode 100644 .githooks/pre-commit
delete mode 100644 .husky/_/husky.sh
delete mode 100644 .husky/pre-commit
create mode 100644 .node-version
diff --git a/.githooks/pre-commit b/.githooks/pre-commit
new file mode 100644
index 00000000..f0f7d343
--- /dev/null
+++ b/.githooks/pre-commit
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+npm run pre-commit
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 998b0652..80741a41 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -7,6 +7,10 @@ on:
- 'beta'
pull_request: {}
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
build_test_release:
strategy:
@@ -34,4 +38,3 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
CI: true
- HUSKY: 0
diff --git a/.husky/_/husky.sh b/.husky/_/husky.sh
deleted file mode 100644
index 6809ccca..00000000
--- a/.husky/_/husky.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-if [ -z "$husky_skip_init" ]; then
- debug () {
- if [ "$HUSKY_DEBUG" = "1" ]; then
- echo "husky (debug) - $1"
- fi
- }
-
- readonly hook_name="$(basename "$0")"
- debug "starting $hook_name..."
-
- if [ "$HUSKY" = "0" ]; then
- debug "HUSKY env variable is set to 0, skipping hook"
- exit 0
- fi
-
- if [ -f ~/.huskyrc ]; then
- debug "sourcing ~/.huskyrc"
- . ~/.huskyrc
- fi
-
- export readonly husky_skip_init=1
- sh -e "$0" "$@"
- exitCode="$?"
-
- if [ $exitCode != 0 ]; then
- echo "husky - $hook_name hook exited with code $exitCode (error)"
- fi
-
- exit $exitCode
-fi
diff --git a/.husky/pre-commit b/.husky/pre-commit
deleted file mode 100644
index d0612ad3..00000000
--- a/.husky/pre-commit
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-. "$(dirname "$0")/_/husky.sh"
-
-npm run pre-commit
diff --git a/.node-version b/.node-version
new file mode 100644
index 00000000..b6a7d89c
--- /dev/null
+++ b/.node-version
@@ -0,0 +1 @@
+16
diff --git a/lint-staged.config.js b/lint-staged.config.js
index a10d3ccf..ebb35d3b 100644
--- a/lint-staged.config.js
+++ b/lint-staged.config.js
@@ -1,4 +1,4 @@
module.exports = {
- '*.{ts,js}': ['eslint --fix', 'git add'],
- '*.{json,md}': ['prettier --write', 'git add'],
+ '*.{ts,js}': ['eslint --fix'],
+ '*.{json,md}': ['prettier --write'],
};
diff --git a/package.json b/package.json
index 7b514db6..977d7a88 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,7 @@
"format:check": "nx format:check",
"pre-commit": "lint-staged",
"semantic-release": "semantic-release",
- "prepare": "husky install"
+ "prepare": "git config core.hookspath .githooks"
},
"dependencies": {
"@angular/animations": "13.1.1",
@@ -77,7 +77,6 @@
"eslint-plugin-jest": "~25.3.4",
"eslint-plugin-jest-dom": "~4.0.1",
"eslint-plugin-testing-library": "~5.0.1",
- "husky": "^7.0.0",
"jasmine-core": "^3.10.1",
"jasmine-spec-reporter": "^7.0.0",
"jest": "27.4.7",
From 8a56824befee4b35a3e8fcd3f556c8ba8eb5dc50 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Mon, 14 Feb 2022 20:24:16 +0100
Subject: [PATCH 7/9] docs: add meirka as a contributor for bug, test (#285)
---
.all-contributorsrc | 10 ++++++++++
README.md | 3 +++
2 files changed, 13 insertions(+)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 96c7a291..dbc27208 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -274,6 +274,16 @@
"doc",
"test"
]
+ },
+ {
+ "login": "meirka",
+ "name": "MeIr",
+ "avatar_url": "https://avatars.githubusercontent.com/u/750901?v=4",
+ "profile": "https://github.com/meirka",
+ "contributions": [
+ "bug",
+ "test"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/README.md b/README.md
index d750dae4..a66015c9 100644
--- a/README.md
+++ b/README.md
@@ -219,6 +219,9 @@ Thanks goes to these people ([emoji key][emojis]):
 Matan Borenkraout 🚧 |
 mleimer 📖 ⚠️ |
+
+  MeIr 🐛 ⚠️ |
+
From b34993969a697cbeb4d4f002b6805cc07bb195ae Mon Sep 17 00:00:00 2001
From: MeIr
Date: Wed, 16 Feb 2022 13:34:38 -0500
Subject: [PATCH 8/9] test: add test case for #280 (#284)
---
.../tests/issues/issue-280.spec.ts | 76 +++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 projects/testing-library/tests/issues/issue-280.spec.ts
diff --git a/projects/testing-library/tests/issues/issue-280.spec.ts b/projects/testing-library/tests/issues/issue-280.spec.ts
new file mode 100644
index 00000000..4c490741
--- /dev/null
+++ b/projects/testing-library/tests/issues/issue-280.spec.ts
@@ -0,0 +1,76 @@
+import {Component, NgModule} from '@angular/core';
+import {render, screen} from '@testing-library/angular';
+import {Router, RouterModule, Routes} from "@angular/router";
+import {RouterTestingModule} from "@angular/router/testing";
+import userEvent from "@testing-library/user-event";
+import {Location} from "@angular/common";
+import {TestBed} from "@angular/core/testing";
+
+@Component({
+ template: `Navigate
`,
+})
+class MainComponent {}
+
+@Component({
+ template: `first page
go to second`
+})
+class FirstComponent {}
+
+@Component({
+ template: `second page
`
+})
+class SecondComponent {
+ constructor(private location: Location) { }
+ goBack() {this.location.back();}
+}
+
+const routes: Routes = [
+ {path: '', redirectTo: '/first', pathMatch: 'full'},
+ {path: 'first', component: FirstComponent},
+ {path: 'second', component: SecondComponent}
+];
+
+@NgModule({
+ declarations: [FirstComponent, SecondComponent],
+ imports: [RouterModule.forRoot(routes)],
+ exports: [RouterModule]
+})
+class AppRoutingModule {}
+
+
+// test('navigate to second page and back', async () => {
+// const subject = await render(MainComponent, {imports: [AppRoutingModule, RouterTestingModule]});
+// await subject.navigate('/');
+//
+// expect(await screen.findByText('Navigate')).toBeInTheDocument();
+// expect(await screen.findByText('first page')).toBeInTheDocument();
+//
+// userEvent.click(await screen.findByText('go to second'));
+//
+// expect(await screen.findByText('second page')).toBeInTheDocument();
+// expect(await screen.findByText('navigate back')).toBeInTheDocument();
+//
+// userEvent.click(await screen.findByText('navigate back'));
+//
+// expect(await screen.findByText('first page')).toBeInTheDocument();
+// });
+
+test('navigate to second page and back', async () => {
+ const subject = await render(MainComponent, {imports: [AppRoutingModule, RouterTestingModule]});
+
+ TestBed.inject(Router).initialNavigation();
+
+ await subject.navigate('/');
+
+ expect(await screen.findByText('Navigate')).toBeInTheDocument();
+ expect(await screen.findByText('first page')).toBeInTheDocument();
+
+ userEvent.click(await screen.findByText('go to second'));
+
+ expect(await screen.findByText('second page')).toBeInTheDocument();
+ expect(await screen.findByText('navigate back')).toBeInTheDocument();
+
+ userEvent.click(await screen.findByText('navigate back'));
+
+ expect(await screen.findByText('first page')).toBeInTheDocument();
+});
From d758b945dd2516675b65fde955291fea43cad282 Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Fri, 25 Feb 2022 19:28:15 +0100
Subject: [PATCH 9/9] fix: invoke initialNavigation when a router is imported
(#286)
---
lint-staged.config.js | 2 +-
.../src/lib/testing-library.ts | 9 ++-
.../tests/issues/issue-280.spec.ts | 60 +++++++------------
3 files changed, 26 insertions(+), 45 deletions(-)
diff --git a/lint-staged.config.js b/lint-staged.config.js
index ebb35d3b..00ee30fd 100644
--- a/lint-staged.config.js
+++ b/lint-staged.config.js
@@ -1,4 +1,4 @@
module.exports = {
'*.{ts,js}': ['eslint --fix'],
- '*.{json,md}': ['prettier --write'],
+ '*.{ts,js,json,md}': ['prettier --write'],
};
diff --git a/projects/testing-library/src/lib/testing-library.ts b/projects/testing-library/src/lib/testing-library.ts
index b1c8c16d..8a6ad6a7 100644
--- a/projects/testing-library/src/lib/testing-library.ts
+++ b/projects/testing-library/src/lib/testing-library.ts
@@ -116,13 +116,12 @@ export async function render(
fixture.componentRef.injector.get(ChangeDetectorRef).detectChanges();
};
- let router = routes ? inject(Router) : null;
const zone = inject(NgZone);
- const navigate = async (elementOrPath: Element | string, basePath = ''): Promise => {
- if (!router) {
- router = inject(Router);
- }
+ const router = inject(Router);
+ router?.initialNavigation();
+
+ const navigate = async (elementOrPath: Element | string, basePath = ''): Promise => {
const href = typeof elementOrPath === 'string' ? elementOrPath : elementOrPath.getAttribute('href');
const [path, params] = (basePath + href).split('?');
const queryParams = params
diff --git a/projects/testing-library/tests/issues/issue-280.spec.ts b/projects/testing-library/tests/issues/issue-280.spec.ts
index 4c490741..19f644ef 100644
--- a/projects/testing-library/tests/issues/issue-280.spec.ts
+++ b/projects/testing-library/tests/issues/issue-280.spec.ts
@@ -1,66 +1,48 @@
-import {Component, NgModule} from '@angular/core';
-import {render, screen} from '@testing-library/angular';
-import {Router, RouterModule, Routes} from "@angular/router";
-import {RouterTestingModule} from "@angular/router/testing";
-import userEvent from "@testing-library/user-event";
-import {Location} from "@angular/common";
-import {TestBed} from "@angular/core/testing";
+import { Location } from '@angular/common';
+import { Component, NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { RouterTestingModule } from '@angular/router/testing';
+import userEvent from '@testing-library/user-event';
+import { render, screen } from '../../src/public_api';
@Component({
- template: `Navigate
`,
+ template: `Navigate
+ `,
})
class MainComponent {}
@Component({
- template: `first page
go to second`
+ template: `first page
+ go to second`,
})
class FirstComponent {}
@Component({
- template: `second page
`
+ template: `second page
+ `,
})
class SecondComponent {
- constructor(private location: Location) { }
- goBack() {this.location.back();}
+ constructor(private location: Location) {}
+ goBack() {
+ this.location.back();
+ }
}
const routes: Routes = [
- {path: '', redirectTo: '/first', pathMatch: 'full'},
- {path: 'first', component: FirstComponent},
- {path: 'second', component: SecondComponent}
+ { path: '', redirectTo: '/first', pathMatch: 'full' },
+ { path: 'first', component: FirstComponent },
+ { path: 'second', component: SecondComponent },
];
@NgModule({
declarations: [FirstComponent, SecondComponent],
imports: [RouterModule.forRoot(routes)],
- exports: [RouterModule]
+ exports: [RouterModule],
})
class AppRoutingModule {}
-
-// test('navigate to second page and back', async () => {
-// const subject = await render(MainComponent, {imports: [AppRoutingModule, RouterTestingModule]});
-// await subject.navigate('/');
-//
-// expect(await screen.findByText('Navigate')).toBeInTheDocument();
-// expect(await screen.findByText('first page')).toBeInTheDocument();
-//
-// userEvent.click(await screen.findByText('go to second'));
-//
-// expect(await screen.findByText('second page')).toBeInTheDocument();
-// expect(await screen.findByText('navigate back')).toBeInTheDocument();
-//
-// userEvent.click(await screen.findByText('navigate back'));
-//
-// expect(await screen.findByText('first page')).toBeInTheDocument();
-// });
-
test('navigate to second page and back', async () => {
- const subject = await render(MainComponent, {imports: [AppRoutingModule, RouterTestingModule]});
-
- TestBed.inject(Router).initialNavigation();
-
- await subject.navigate('/');
+ await render(MainComponent, { imports: [AppRoutingModule, RouterTestingModule] });
expect(await screen.findByText('Navigate')).toBeInTheDocument();
expect(await screen.findByText('first page')).toBeInTheDocument();