Skip to content

Commit 91d1f2d

Browse files
committed
feat: update to Angular 21 (and switch to Vitest)
1 parent db204fb commit 91d1f2d

File tree

148 files changed

+2723
-580
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

148 files changed

+2723
-580
lines changed

.browserslistrc

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

.github/workflows/ci.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,20 @@ jobs:
3535
- name: install
3636
run: npm install --force
3737
- name: build
38-
run: npm run build -- --skip-nx-cache
39-
- name: test
40-
run: npm run test
38+
run: npm run build
39+
timeout-minutes: 5
40+
- name: test-library
41+
run: npm run test:testing-library
42+
timeout-minutes: 5
43+
- name: test-examples
44+
run: npm run test:example-app
45+
timeout-minutes: 5
46+
- name: test-karma-examples
47+
run: npm run test:karma-app -- --watch=false --no-progress
48+
timeout-minutes: 5
4149
- name: lint
4250
run: npm run lint
51+
timeout-minutes: 5
4352
- name: Release
4453
if: github.repository == 'testing-library/angular-testing-library' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta')
4554
run: npx semantic-release

angular.json

Lines changed: 81 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"prefix": "lib",
1919
"architect": {
2020
"build": {
21-
"builder": "@angular-devkit/build-angular:ng-packagr",
21+
"builder": "@angular/build:ng-packagr",
2222
"options": {
2323
"project": "projects/testing-library/ng-package.json"
2424
},
@@ -33,9 +33,9 @@
3333
"defaultConfiguration": "production"
3434
},
3535
"test": {
36-
"builder": "@angular-builders/jest:run",
36+
"builder": "@angular/build:unit-test",
3737
"options": {
38-
"configPath": "projects/testing-library/jest.config.ts"
38+
"setupFiles": ["projects/testing-library/test-setup.ts"]
3939
}
4040
},
4141
"lint": {
@@ -53,16 +53,17 @@
5353
"prefix": "app",
5454
"architect": {
5555
"build": {
56-
"builder": "@angular-devkit/build-angular:browser",
56+
"builder": "@angular/build:application",
5757
"options": {
58-
"outputPath": "dist/apps/example-app",
58+
"outputPath": {
59+
"base": "dist/apps/example-app"
60+
},
5961
"index": "apps/example-app/src/index.html",
60-
"main": "apps/example-app/src/main.ts",
61-
"polyfills": "apps/example-app/src/polyfills.ts",
6262
"tsConfig": "apps/example-app/tsconfig.app.json",
6363
"assets": ["apps/example-app/src/favicon.ico", "apps/example-app/src/assets"],
64-
"styles": ["apps/example-app/src/styles.css"],
65-
"scripts": []
64+
"styles": [],
65+
"scripts": [],
66+
"browser": "apps/example-app/src/main.ts"
6667
},
6768
"configurations": {
6869
"production": {
@@ -75,9 +76,7 @@
7576
"outputHashing": "all"
7677
},
7778
"development": {
78-
"buildOptimizer": false,
7979
"optimization": false,
80-
"vendorChunk": true,
8180
"extractLicenses": false,
8281
"sourceMap": true,
8382
"namedChunks": true
@@ -86,7 +85,7 @@
8685
"defaultConfiguration": "production"
8786
},
8887
"serve": {
89-
"builder": "@angular-devkit/build-angular:dev-server",
88+
"builder": "@angular/build:dev-server",
9089
"configurations": {
9190
"production": {
9291
"buildTarget": "example-app:build:production"
@@ -97,22 +96,77 @@
9796
},
9897
"defaultConfiguration": "development"
9998
},
100-
"extract-i18n": {
101-
"builder": "@angular-devkit/build-angular:extract-i18n",
99+
"test": {
100+
"builder": "@angular/build:unit-test",
102101
"options": {
103-
"buildTarget": "example-app:build"
102+
"setupFiles": ["apps/example-app/test-setup.ts"]
104103
}
105104
},
106-
"test": {
107-
"builder": "@angular-builders/jest:run",
105+
"lint": {
106+
"builder": "@angular-eslint/builder:lint",
108107
"options": {
109-
"configPath": "apps/example-app/jest.config.ts"
108+
"lintFilePatterns": ["apps/example-app/**/*.ts", "apps/example-app/**/*.html"]
110109
}
110+
}
111+
}
112+
},
113+
"example-app-jest": {
114+
"projectType": "application",
115+
"root": "apps/example-app-jest",
116+
"sourceRoot": "apps/example-app-jest/src",
117+
"prefix": "app",
118+
"architect": {
119+
"build": {
120+
"builder": "@angular/build:application",
121+
"options": {
122+
"outputPath": {
123+
"base": "dist/apps/example-app-jest"
124+
},
125+
"index": "apps/example-app-jest/src/index.html",
126+
"tsConfig": "apps/example-app-jest/tsconfig.app.json",
127+
"assets": ["apps/example-app-jest/src/favicon.ico", "apps/example-app-jest/src/assets"],
128+
"styles": [],
129+
"scripts": [],
130+
"browser": "apps/example-app-jest/src/main.ts"
131+
},
132+
"configurations": {
133+
"production": {
134+
"budgets": [
135+
{
136+
"type": "anyComponentStyle",
137+
"maximumWarning": "6kb"
138+
}
139+
],
140+
"outputHashing": "all"
141+
},
142+
"development": {
143+
"optimization": false,
144+
"extractLicenses": false,
145+
"sourceMap": true,
146+
"namedChunks": true
147+
}
148+
},
149+
"defaultConfiguration": "production"
150+
},
151+
"serve": {
152+
"builder": "@angular/build:dev-server",
153+
"configurations": {
154+
"production": {
155+
"buildTarget": "example-app-jest:build:production"
156+
},
157+
"development": {
158+
"buildTarget": "example-app-jest:build:development"
159+
}
160+
},
161+
"defaultConfiguration": "development"
162+
},
163+
"test": {
164+
"builder": "@angular-builders/jest:run"
111165
},
112166
"lint": {
113167
"builder": "@angular-eslint/builder:lint",
114168
"options": {
115-
"lintFilePatterns": ["apps/example-app/**/*.ts", "apps/example-app/**/*.html"]
169+
"lintFilePatterns": ["apps/example-app-jest/**/*.ts", "apps/example-app-jest/**/*.html"]
116170
}
117171
}
118172
}
@@ -124,15 +178,17 @@
124178
"prefix": "app",
125179
"architect": {
126180
"build": {
127-
"builder": "@angular-devkit/build-angular:browser",
181+
"builder": "@angular/build:application",
128182
"options": {
129-
"outputPath": "dist/apps/example-app-karma",
183+
"outputPath": {
184+
"base": "dist/apps/example-app-karma"
185+
},
130186
"index": "apps/example-app-karma/src/index.html",
131-
"main": "apps/example-app-karma/src/main.ts",
132187
"tsConfig": "apps/example-app-karma/tsconfig.app.json",
133188
"assets": ["apps/example-app-karma/src/favicon.ico", "apps/example-app-karma/src/assets"],
134189
"styles": [],
135-
"scripts": []
190+
"scripts": [],
191+
"browser": "apps/example-app-karma/src/main.ts"
136192
},
137193
"configurations": {
138194
"production": {
@@ -145,9 +201,7 @@
145201
"outputHashing": "all"
146202
},
147203
"development": {
148-
"buildOptimizer": false,
149204
"optimization": false,
150-
"vendorChunk": true,
151205
"extractLicenses": false,
152206
"sourceMap": true,
153207
"namedChunks": true
@@ -156,7 +210,7 @@
156210
"defaultConfiguration": "production"
157211
},
158212
"serve": {
159-
"builder": "@angular-devkit/build-angular:dev-server",
213+
"builder": "@angular/build:dev-server",
160214
"configurations": {
161215
"production": {
162216
"buildTarget": "example-app-karma:build:production"
@@ -168,7 +222,7 @@
168222
"defaultConfiguration": "development"
169223
},
170224
"test": {
171-
"builder": "@angular-devkit/build-angular:karma",
225+
"builder": "@angular/build:karma",
172226
"options": {
173227
"main": "apps/example-app-karma/src/test.ts",
174228
"tsConfig": "apps/example-app-karma/tsconfig.spec.json",
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @ts-check
2+
3+
// TODO - https://github.com/nrwl/nx/issues/22576
4+
5+
/** @type {import('@typescript-eslint/utils/ts-eslint').FlatConfig.ConfigPromise} */
6+
const config = (async () => (await import('./eslint.config.mjs')).default)();
7+
module.exports = config;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// @ts-check
2+
3+
import tseslint from 'typescript-eslint';
4+
import rootConfig from '../../eslint.config.mjs';
5+
6+
export default tseslint.config(...rootConfig);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module.exports = {
2+
preset: 'jest-preset-angular',
3+
setupFilesAfterEnv: ['<rootDir>/apps/example-app-jest/src/test-setup.ts'],
4+
modulePathIgnorePatterns: ['<rootDir>/dist'],
5+
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/dist/'],
6+
globals: {
7+
'ts-jest': {
8+
tsconfig: '<rootDir>/apps/example-app-jest/tsconfig.spec.json',
9+
stringifyContentPathRegex: '\\.(html|svg)$',
10+
},
11+
},
12+
coverageDirectory: 'coverage/apps/example-app-jest',
13+
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
14+
moduleNameMapper: {
15+
'@testing-library/angular/jest-utils': '<rootDir>/projects/testing-library/jest-utils/index.ts',
16+
'@testing-library/angular': '<rootDir>/projects/testing-library',
17+
},
18+
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { render, screen } from '@testing-library/angular';
2+
import userEvent from '@testing-library/user-event';
3+
4+
import { SingleComponent } from './00-single-component';
5+
6+
test('renders the current value and can increment and decrement', async () => {
7+
const user = userEvent.setup();
8+
await render(SingleComponent);
9+
10+
const incrementControl = screen.getByRole('button', { name: /increment/i });
11+
const decrementControl = screen.getByRole('button', { name: /decrement/i });
12+
const valueControl = screen.getByTestId('value');
13+
14+
expect(valueControl).toHaveTextContent('0');
15+
16+
await user.click(incrementControl);
17+
await user.click(incrementControl);
18+
expect(valueControl).toHaveTextContent('2');
19+
20+
await user.click(decrementControl);
21+
expect(valueControl).toHaveTextContent('1');
22+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Component } from '@angular/core';
2+
3+
@Component({
4+
selector: 'atl-fixture',
5+
standalone: true,
6+
template: `
7+
<button (click)="value = value - 1">Decrement</button>
8+
<span data-testid="value">{{ value }}</span>
9+
<button (click)="value = value + 1">Increment</button>
10+
`,
11+
})
12+
export class SingleComponent {
13+
value = 0;
14+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { render, screen } from '@testing-library/angular';
2+
import userEvent from '@testing-library/user-event';
3+
4+
import { NestedContainerComponent } from './01-nested-component';
5+
6+
test('renders the current value and can increment and decrement', async () => {
7+
const user = userEvent.setup();
8+
await render(NestedContainerComponent);
9+
10+
const incrementControl = screen.getByRole('button', { name: /increment/i });
11+
const decrementControl = screen.getByRole('button', { name: /decrement/i });
12+
const valueControl = screen.getByTestId('value');
13+
14+
expect(valueControl).toHaveTextContent('0');
15+
16+
await user.click(incrementControl);
17+
await user.click(incrementControl);
18+
expect(valueControl).toHaveTextContent('2');
19+
20+
await user.click(decrementControl);
21+
expect(valueControl).toHaveTextContent('1');
22+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Component, Input, Output, EventEmitter } from '@angular/core';
2+
3+
@Component({
4+
standalone: true,
5+
selector: 'atl-button',
6+
template: ' <button (click)="raise.emit()">{{ name }}</button> ',
7+
})
8+
export class NestedButtonComponent {
9+
@Input() name = '';
10+
@Output() raise = new EventEmitter<void>();
11+
}
12+
13+
@Component({
14+
standalone: true,
15+
selector: 'atl-value',
16+
template: ' <span data-testid="value">{{ value }}</span> ',
17+
})
18+
export class NestedValueComponent {
19+
@Input() value?: number;
20+
}
21+
22+
@Component({
23+
standalone: true,
24+
selector: 'atl-fixture',
25+
template: `
26+
<atl-button (raise)="value = value - 1" name="Decrement" />
27+
<atl-value [value]="value" />
28+
<atl-button (raise)="value = value + 1" name="Increment" />
29+
`,
30+
imports: [NestedButtonComponent, NestedValueComponent],
31+
})
32+
export class NestedContainerComponent {
33+
value = 0;
34+
}

0 commit comments

Comments
 (0)