Skip to content

Commit

Permalink
fix: support Angular 19 (#503)
Browse files Browse the repository at this point in the history
timdeschryver authored Dec 3, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 4bd4ab2 commit fdcf5fa
Showing 12 changed files with 111 additions and 87 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- name: install
run: npm install
run: npm install --force
- name: build
run: npm run build -- --skip-nx-cache
- name: test
46 changes: 23 additions & 23 deletions package.json
Original file line number Diff line number Diff line change
@@ -27,35 +27,35 @@
"prepare": "git config core.hookspath .githooks"
},
"dependencies": {
"@angular/animations": "18.2.13",
"@angular/cdk": "18.2.14",
"@angular/common": "18.2.13",
"@angular/compiler": "18.2.13",
"@angular/core": "18.2.13",
"@angular/material": "18.2.14",
"@angular/platform-browser": "18.2.13",
"@angular/platform-browser-dynamic": "18.2.13",
"@angular/router": "18.2.13",
"@ngrx/store": "18.0.2",
"@angular/animations": "19.0.1",
"@angular/cdk": "19.0.1",
"@angular/common": "19.0.1",
"@angular/compiler": "19.0.1",
"@angular/core": "19.0.1",
"@angular/material": "19.0.1",
"@angular/platform-browser": "19.0.1",
"@angular/platform-browser-dynamic": "19.0.1",
"@angular/router": "19.0.1",
"@ngrx/store": "19.0.0-beta.0",
"@nx/angular": "20.1.3",
"@testing-library/dom": "^10.0.0",
"@testing-library/dom": "^10.4.0",
"rxjs": "7.8.0",
"tslib": "~2.3.1",
"zone.js": "0.14.10"
"zone.js": "^0.15.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "18.2.9",
"@angular-devkit/core": "18.2.9",
"@angular-devkit/schematics": "18.2.9",
"@angular-devkit/build-angular": "19.0.1",
"@angular-devkit/core": "19.0.1",
"@angular-devkit/schematics": "19.0.1",
"@angular-eslint/builder": "18.3.0",
"@angular-eslint/eslint-plugin": "18.0.1",
"@angular-eslint/eslint-plugin-template": "18.0.1",
"@angular-eslint/schematics": "18.3.0",
"@angular-eslint/template-parser": "18.0.1",
"@angular/cli": "~18.2.0",
"@angular/compiler-cli": "18.2.13",
"@angular/forms": "18.2.13",
"@angular/language-service": "18.2.13",
"@angular/cli": "19.0.1",
"@angular/compiler-cli": "19.0.1",
"@angular/forms": "19.0.1",
"@angular/language-service": "19.0.1",
"@nx/eslint": "20.1.3",
"@nx/eslint-plugin": "20.1.3",
"@nx/jest": "20.1.3",
@@ -68,7 +68,7 @@
"@testing-library/user-event": "^14.4.3",
"@types/jasmine": "4.3.1",
"@types/jest": "29.5.14",
"@types/node": "18.16.9",
"@types/node": "22.10.1",
"@types/testing-library__jasmine-dom": "^1.3.0",
"@typescript-eslint/eslint-plugin": "7.16.0",
"@typescript-eslint/parser": "7.16.0",
@@ -86,15 +86,15 @@
"jasmine-spec-reporter": "7.0.0",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"jest-preset-angular": "14.1.0",
"jest-preset-angular": "14.4.1",
"karma": "6.4.0",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage": "^2.2.1",
"karma-jasmine": "5.1.0",
"karma-jasmine-html-reporter": "2.0.0",
"lint-staged": "^12.1.6",
"ng-mocks": "^14.11.0",
"ng-packagr": "18.2.1",
"ng-packagr": "19.0.1",
"nx": "20.1.3",
"postcss": "^8.4.5",
"postcss-import": "14.1.0",
@@ -105,6 +105,6 @@
"semantic-release": "^18.0.0",
"ts-jest": "29.1.0",
"ts-node": "10.9.1",
"typescript": "5.5.4"
"typescript": "5.6.2"
}
}
15 changes: 11 additions & 4 deletions projects/testing-library/src/lib/testing-library.ts
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ import {
RenderComponentOptions,
RenderResult,
RenderTemplateOptions,
Config,
} from './models';

