diff --git a/.all-contributorsrc b/.all-contributorsrc
index 3b3a470d..07a9a931 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -419,6 +419,24 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "FabienDehopre",
+ "name": "Fabien Dehopré",
+ "avatar_url": "https://avatars.githubusercontent.com/u/97023?v=4",
+ "profile": "https://github.com/FabienDehopre",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "jvereecken",
+ "name": "Jamie Vereecken",
+ "avatar_url": "https://avatars.githubusercontent.com/u/108937550?v=4",
+ "profile": "https://github.com/jvereecken",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 7,
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index db976dcf..ac9d248f 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,7 +1,7 @@
// For format details, see https://aka.ms/devcontainer.json.
{
"name": "angular-testing-library",
- "image": "mcr.microsoft.com/devcontainers/typescript-node:0-20-bullseye",
+ "image": "mcr.microsoft.com/devcontainers/typescript-node:22-bullseye",
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
@@ -13,7 +13,7 @@
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
- "postCreateCommand": "npm i",
+ "postCreateCommand": "npm install --force",
"onCreateCommand": "sudo cp .devcontainer/welcome-message.txt /usr/local/etc/vscode-dev-containers/first-run-notice.txt",
"waitFor": "postCreateCommand",
diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index 3c3629e6..00000000
--- a/.eslintignore
+++ /dev/null
@@ -1 +0,0 @@
-node_modules
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 0a96094f..00000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,127 +0,0 @@
-{
- "root": true,
- "ignorePatterns": ["**/*"],
- "plugins": ["@nx", "testing-library"],
- "overrides": [
- {
- "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
- "rules": {
- "@nx/enforce-module-boundaries": [
- "error",
- {
- "enforceBuildableLibDependency": true,
- "allow": [],
- "depConstraints": [
- {
- "sourceTag": "*",
- "onlyDependOnLibsWithTags": ["*"]
- }
- ]
- }
- ]
- }
- },
- {
- "files": ["*.ts", "*.tsx"],
- "extends": ["plugin:@nx/typescript"],
- "rules": {
- "@typescript-eslint/no-extra-semi": "error",
- "no-extra-semi": "off"
- }
- },
- {
- "files": ["*.js", "*.jsx"],
- "extends": ["plugin:@nx/javascript"],
- "rules": {
- "@typescript-eslint/no-extra-semi": "error",
- "no-extra-semi": "off"
- }
- },
- {
- "files": ["*.ts"],
- "plugins": ["eslint-plugin-import", "@angular-eslint/eslint-plugin", "@typescript-eslint"],
- "rules": {
- "@typescript-eslint/consistent-type-definitions": "error",
- "@typescript-eslint/dot-notation": "off",
- "@typescript-eslint/naming-convention": "error",
- "@typescript-eslint/no-shadow": [
- "error",
- {
- "hoist": "all"
- }
- ],
- "@typescript-eslint/no-unused-expressions": "error",
- "@typescript-eslint/prefer-function-type": "error",
- "@typescript-eslint/quotes": "off",
- "@typescript-eslint/type-annotation-spacing": "error",
- "@typescript-eslint/no-explicit-any": "off",
- "arrow-body-style": "off",
- "brace-style": ["error", "1tbs"],
- "curly": "error",
- "eol-last": "error",
- "eqeqeq": ["error", "smart"],
- "guard-for-in": "error",
- "id-blacklist": "off",
- "id-match": "off",
- "import/no-deprecated": "warn",
- "no-bitwise": "error",
- "no-caller": "error",
- "no-console": [
- "error",
- {
- "allow": [
- "log",
- "warn",
- "dir",
- "timeLog",
- "assert",
- "clear",
- "count",
- "countReset",
- "group",
- "groupEnd",
- "table",
- "dirxml",
- "error",
- "groupCollapsed",
- "Console",
- "profile",
- "profileEnd",
- "timeStamp",
- "context"
- ]
- }
- ],
- "no-empty": "off",
- "no-eval": "error",
- "no-new-wrappers": "error",
- "no-throw-literal": "error",
- "no-undef-init": "error",
- "no-underscore-dangle": "off",
- "radix": "error",
- "spaced-comment": [
- "error",
- "always",
- {
- "markers": ["/"]
- }
- ]
- }
- },
- {
- "files": ["*.html"],
- "rules": {}
- },
- {
- "files": ["*.ts", "*.js"],
- "extends": ["prettier"]
- },
- {
- "files": ["*.spec.ts"],
- "extends": ["plugin:testing-library/angular"],
- "rules": {
- "testing-library/prefer-explicit-assert": "error"
- }
- }
- ]
-}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5820814f..215ef7d5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -22,7 +22,7 @@ jobs:
strategy:
matrix:
- node-version: ${{ fromJSON((github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') && '[20]' || '[18, 20]') }}
+ node-version: ${{ fromJSON((github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') && '[22]' || '[18, 20, 22]') }}
os: ${{ fromJSON((github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') && '["ubuntu-latest"]' || '["ubuntu-latest", "windows-latest"]') }}
runs-on: ${{ matrix.os }}
@@ -38,6 +38,8 @@ jobs:
run: npm run build -- --skip-nx-cache
- name: test
run: npm run test
+ - name: lint
+ run: npm run lint
- name: Release
if: github.repository == 'testing-library/angular-testing-library' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta')
run: npx semantic-release
diff --git a/.node-version b/.node-version
index 914d1a73..8fdd954d 100644
--- a/.node-version
+++ b/.node-version
@@ -1 +1 @@
-20.9
\ No newline at end of file
+22
\ No newline at end of file
diff --git a/README.md b/README.md
index c98936d2..028f7213 100644
--- a/README.md
+++ b/README.md
@@ -98,7 +98,7 @@ counter.component.ts
```ts
@Component({
- selector: 'app-counter',
+ selector: 'atl-counter',
template: `
{{ hello() }}
@@ -179,6 +179,7 @@ You may also be interested in installing `jest-dom` so you can use
| Angular | Angular Testing Library |
| ------- | ---------------------------- |
+| 19.x | 17.x, 16.x, 15.x, 14.x, 13.x |
| 18.x | 17.x, 16.x, 15.x, 14.x, 13.x |
| 17.x | 17.x, 16.x, 15.x, 14.x, 13.x |
| 16.x | 14.x, 13.x |
@@ -272,6 +273,8 @@ Thanks goes to these people ([emoji key][emojis]):
 Arthur Petrie 💻 |
+  Fabien Dehopré 💻 |
+  Jamie Vereecken 💻 |
diff --git a/apps/example-app-karma/.eslintrc.json b/apps/example-app-karma/.eslintrc.json
deleted file mode 100644
index 404aa664..00000000
--- a/apps/example-app-karma/.eslintrc.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "extends": "../../.eslintrc.json",
- "ignorePatterns": ["!**/*"],
- "overrides": [
- {
- "files": ["*.ts"],
- "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
- "parserOptions": {
- "project": ["apps/example-app-karma/tsconfig.*?.json"]
- },
- "rules": {
- "@angular-eslint/directive-selector": [
- "error",
- {
- "type": "attribute",
- "prefix": "app",
- "style": "camelCase"
- }
- ],
- "@angular-eslint/component-selector": [
- "error",
- {
- "type": "element",
- "prefix": "app",
- "style": "kebab-case"
- }
- ]
- }
- },
- {
- "files": ["*.spec.ts"],
- "env": {
- "jasmine": true
- },
- "plugins": ["jasmine"],
- "extends": ["plugin:jasmine/recommended"]
- },
- {
- "files": ["*.html"],
- "extends": ["plugin:@nx/angular-template"],
- "rules": {}
- }
- ]
-}
diff --git a/apps/example-app-karma/eslint.config.cjs b/apps/example-app-karma/eslint.config.cjs
new file mode 100644
index 00000000..9e951e7a
--- /dev/null
+++ b/apps/example-app-karma/eslint.config.cjs
@@ -0,0 +1,7 @@
+// @ts-check
+
+// TODO - https://github.com/nrwl/nx/issues/22576
+
+/** @type {import('@typescript-eslint/utils/ts-eslint').FlatConfig.ConfigPromise} */
+const config = (async () => (await import('./eslint.config.mjs')).default)();
+module.exports = config;
diff --git a/apps/example-app-karma/eslint.config.mjs b/apps/example-app-karma/eslint.config.mjs
new file mode 100644
index 00000000..8f627dbf
--- /dev/null
+++ b/apps/example-app-karma/eslint.config.mjs
@@ -0,0 +1,8 @@
+// @ts-check
+
+import tseslint from "typescript-eslint";
+import rootConfig from "../../eslint.config.mjs";
+
+export default tseslint.config(
+ ...rootConfig,
+);
diff --git a/apps/example-app-karma/jasmine-dom.d.ts b/apps/example-app-karma/jasmine-dom.d.ts
index f8fa4a7f..54d79038 100644
--- a/apps/example-app-karma/jasmine-dom.d.ts
+++ b/apps/example-app-karma/jasmine-dom.d.ts
@@ -1,5 +1,4 @@
declare module '@testing-library/jasmine-dom' {
- // eslint-disable-next-line @typescript-eslint/naming-convention
const JasmineDOM: any;
export default JasmineDOM;
}
diff --git a/apps/example-app-karma/src/app/examples/login-form.spec.ts b/apps/example-app-karma/src/app/examples/login-form.spec.ts
index 9c510652..a0282341 100644
--- a/apps/example-app-karma/src/app/examples/login-form.spec.ts
+++ b/apps/example-app-karma/src/app/examples/login-form.spec.ts
@@ -29,7 +29,7 @@ it('should display invalid message and submit button must be disabled', async ()
});
@Component({
- selector: 'app-login',
+ selector: 'atl-login',
standalone: true,
imports: [ReactiveFormsModule, NgIf],
template: `
@@ -51,7 +51,7 @@ class LoginComponent {
});
constructor(private fb: FormBuilder) {}
-
+
get email(): FormControl {
return this.form.get('email') as FormControl;
}
diff --git a/apps/example-app-karma/src/app/issues/rerender.spec.ts b/apps/example-app-karma/src/app/issues/rerender.spec.ts
index 9b044d1f..324e8a16 100644
--- a/apps/example-app-karma/src/app/issues/rerender.spec.ts
+++ b/apps/example-app-karma/src/app/issues/rerender.spec.ts
@@ -7,9 +7,9 @@ it('can rerender component', async () => {
},
});
- expect(screen.getByText('Hello Sarah')).toBeTruthy();
+ expect(screen.getByText('Hello Sarah')).toBeInTheDocument();
await rerender({ componentProperties: { name: 'Mark' } });
- expect(screen.getByText('Hello Mark')).toBeTruthy();
+ expect(screen.getByText('Hello Mark')).toBeInTheDocument();
});
diff --git a/apps/example-app/.eslintrc.json b/apps/example-app/.eslintrc.json
deleted file mode 100644
index ed5e4d11..00000000
--- a/apps/example-app/.eslintrc.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "extends": "../../.eslintrc.json",
- "ignorePatterns": ["!**/*"],
- "overrides": [
- {
- "files": ["*.ts"],
- "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
- "parserOptions": {
- "project": ["apps/example-app/tsconfig.*?.json"]
- },
- "rules": {
- "@angular-eslint/directive-selector": [
- "error",
- {
- "type": "attribute",
- "prefix": "app",
- "style": "camelCase"
- }
- ],
- "@angular-eslint/component-selector": [
- "error",
- {
- "type": "element",
- "prefix": "app",
- "style": "kebab-case"
- }
- ]
- }
- },
- {
- "files": ["*.spec.ts"],
- "env": {
- "jest": true
- },
- "extends": ["plugin:jest/recommended", "plugin:jest/style", "plugin:jest-dom/recommended"],
- "rules": {
- "jest/consistent-test-it": ["error"],
- "jest/expect-expect": "off"
- }
- },
- {
- "files": ["*.html"],
- "extends": ["plugin:@nx/angular-template"],
- "rules": {}
- }
- ]
-}
diff --git a/apps/example-app/eslint.config.cjs b/apps/example-app/eslint.config.cjs
new file mode 100644
index 00000000..9e951e7a
--- /dev/null
+++ b/apps/example-app/eslint.config.cjs
@@ -0,0 +1,7 @@
+// @ts-check
+
+// TODO - https://github.com/nrwl/nx/issues/22576
+
+/** @type {import('@typescript-eslint/utils/ts-eslint').FlatConfig.ConfigPromise} */
+const config = (async () => (await import('./eslint.config.mjs')).default)();
+module.exports = config;
diff --git a/apps/example-app/eslint.config.mjs b/apps/example-app/eslint.config.mjs
new file mode 100644
index 00000000..01625848
--- /dev/null
+++ b/apps/example-app/eslint.config.mjs
@@ -0,0 +1,8 @@
+// @ts-check
+
+import tseslint from "typescript-eslint";
+import rootConfig from "../../eslint.config.mjs";
+
+export default tseslint.config(
+ ...rootConfig,
+);
\ No newline at end of file
diff --git a/apps/example-app/jest.config.ts b/apps/example-app/jest.config.ts
index 4b0c248c..e0ea9c2d 100644
--- a/apps/example-app/jest.config.ts
+++ b/apps/example-app/jest.config.ts
@@ -1,4 +1,3 @@
-/* eslint-disable */
export default {
displayName: {
name: 'Example App',
diff --git a/apps/example-app/src/app/examples/00-single-component.ts b/apps/example-app/src/app/examples/00-single-component.ts
index 7c132c2f..4a092390 100644
--- a/apps/example-app/src/app/examples/00-single-component.ts
+++ b/apps/example-app/src/app/examples/00-single-component.ts
@@ -1,7 +1,7 @@
import { Component } from '@angular/core';
@Component({
- selector: 'app-fixture',
+ selector: 'atl-fixture',
standalone: true,
template: `
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 645ce966..fd0d0c0e 100644
--- a/apps/example-app/src/app/examples/01-nested-component.ts
+++ b/apps/example-app/src/app/examples/01-nested-component.ts
@@ -2,7 +2,7 @@ import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
standalone: true,
- selector: 'app-button',
+ selector: 'atl-button',
template: ' ',
})
export class NestedButtonComponent {
@@ -12,7 +12,7 @@ export class NestedButtonComponent {
@Component({
standalone: true,
- selector: 'app-value',
+ selector: 'atl-value',
template: ' {{ value }} ',
})
export class NestedValueComponent {
@@ -21,11 +21,11 @@ export class NestedValueComponent {
@Component({
standalone: true,
- selector: 'app-fixture',
+ selector: 'atl-fixture',
template: `
-
-
-
+
+
+
`,
imports: [NestedButtonComponent, NestedValueComponent],
})
diff --git a/apps/example-app/src/app/examples/02-input-output.spec.ts b/apps/example-app/src/app/examples/02-input-output.spec.ts
index 847f6e14..5a55bd57 100644
--- a/apps/example-app/src/app/examples/02-input-output.spec.ts
+++ b/apps/example-app/src/app/examples/02-input-output.spec.ts
@@ -36,7 +36,7 @@ test.skip('is possible to set input and listen for output with the template synt
const user = userEvent.setup();
const sendSpy = jest.fn();
- await render('', {
+ await render('', {
imports: [InputOutputComponent],
on: {
sendValue: sendSpy,
@@ -94,7 +94,7 @@ test('is possible to set input and listen for output with the template syntax (d
const user = userEvent.setup();
const sendSpy = jest.fn();
- await render('', {
+ await render('', {
imports: [InputOutputComponent],
componentProperties: {
sendValue: sendSpy,
diff --git a/apps/example-app/src/app/examples/02-input-output.ts b/apps/example-app/src/app/examples/02-input-output.ts
index 5bf70abb..3d7f9796 100644
--- a/apps/example-app/src/app/examples/02-input-output.ts
+++ b/apps/example-app/src/app/examples/02-input-output.ts
@@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
standalone: true,
- selector: 'app-fixture',
+ selector: 'atl-fixture',
template: `
{{ value }}
diff --git a/apps/example-app/src/app/examples/03-forms.ts b/apps/example-app/src/app/examples/03-forms.ts
index 49756dca..a62d8650 100644
--- a/apps/example-app/src/app/examples/03-forms.ts
+++ b/apps/example-app/src/app/examples/03-forms.ts
@@ -4,7 +4,7 @@ import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
@Component({
standalone: true,
- selector: 'app-fixture',
+ selector: 'atl-fixture',
imports: [ReactiveFormsModule, NgForOf, NgIf],
template: `