type SubscribedOutput<T> = readonly [key: keyof T, callback: (v: any) => void, subscription: OutputRefSubscription];
@@ -82,7 +83,9 @@ export async function render<SutType, WrapperType = SutType>(
configureTestBed = () => {
/* noop*/
},
} = { ...globalConfig, ...renderOptions };
} = { ...globalConfig, ...renderOptions } as RenderComponentOptions<SutType> &
RenderTemplateOptions<WrapperType> &
Config;

dtlConfigure({
eventWrapper: (cb) => {
@@ -228,7 +231,7 @@ export async function render<SutType, WrapperType = SutType>(
return createdFixture;
};

const fixture = await renderFixture(componentProperties, allInputs, componentOutputs, on);
const fixture = await renderFixture(componentProperties, allInputs as any, componentOutputs, on);

if (deferBlockStates) {
if (Array.isArray(deferBlockStates)) {
@@ -494,12 +497,16 @@ function addAutoDeclarations<SutType>(
wrapper,
}: Pick<RenderTemplateOptions<any>, 'declarations' | 'excludeComponentDeclaration' | 'wrapper'>,
) {
const nonStandaloneDeclarations = declarations?.filter((d) => !isStandalone(d));
if (typeof sut === 'string') {
return [...declarations, wrapper];
if (wrapper && isStandalone(wrapper)) {
return nonStandaloneDeclarations;
}
return [...nonStandaloneDeclarations, wrapper];
}

const components = () => (excludeComponentDeclaration || isStandalone(sut) ? [] : [sut]);
return [...declarations, ...components()];
return [...nonStandaloneDeclarations, ...components()];
}

function addAutoImports<SutType>(
4 changes: 3 additions & 1 deletion projects/testing-library/test-setup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
import '@testing-library/jest-dom';
import { TextEncoder, TextDecoder } from 'util';

setupZoneTestEnv();

// eslint-disable-next-line @typescript-eslint/naming-convention
Object.assign(global, { TextDecoder, TextEncoder });
1 change: 1 addition & 0 deletions projects/testing-library/tests/config.spec.ts
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ import { ReactiveFormsModule, FormBuilder } from '@angular/forms';
</div>
</form>
`,
standalone: false,
})
class FormsComponent {
form = this.formBuilder.group({
2 changes: 2 additions & 0 deletions projects/testing-library/tests/find-by.spec.ts
Original file line number Diff line number Diff line change
@@ -2,10 +2,12 @@ import { Component } from '@angular/core';
import { timer } from 'rxjs';
import { render, screen } from '../src/public_api';
import { mapTo } from 'rxjs/operators';
import { AsyncPipe } from '@angular/common';

@Component({
selector: 'atl-fixture',
template: ` <div>{{ result | async }}</div> `,
imports: [AsyncPipe],
})
class FixtureComponent {
result = timer(30).pipe(mapTo('I am visible'));
38 changes: 21 additions & 17 deletions projects/testing-library/tests/integration.spec.ts
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import { of, BehaviorSubject } from 'rxjs';
import { debounceTime, switchMap, map, startWith } from 'rxjs/operators';
import { render, screen, waitFor, waitForElementToBeRemoved, within } from '../src/lib/testing-library';
import userEvent from '@testing-library/user-event';
import { AsyncPipe, NgForOf } from '@angular/common';

const DEBOUNCE_TIME = 1_000;

@@ -21,6 +22,25 @@ class ModalService {
}
}

@Component({
selector: 'atl-table',
template: `
<table>
<tr *ngFor="let entity of entities">
<td>{{ entity.name }}</td>
<td>
<button (click)="edit.next(entity.name)">Edit</button>
</td>
</tr>
</table>
`,
imports: [NgForOf],
})
class TableComponent {
@Input() entities: any[] = [];
@Output() edit = new EventEmitter<string>();
}

@Component({
template: `
<h1>Entities Title</h1>
@@ -31,6 +51,7 @@ class ModalService {
</label>
<atl-table [entities]="entities | async" (edit)="editEntityClicked($event)"></atl-table>
`,
imports: [TableComponent, AsyncPipe],
})
class EntitiesComponent {
query = new BehaviorSubject<string>('');
@@ -55,22 +76,6 @@ class EntitiesComponent {
}
}

@Component({
selector: 'atl-table',
template: `
<table>
<tr *ngFor="let entity of entities">
<td>{{ entity.name }}</td>
<td><button (click)="edit.next(entity.name)">Edit</button></td>
</tr>
</table>
`,
})
class TableComponent {
@Input() entities: any[] = [];
@Output() edit = new EventEmitter<string>();
}

const entities = [
{
id: 1,
@@ -91,7 +96,6 @@ async function setup() {
const user = userEvent.setup();

await render(EntitiesComponent, {
declarations: [TableComponent],
providers: [
{
provide: EntitiesService,
4 changes: 3 additions & 1 deletion projects/testing-library/tests/issues/issue-230.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Component } from '@angular/core';
import { render, waitFor, screen } from '../../src/public_api';
import { NgClass } from '@angular/common';

@Component({
template: ` <button [ngClass]="classes">Load</button> `,
imports: [NgClass],
})
class LoopComponent {
get classes() {
@@ -17,7 +19,7 @@ test('wait does not end up in a loop', async () => {

await expect(
waitFor(() => {
expect(true).toEqual(false);
expect(true).toBe(false);
}),
).rejects.toThrow();
});
9 changes: 5 additions & 4 deletions projects/testing-library/tests/issues/issue-280.spec.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { Location } from '@angular/common';
import { Component, NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { RouterLink, RouterModule, RouterOutlet, 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: `<div>Navigate</div>
template: ` <div>Navigate</div>
<router-outlet></router-outlet>`,
imports: [RouterOutlet],
})
class MainComponent {}

@Component({
template: `<div>first page</div>
template: ` <div>first page</div>
<a routerLink="/second">go to second</a>`,
imports: [RouterLink],
})
class FirstComponent {}

@@ -35,7 +37,6 @@ const routes: Routes = [
];

@NgModule({
declarations: [FirstComponent, SecondComponent],
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
18 changes: 9 additions & 9 deletions projects/testing-library/tests/render-template.spec.ts
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ class GreetingComponent {

test('the directive renders', async () => {
const view = await render('<div onOff></div>', {
declarations: [OnOffDirective],
imports: [OnOffDirective],
});

// eslint-disable-next-line testing-library/no-container
@@ -54,7 +54,7 @@ test('the directive renders', async () => {

test('the component renders', async () => {
const view = await render('<greeting name="Angular"></greeting>', {
declarations: [GreetingComponent],
imports: [GreetingComponent],
});

// eslint-disable-next-line testing-library/no-container
@@ -64,7 +64,7 @@ test('the component renders', async () => {

test('uses the default props', async () => {
await render('<div onOff></div>', {
declarations: [OnOffDirective],
imports: [OnOffDirective],
});

fireEvent.click(screen.getByText('init'));
@@ -74,7 +74,7 @@ test('uses the default props', async () => {

test('overrides input properties', async () => {
await render('<div onOff on="hello"></div>', {
declarations: [OnOffDirective],
imports: [OnOffDirective],
});

fireEvent.click(screen.getByText('init'));
@@ -85,7 +85,7 @@ test('overrides input properties', async () => {
test('overrides input properties via a wrapper', async () => {
// `bar` will be set as a property on the wrapper component, the property will be used to pass to the directive
await render('<div onOff [on]="bar"></div>', {
declarations: [OnOffDirective],
imports: [OnOffDirective],
componentProperties: {
bar: 'hello',
},
@@ -100,7 +100,7 @@ test('overrides output properties', async () => {
const clicked = jest.fn();

await render('<div onOff (clicked)="clicked($event)"></div>', {
declarations: [OnOffDirective],
imports: [OnOffDirective],
componentProperties: {
clicked,
},
@@ -116,7 +116,7 @@ test('overrides output properties', async () => {
describe('removeAngularAttributes', () => {
it('should remove angular attributes', async () => {
await render('<div onOff (clicked)="clicked($event)"></div>', {
declarations: [OnOffDirective],
imports: [OnOffDirective],
removeAngularAttributes: true,
});

@@ -126,7 +126,7 @@ describe('removeAngularAttributes', () => {

it('is disabled by default', async () => {
await render('<div onOff (clicked)="clicked($event)"></div>', {
declarations: [OnOffDirective],
imports: [OnOffDirective],
});

expect(document.querySelector('[ng-version]')).not.toBeNull();
@@ -136,7 +136,7 @@ describe('removeAngularAttributes', () => {

test('updates properties and invokes change detection', async () => {
const view = await render<{ value: string }>('<div [update]="value" ></div>', {
declarations: [UpdateInputDirective],
imports: [UpdateInputDirective],
componentProperties: {
value: 'value1',
},
Loading

0 comments on commit fdcf5fa

Please sign in to comment.