From ef6194b134c64c9249f9f3614ca7dad0bd275ec5 Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Thu, 25 Apr 2024 19:26:55 +0200
Subject: [PATCH 01/12] docs: include v16 in version compatibility table (#448)

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index eed18ab..531c5e5 100644
--- a/README.md
+++ b/README.md
@@ -162,7 +162,7 @@ You may also be interested in installing `jest-dom` so you can use
 
 | Angular | Angular Testing Library |
 | ------- | ----------------------- |
-| 17.x    | 15.x, 14.x, 13.x        |
+| 17.x    | 16.x, 15.x, 14.x, 13.x  |
 | 16.x    | 14.x, 13.x              |
 | >= 15.1 | 14.x, 13.x              |
 | < 15.1  | 12.x, 11.x              |

From 3d396c0d925122159b750b6cd363c13b8efeb07a Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Mon, 20 May 2024 14:24:58 +0200
Subject: [PATCH 02/12] docs: add directive example (#450)

---
 .../src/app/examples/08-directive.spec.ts     | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)

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 5ba450b..8b70b38 100644
--- a/apps/example-app/src/app/examples/08-directive.spec.ts
+++ b/apps/example-app/src/app/examples/08-directive.spec.ts
@@ -1,8 +1,34 @@
+import { Component } from '@angular/core';
 import { render, screen } from '@testing-library/angular';
 import userEvent from '@testing-library/user-event';
 
 import { SpoilerDirective } from './08-directive';
 
+test('it is possible to test directives with container component', async () => {
+  @Component({
+    template: `<div appSpoiler data-testid="dir"></div>`,
+    imports: [SpoilerDirective],
+    standalone: true,
+  })
+  class FixtureComponent {}
+
+  const user = userEvent.setup();
+  await render(FixtureComponent);
+
+  const directive = screen.getByTestId('dir');
+
+  expect(screen.queryByText('I am visible now...')).not.toBeInTheDocument();
+  expect(screen.getByText('SPOILER')).toBeInTheDocument();
+
+  await user.hover(directive);
+  expect(screen.queryByText('SPOILER')).not.toBeInTheDocument();
+  expect(screen.getByText('I am visible now...')).toBeInTheDocument();
+
+  await user.unhover(directive);
+  expect(screen.getByText('SPOILER')).toBeInTheDocument();
+  expect(screen.queryByText('I am visible now...')).not.toBeInTheDocument();
+});
+
 test('it is possible to test directives', async () => {
   const user = userEvent.setup();
 

From 9a1da54a31fb062e8d38385eb300323a11a903ad Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Sat, 25 May 2024 18:08:08 +0200
Subject: [PATCH 03/12] build: update to Angular 18

---
 .eslintrc.json                        | 10 +++-
 .github/workflows/ci.yml              |  2 +-
 apps/example-app-karma/project.json   |  7 ++-
 apps/example-app/project.json         |  7 ++-
 decorate-angular-cli.js               | 70 ------------------------
 nx.json                               | 15 +++---
 package.json                          | 76 +++++++++++++--------------
 projects/testing-library/project.json |  7 ++-
 8 files changed, 63 insertions(+), 131 deletions(-)
 delete mode 100644 decorate-angular-cli.js

diff --git a/.eslintrc.json b/.eslintrc.json
index 765bf88..0a96094 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -24,12 +24,18 @@
     {
       "files": ["*.ts", "*.tsx"],
       "extends": ["plugin:@nx/typescript"],
-      "rules": {}
+      "rules": {
+        "@typescript-eslint/no-extra-semi": "error",
+        "no-extra-semi": "off"
+      }
     },
     {
       "files": ["*.js", "*.jsx"],
       "extends": ["plugin:@nx/javascript"],
-      "rules": {}
+      "rules": {
+        "@typescript-eslint/no-extra-semi": "error",
+        "no-extra-semi": "off"
+      }
     },
     {
       "files": ["*.ts"],
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 28aac0d..5820814 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -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
diff --git a/apps/example-app-karma/project.json b/apps/example-app-karma/project.json
index 733fe68..00820e3 100644
--- a/apps/example-app-karma/project.json
+++ b/apps/example-app-karma/project.json
@@ -4,6 +4,7 @@
   "projectType": "application",
   "sourceRoot": "apps/example-app-karma/src",
   "prefix": "app",
+  "tags": [],
   "generators": {},
   "targets": {
     "build": {
@@ -52,8 +53,7 @@
       "defaultConfiguration": "development"
     },
     "lint": {
-      "executor": "@nx/eslint:lint",
-      "outputs": ["{options.outputFile}"]
+      "executor": "@nx/eslint:lint"
     },
     "test": {
       "executor": "@angular-devkit/build-angular:karma",
@@ -63,6 +63,5 @@
         "karmaConfig": "apps/example-app-karma/karma.conf.js"
       }
     }
-  },
-  "tags": []
+  }
 }
diff --git a/apps/example-app/project.json b/apps/example-app/project.json
index 8af5697..ecbadfc 100644
--- a/apps/example-app/project.json
+++ b/apps/example-app/project.json
@@ -4,6 +4,7 @@
   "projectType": "application",
   "sourceRoot": "apps/example-app/src",
   "prefix": "app",
+  "tags": [],
   "generators": {},
   "targets": {
     "build": {
@@ -59,8 +60,7 @@
       }
     },
     "lint": {
-      "executor": "@nx/eslint:lint",
-      "outputs": ["{options.outputFile}"]
+      "executor": "@nx/eslint:lint"
     },
     "test": {
       "executor": "@nx/jest:jest",
@@ -70,6 +70,5 @@
       },
       "outputs": ["{workspaceRoot}/coverage/"]
     }
-  },
-  "tags": []
+  }
 }
diff --git a/decorate-angular-cli.js b/decorate-angular-cli.js
deleted file mode 100644
index cff5ab7..0000000
--- a/decorate-angular-cli.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * This file decorates the Angular CLI with the Nx CLI to enable features such as computation caching
- * and faster execution of tasks.
- *
- * It does this by:
- *
- * - Patching the Angular CLI to warn you in case you accidentally use the undecorated ng command.
- * - Symlinking the ng to nx command, so all commands run through the Nx CLI
- * - Updating the package.json postinstall script to give you control over this script
- *
- * The Nx CLI decorates the Angular CLI, so the Nx CLI is fully compatible with it.
- * Every command you run should work the same when using the Nx CLI, except faster.
- *
- * Because of symlinking you can still type `ng build/test/lint` in the terminal. The ng command, in this case,
- * will point to nx, which will perform optimizations before invoking ng. So the Angular CLI is always invoked.
- * The Nx CLI simply does some optimizations before invoking the Angular CLI.
- *
- * To opt out of this patch:
- * - Replace occurrences of nx with ng in your package.json
- * - Remove the script from your postinstall script in your package.json
- * - Delete and reinstall your node_modules
- */
-
-const fs = require('fs');
-const os = require('os');
-const cp = require('child_process');
-const isWindows = os.platform() === 'win32';
-let output;
-try {
-  output = require('@nx/workspace').output;
-} catch (e) {
-  console.warn(
-    'Angular CLI could not be decorated to enable computation caching. Please ensure @nx/workspace is installed.',
-  );
-  process.exit(0);
-}
-
-/**
- * Symlink of ng to nx, so you can keep using `ng build/test/lint` and still
- * invoke the Nx CLI and get the benefits of computation caching.
- */
-function symlinkNgCLItoNxCLI() {
-  try {
-    const ngPath = './node_modules/.bin/ng';
-    const nxPath = './node_modules/.bin/nx';
-    if (isWindows) {
-      /**
-       * This is the most reliable way to create symlink-like behavior on Windows.
-       * Such that it works in all shells and works with npx.
-       */
-      ['', '.cmd', '.ps1'].forEach((ext) => {
-        if (fs.existsSync(nxPath + ext)) fs.writeFileSync(ngPath + ext, fs.readFileSync(nxPath + ext));
-      });
-    } else {
-      // If unix-based, symlink
-      cp.execSync(`ln -sf ./nx ${ngPath}`);
-    }
-  } catch (e) {
-    output.error({ title: 'Unable to create a symlink from the Angular CLI to the Nx CLI:' + e.message });
-    throw e;
-  }
-}
-
-try {
-  symlinkNgCLItoNxCLI();
-  require('@nrwl/cli/lib/decorate-cli').decorateCli();
-  output.log({ title: 'Angular CLI has been decorated to enable computation caching.' });
-} catch (e) {
-  output.error({ title: 'Decoration of the Angular CLI did not complete successfully' });
-}
diff --git a/nx.json b/nx.json
index 7040d68..df534f7 100644
--- a/nx.json
+++ b/nx.json
@@ -1,7 +1,4 @@
 {
-  "affected": {
-    "defaultBase": "main"
-  },
   "workspaceLayout": {
     "appsDir": "apps",
     "libsDir": "projects"
@@ -71,10 +68,6 @@
       "inputs": ["default", "^production"],
       "cache": true
     },
-    "lint": {
-      "inputs": ["default", "{workspaceRoot}/.eslintrc.json"],
-      "cache": true
-    },
     "@nx/jest:jest": {
       "inputs": ["default", "^production"],
       "cache": true,
@@ -87,6 +80,10 @@
           "codeCoverage": true
         }
       }
+    },
+    "@nx/eslint:lint": {
+      "inputs": ["default", "{workspaceRoot}/.eslintrc.json"],
+      "cache": true
     }
   },
   "namedInputs": {
@@ -104,5 +101,7 @@
     ]
   },
   "nxCloudAccessToken": "M2Q4YjlkNjMtMzY1NC00ZjkwLTk1ZjgtZjg5Y2VkMzFjM2FifHJlYWQtd3JpdGU=",
-  "parallel": 3
+  "parallel": 3,
+  "useInferencePlugins": false,
+  "defaultBase": "main"
 }
diff --git a/package.json b/package.json
index 6c96abe..235d0ec 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,6 @@
   "scripts": {
     "ng": "nx",
     "nx": "nx",
-    "postinstall": "node ./decorate-angular-cli.js && ngcc --properties es2020 browser module main",
     "start": "nx serve",
     "prebuild": "rimraf dist",
     "build": "nx run-many --target=build --projects=testing-library",
@@ -28,42 +27,42 @@
     "prepare": "git config core.hookspath .githooks"
   },
   "dependencies": {
-    "@angular/animations": "17.3.2",
-    "@angular/cdk": "17.3.2",
-    "@angular/common": "17.3.2",
-    "@angular/compiler": "17.3.2",
-    "@angular/core": "17.3.2",
-    "@angular/material": "17.3.2",
-    "@angular/platform-browser": "17.3.2",
-    "@angular/platform-browser-dynamic": "17.3.2",
-    "@angular/router": "17.3.2",
-    "@ngrx/store": "17.1.0",
-    "@nx/angular": "17.2.8",
+    "@angular/animations": "18.0.0",
+    "@angular/cdk": "18.0.0",
+    "@angular/common": "18.0.0",
+    "@angular/compiler": "18.0.0",
+    "@angular/core": "18.0.0",
+    "@angular/material": "18.0.0",
+    "@angular/platform-browser": "18.0.0",
+    "@angular/platform-browser-dynamic": "18.0.0",
+    "@angular/router": "18.0.0",
+    "@ngrx/store": "18.0.0-beta.1",
+    "@nx/angular": "19.1.0",
     "@testing-library/dom": "^10.0.0",
     "rxjs": "7.8.0",
     "tslib": "~2.3.1",
     "zone.js": "0.14.2"
   },
   "devDependencies": {
-    "@angular-devkit/build-angular": "17.3.2",
-    "@angular-devkit/core": "17.3.2",
-    "@angular-devkit/schematics": "17.3.2",
-    "@angular-eslint/builder": "17.0.1",
-    "@angular-eslint/eslint-plugin": "17.0.1",
-    "@angular-eslint/eslint-plugin-template": "17.0.1",
-    "@angular-eslint/schematics": "17.0.1",
-    "@angular-eslint/template-parser": "17.0.1",
-    "@angular/cli": "~17.3.2",
-    "@angular/compiler-cli": "17.3.2",
-    "@angular/forms": "17.3.2",
-    "@angular/language-service": "17.3.2",
-    "@nx/eslint": "17.2.8",
-    "@nx/eslint-plugin": "17.2.8",
-    "@nx/jest": "17.2.8",
-    "@nx/node": "17.2.8",
-    "@nx/plugin": "17.2.8",
-    "@nx/workspace": "17.2.8",
-    "@schematics/angular": "17.3.2",
+    "@angular-devkit/build-angular": "18.0.1",
+    "@angular-devkit/core": "18.0.1",
+    "@angular-devkit/schematics": "18.0.1",
+    "@angular-eslint/builder": "17.3.0",
+    "@angular-eslint/eslint-plugin": "17.3.0",
+    "@angular-eslint/eslint-plugin-template": "17.3.0",
+    "@angular-eslint/schematics": "17.5.1",
+    "@angular-eslint/template-parser": "17.3.0",
+    "@angular/cli": "~18.0.0",
+    "@angular/compiler-cli": "18.0.0",
+    "@angular/forms": "18.0.0",
+    "@angular/language-service": "18.0.0",
+    "@nx/eslint": "19.1.0",
+    "@nx/eslint-plugin": "19.1.0",
+    "@nx/jest": "19.1.0",
+    "@nx/node": "19.1.0",
+    "@nx/plugin": "19.1.0",
+    "@nx/workspace": "19.1.0",
+    "@schematics/angular": "18.0.1",
     "@testing-library/jasmine-dom": "^1.2.0",
     "@testing-library/jest-dom": "^5.16.5",
     "@testing-library/user-event": "^14.4.3",
@@ -71,10 +70,11 @@
     "@types/jest": "29.5.1",
     "@types/node": "18.16.9",
     "@types/testing-library__jasmine-dom": "^1.3.0",
-    "@typescript-eslint/eslint-plugin": "6.9.1",
-    "@typescript-eslint/parser": "6.9.1",
+    "@typescript-eslint/eslint-plugin": "7.3.0",
+    "@typescript-eslint/parser": "7.3.0",
+    "autoprefixer": "^10.4.0",
     "cpy-cli": "^3.1.1",
-    "eslint": "8.48.0",
+    "eslint": "8.57.0",
     "eslint-config-prettier": "9.0.0",
     "eslint-plugin-import": "~2.25.4",
     "eslint-plugin-jasmine": "~4.1.3",
@@ -85,7 +85,7 @@
     "jasmine-spec-reporter": "7.0.0",
     "jest": "29.7.0",
     "jest-environment-jsdom": "29.5.0",
-    "jest-preset-angular": "14.0.3",
+    "jest-preset-angular": "14.1.0",
     "karma": "6.4.0",
     "karma-chrome-launcher": "^3.1.0",
     "karma-coverage": "^2.2.1",
@@ -93,8 +93,8 @@
     "karma-jasmine-html-reporter": "2.0.0",
     "lint-staged": "^12.1.6",
     "ng-mocks": "^14.11.0",
-    "ng-packagr": "17.3.0",
-    "nx": "17.2.8",
+    "ng-packagr": "18.0.0",
+    "nx": "19.1.0",
     "postcss": "^8.4.5",
     "postcss-import": "14.1.0",
     "postcss-preset-env": "7.5.0",
@@ -104,6 +104,6 @@
     "semantic-release": "^18.0.0",
     "ts-jest": "29.1.0",
     "ts-node": "10.9.1",
-    "typescript": "5.2.2"
+    "typescript": "5.4.5"
   }
 }
diff --git a/projects/testing-library/project.json b/projects/testing-library/project.json
index b91e85c..1deb065 100644
--- a/projects/testing-library/project.json
+++ b/projects/testing-library/project.json
@@ -4,6 +4,7 @@
   "projectType": "library",
   "sourceRoot": "projects/testing-library/src",
   "prefix": "lib",
+  "tags": [],
   "targets": {
     "build-package": {
       "executor": "@nx/angular:package",
@@ -22,8 +23,7 @@
       "defaultConfiguration": "production"
     },
     "lint": {
-      "executor": "@nx/eslint:lint",
-      "outputs": ["{options.outputFile}"]
+      "executor": "@nx/eslint:lint"
     },
     "build": {
       "executor": "nx:run-commands",
@@ -50,6 +50,5 @@
       },
       "outputs": ["{workspaceRoot}/coverage/projects/testing-library"]
     }
-  },
-  "tags": []
+  }
 }

From 7281dec47c6e517566413fe33bff449cfdd7197a Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Sat, 25 May 2024 18:08:30 +0200
Subject: [PATCH 04/12] docs: update version compatibility

---
 README.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.md b/README.md
index 531c5e5..e923e57 100644
--- a/README.md
+++ b/README.md
@@ -162,6 +162,7 @@ You may also be interested in installing `jest-dom` so you can use
 
 | Angular | Angular Testing Library |
 | ------- | ----------------------- |
+| 18.x    | 16.x, 15.x, 14.x, 13.x  |
 | 17.x    | 16.x, 15.x, 14.x, 13.x  |
 | 16.x    | 14.x, 13.x              |
 | >= 15.1 | 14.x, 13.x              |

From 47f680f18f1536e52e48c89bf371ba596e1a64db Mon Sep 17 00:00:00 2001
From: Matan Borenkraout <Matanbobi@gmail.com>
Date: Sat, 1 Jun 2024 20:07:18 +0300
Subject: [PATCH 05/12] docs: update all contributors badge (#452)

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index e923e57..2ba3f84 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,7 @@ practices.</p>
 [![version][version-badge]][package] [![downloads][downloads-badge]][npmtrends]
 [![MIT License][license-badge]][license]
 
-[![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors)
+[![All Contributors](https://img.shields.io/github/all-contributors/testing-library/angular-testing-library?color=ee8449&style=flat-square)](#contributors)
 [![PRs Welcome][prs-badge]][prs] [![Code of Conduct][coc-badge]][coc]
 [![Discord][discord-badge]][discord]
 

From 86c08e066df2bb316f405cf49e5c27effc60d6e0 Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Fri, 21 Jun 2024 20:27:32 +0200
Subject: [PATCH 06/12] docs: add computed example (#455)

---
 .../22-signal-inputs.component.spec.ts        | 50 +++++++++++++++----
 .../examples/22-signal-inputs.component.ts    |  7 ++-
 2 files changed, 45 insertions(+), 12 deletions(-)

diff --git a/apps/example-app/src/app/examples/22-signal-inputs.component.spec.ts b/apps/example-app/src/app/examples/22-signal-inputs.component.spec.ts
index 6a55e61..113d330 100644
--- a/apps/example-app/src/app/examples/22-signal-inputs.component.spec.ts
+++ b/apps/example-app/src/app/examples/22-signal-inputs.component.spec.ts
@@ -1,4 +1,4 @@
-import { render, screen } from '@testing-library/angular';
+import { render, screen, within } from '@testing-library/angular';
 import { SignalInputComponent } from './22-signal-inputs.component';
 import userEvent from '@testing-library/user-event';
 
@@ -10,7 +10,20 @@ test('works with signal inputs', async () => {
     },
   });
 
-  expect(screen.getByText(/hello world/i)).toBeInTheDocument();
+  const inputValue = within(screen.getByTestId('input-value'));
+  expect(inputValue.getByText(/hello world/i)).toBeInTheDocument();
+});
+
+test('works with computed', async () => {
+  await render(SignalInputComponent, {
+    componentInputs: {
+      greeting: 'Hello',
+      name: 'world',
+    },
+  });
+
+  const computedValue = within(screen.getByTestId('computed-value'));
+  expect(computedValue.getByText(/hello world/i)).toBeInTheDocument();
 });
 
 test('can update signal inputs', async () => {
@@ -21,11 +34,16 @@ test('can update signal inputs', async () => {
     },
   });
 
-  expect(screen.getByText(/hello world/i)).toBeInTheDocument();
+  const inputValue = within(screen.getByTestId('input-value'));
+  const computedValue = within(screen.getByTestId('computed-value'));
+
+  expect(inputValue.getByText(/hello world/i)).toBeInTheDocument();
 
   fixture.componentInstance.name.set('updated');
   // set doesn't trigger change detection within the test, findBy is needed to update the template
-  expect(await screen.findByText(/hello updated/i)).toBeInTheDocument();
+  expect(await inputValue.findByText(/hello updated/i)).toBeInTheDocument();
+  expect(await computedValue.findByText(/hello updated/i)).toBeInTheDocument();
+
   // it's not recommended to access the model directly, but it's possible
   expect(fixture.componentInstance.name()).toBe('updated');
 });
@@ -55,22 +73,29 @@ test('model update also updates the template', async () => {
     },
   });
 
-  expect(screen.getByText(/hello initial/i)).toBeInTheDocument();
+  const inputValue = within(screen.getByTestId('input-value'));
+  const computedValue = within(screen.getByTestId('computed-value'));
+
+  expect(inputValue.getByText(/hello initial/i)).toBeInTheDocument();
+  expect(computedValue.getByText(/hello initial/i)).toBeInTheDocument();
 
   await userEvent.clear(screen.getByRole('textbox'));
   await userEvent.type(screen.getByRole('textbox'), 'updated');
 
-  expect(screen.getByText(/hello updated/i)).toBeInTheDocument();
+  expect(inputValue.getByText(/hello updated/i)).toBeInTheDocument();
+  expect(computedValue.getByText(/hello updated/i)).toBeInTheDocument();
   expect(fixture.componentInstance.name()).toBe('updated');
 
   fixture.componentInstance.name.set('new value');
   // set doesn't trigger change detection within the test, findBy is needed to update the template
-  expect(await screen.findByText(/hello new value/i)).toBeInTheDocument();
+  expect(await inputValue.findByText(/hello new value/i)).toBeInTheDocument();
+  expect(await computedValue.findByText(/hello new value/i)).toBeInTheDocument();
+
   // it's not recommended to access the model directly, but it's possible
   expect(fixture.componentInstance.name()).toBe('new value');
 });
 
-test('works with signal inputs and rerenders', async () => {
+test('works with signal inputs, computed values, and rerenders', async () => {
   const view = await render(SignalInputComponent, {
     componentInputs: {
       greeting: 'Hello',
@@ -78,7 +103,11 @@ test('works with signal inputs and rerenders', async () => {
     },
   });
 
-  expect(screen.getByText(/hello world/i)).toBeInTheDocument();
+  const inputValue = within(screen.getByTestId('input-value'));
+  const computedValue = within(screen.getByTestId('computed-value'));
+
+  expect(inputValue.getByText(/hello world/i)).toBeInTheDocument();
+  expect(computedValue.getByText(/hello world/i)).toBeInTheDocument();
 
   await view.rerender({
     componentInputs: {
@@ -87,5 +116,6 @@ test('works with signal inputs and rerenders', async () => {
     },
   });
 
-  expect(screen.getByText(/bye test/i)).toBeInTheDocument();
+  expect(inputValue.getByText(/bye test/i)).toBeInTheDocument();
+  expect(computedValue.getByText(/bye test/i)).toBeInTheDocument();
 });
diff --git a/apps/example-app/src/app/examples/22-signal-inputs.component.ts b/apps/example-app/src/app/examples/22-signal-inputs.component.ts
index ae1e779..ddc0c90 100644
--- a/apps/example-app/src/app/examples/22-signal-inputs.component.ts
+++ b/apps/example-app/src/app/examples/22-signal-inputs.component.ts
@@ -1,10 +1,11 @@
-import { Component, input, model, output } from '@angular/core';
+import { Component, computed, input, model, output } from '@angular/core';
 import { FormsModule } from '@angular/forms';
 
 @Component({
   selector: 'app-signal-input',
   template: `
-    <div>{{ greetings() }} {{ name() }}</div>
+    <div data-testid="input-value">{{ greetings() }} {{ name() }}</div>
+    <div data-testid="computed-value">{{ greetingMessage() }}</div>
     <button (click)="submitName()">Submit</button>
     <input type="text" [(ngModel)]="name" />
   `,
@@ -18,6 +19,8 @@ export class SignalInputComponent {
   name = model.required<string>();
   submit = output<string>();
 
+  greetingMessage = computed(() => `${this.greetings()} ${this.name()}`);
+
   submitName() {
     this.submit.emit(this.name());
   }

From fbfc9dbe1ca97ac519428bf6cfb15118f2a7d059 Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Fri, 21 Jun 2024 18:51:25 +0200
Subject: [PATCH 07/12] feat: move dtl to peerDeps (#456)

BREAKING CHANGE:

`@testing-library/dom` is now a peer dependency of `@testing-library/angular`.
This means that you need to install `@testing-library/dom` separately.
---
 projects/testing-library/package.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/projects/testing-library/package.json b/projects/testing-library/package.json
index fd3cfac..4aea894 100644
--- a/projects/testing-library/package.json
+++ b/projects/testing-library/package.json
@@ -32,10 +32,10 @@
     "@angular/common": ">= 17.0.0",
     "@angular/platform-browser": ">= 17.0.0",
     "@angular/router": ">= 17.0.0",
-    "@angular/core": ">= 17.0.0"
+    "@angular/core": ">= 17.0.0",
+    "@testing-library/dom": "^10.0.0"
   },
   "dependencies": {
-    "@testing-library/dom": "^10.0.0",
     "tslib": "^2.3.1"
   },
   "publishConfig": {

From 5d7b368d273b2952bc2dc222cf0bb6eac5f2c598 Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Fri, 21 Jun 2024 19:59:34 +0200
Subject: [PATCH 08/12] feat: add DTL as devDependency on ng-add (#457)

---
 .../schematics/ng-add/index.ts                | 20 +++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/projects/testing-library/schematics/ng-add/index.ts b/projects/testing-library/schematics/ng-add/index.ts
index 68b9dfa..24a0a3d 100644
--- a/projects/testing-library/schematics/ng-add/index.ts
+++ b/projects/testing-library/schematics/ng-add/index.ts
@@ -1,11 +1,27 @@
 import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
+import {
+  addPackageJsonDependency,
+  getPackageJsonDependency,
+  NodeDependencyType,
+} from '@schematics/angular/utility/dependencies';
+
+const dtl = '@testing-library/dom';
 
 export default function (): Rule {
-  return (host: Tree, context: SchematicContext) => {
+  return (tree: Tree, context: SchematicContext) => {
+    const dtlDep = getPackageJsonDependency(tree, dtl);
+    if (dtlDep) {
+      context.logger.info(`Skipping installation of '@testing-library/dom' because it's already installed.`);
+    } else {
+      context.logger.info(`Adding '@testing-library/dom' as a dev dependency.`);
+      addPackageJsonDependency(tree, { name: dtl, type: NodeDependencyType.Dev, overwrite: false, version: '^10.0.0' });
+    }
+
     context.logger.info(
       `Correctly installed @testing-library/angular.
 See our docs at https://testing-library.com/docs/angular-testing-library/intro/ to get started.`,
     );
-    return host;
+
+    return tree;
   };
 }

From 563d44b65dc8d02855f24b3d2fa88866970b58f6 Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Fri, 21 Jun 2024 20:11:36 +0200
Subject: [PATCH 09/12] feat: add migration to add DTL as devDependency (#458)

---
 projects/testing-library/package.json         |  2 +-
 .../dtl-as-dev-dependency/index.spec.ts       | 44 +++++++++++++++++++
 .../migrations/dtl-as-dev-dependency/index.ts | 20 +++++++++
 .../schematics/migrations/migration.json      |  3 --
 .../schematics/migrations/migrations.json     | 10 +++++
 projects/testing-library/test-setup.ts        |  4 ++
 .../testing-library/tsconfig.lib.prod.json    |  2 +-
 .../testing-library/tsconfig.schematics.json  |  3 +-
 8 files changed, 82 insertions(+), 6 deletions(-)
 create mode 100644 projects/testing-library/schematics/migrations/dtl-as-dev-dependency/index.spec.ts
 create mode 100644 projects/testing-library/schematics/migrations/dtl-as-dev-dependency/index.ts
 delete mode 100644 projects/testing-library/schematics/migrations/migration.json
 create mode 100644 projects/testing-library/schematics/migrations/migrations.json

diff --git a/projects/testing-library/package.json b/projects/testing-library/package.json
index 4aea894..2852d02 100644
--- a/projects/testing-library/package.json
+++ b/projects/testing-library/package.json
@@ -26,7 +26,7 @@
     "save": "devDependencies"
   },
   "ng-update": {
-    "migrations": "./schematics/migrations/migration.json"
+    "migrations": "./schematics/migrations/migrations.json"
   },
   "peerDependencies": {
     "@angular/common": ">= 17.0.0",
diff --git a/projects/testing-library/schematics/migrations/dtl-as-dev-dependency/index.spec.ts b/projects/testing-library/schematics/migrations/dtl-as-dev-dependency/index.spec.ts
new file mode 100644
index 0000000..a3c0fd1
--- /dev/null
+++ b/projects/testing-library/schematics/migrations/dtl-as-dev-dependency/index.spec.ts
@@ -0,0 +1,44 @@
+import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
+import * as path from 'path';
+import { EmptyTree } from '@angular-devkit/schematics';
+
+test('adds DTL to devDependencies', async () => {
+  const tree = await setup({});
+  const pkg = tree.readContent('package.json');
+
+  expect(pkg).toMatchInlineSnapshot(`
+    "{
+      \\"devDependencies\\": {
+        \\"@testing-library/dom\\": \\"^10.0.0\\"
+      }
+    }"
+  `);
+});
+
+test('ignores if DTL is already listed as a dev dependency', async () => {
+  // eslint-disable-next-line @typescript-eslint/naming-convention
+  const tree = await setup({ devDependencies: { '@testing-library/dom': '^9.0.0' } });
+  const pkg = tree.readContent('package.json');
+
+  expect(pkg).toMatchInlineSnapshot(`"{\\"devDependencies\\":{\\"@testing-library/dom\\":\\"^9.0.0\\"}}"`);
+});
+
+test('ignores if DTL is already listed as a dependency', async () => {
+  // eslint-disable-next-line @typescript-eslint/naming-convention
+  const tree = await setup({ dependencies: { '@testing-library/dom': '^11.0.0' } });
+  const pkg = tree.readContent('package.json');
+
+  expect(pkg).toMatchInlineSnapshot(`"{\\"dependencies\\":{\\"@testing-library/dom\\":\\"^11.0.0\\"}}"`);
+});
+
+async function setup(packageJson: object) {
+  const collectionPath = path.join(__dirname, '../migrations.json');
+  const schematicRunner = new SchematicTestRunner('schematics', collectionPath);
+
+  const tree = new UnitTestTree(new EmptyTree());
+  tree.create('package.json', JSON.stringify(packageJson));
+
+  await schematicRunner.runSchematic(`atl-add-dtl-as-dev-dependency`, {}, tree);
+
+  return tree;
+}
diff --git a/projects/testing-library/schematics/migrations/dtl-as-dev-dependency/index.ts b/projects/testing-library/schematics/migrations/dtl-as-dev-dependency/index.ts
new file mode 100644
index 0000000..1c06e2f
--- /dev/null
+++ b/projects/testing-library/schematics/migrations/dtl-as-dev-dependency/index.ts
@@ -0,0 +1,20 @@
+import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
+import {
+  addPackageJsonDependency,
+  getPackageJsonDependency,
+  NodeDependencyType,
+} from '@schematics/angular/utility/dependencies';
+
+const dtl = '@testing-library/dom';
+
+export default function (): Rule {
+  return async (tree: Tree, context: SchematicContext) => {
+    const dtlDep = getPackageJsonDependency(tree, dtl);
+    if (dtlDep) {
+      context.logger.info(`Skipping installation of '@testing-library/dom' because it's already installed.`);
+    } else {
+      context.logger.info(`Adding '@testing-library/dom' as a peer dependency.`);
+      addPackageJsonDependency(tree, { name: dtl, type: NodeDependencyType.Dev, overwrite: false, version: '^10.0.0' });
+    }
+  };
+}
diff --git a/projects/testing-library/schematics/migrations/migration.json b/projects/testing-library/schematics/migrations/migration.json
deleted file mode 100644
index 63001b4..0000000
--- a/projects/testing-library/schematics/migrations/migration.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "schematics": {}
-}
diff --git a/projects/testing-library/schematics/migrations/migrations.json b/projects/testing-library/schematics/migrations/migrations.json
new file mode 100644
index 0000000..711b7ae
--- /dev/null
+++ b/projects/testing-library/schematics/migrations/migrations.json
@@ -0,0 +1,10 @@
+{
+  "$schema": "../../../../node_modules/@angular-devkit/schematics/collection-schema.json",
+  "schematics": {
+    "atl-add-dtl-as-dev-dependency": {
+      "description": "Add @testing-library/dom as a dev dependency",
+      "version": "17.0.0-beta.3",
+      "factory": "./dtl-as-dev-dependency/index"
+    }
+  }
+}
diff --git a/projects/testing-library/test-setup.ts b/projects/testing-library/test-setup.ts
index 0da94a0..600d085 100644
--- a/projects/testing-library/test-setup.ts
+++ b/projects/testing-library/test-setup.ts
@@ -1,2 +1,6 @@
 import 'jest-preset-angular/setup-jest';
 import '@testing-library/jest-dom';
+import { TextEncoder, TextDecoder } from 'util';
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+Object.assign(global, { TextDecoder, TextEncoder });
diff --git a/projects/testing-library/tsconfig.lib.prod.json b/projects/testing-library/tsconfig.lib.prod.json
index 1f041c9..752ed5e 100644
--- a/projects/testing-library/tsconfig.lib.prod.json
+++ b/projects/testing-library/tsconfig.lib.prod.json
@@ -8,5 +8,5 @@
   "angularCompilerOptions": {
     "compilationMode": "partial"
   },
-  "exclude": ["jest.config.ts"]
+  "exclude": ["src/test-setup.ts", "**/*.spec.ts", "**/*.test.ts", "jest.config.ts"]
 }
diff --git a/projects/testing-library/tsconfig.schematics.json b/projects/testing-library/tsconfig.schematics.json
index 481a34b..1311558 100644
--- a/projects/testing-library/tsconfig.schematics.json
+++ b/projects/testing-library/tsconfig.schematics.json
@@ -13,5 +13,6 @@
     "skipLibCheck": true,
     "sourceMap": false
   },
-  "include": ["schematics/**/*.ts"]
+  "include": ["schematics/**/*.ts"],
+  "exclude": ["src/test-setup.ts", "**/*.spec.ts", "**/*.test.ts", "jest.config.ts"]
 }

From af03c484b377631a9a6c0f8b48f31f08cdd89869 Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Sat, 22 Jun 2024 14:22:42 +0200
Subject: [PATCH 10/12] docs: update docs for v17 (#459)

---
 README.md | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/README.md b/README.md
index 2ba3f84..7ab5040 100644
--- a/README.md
+++ b/README.md
@@ -147,10 +147,18 @@ describe('Counter', () => {
 ## Installation
 
 This module is distributed via [npm][npm] which is bundled with [node][node] and
-should be installed as one of your project's `devDependencies`:
+should be installed as one of your project's `devDependencies`.
+Starting from ATL version 17, you'll also need to install `@testing-library/dom`:
 
 ```bash
-npm install @testing-library/angular --save-dev
+npm install --save-dev @testing-library/angular @testing-library/dom
+```
+
+Or, you can use the `ng add` command.
+This includes the installation of `@testing-library/dom`.
+
+```bash
+ng add @testing-library/angular
 ```
 
 You may also be interested in installing `jest-dom` so you can use
@@ -160,14 +168,14 @@ You may also be interested in installing `jest-dom` so you can use
 
 ## Version compatibility
 
-| Angular | Angular Testing Library |
-| ------- | ----------------------- |
-| 18.x    | 16.x, 15.x, 14.x, 13.x  |
-| 17.x    | 16.x, 15.x, 14.x, 13.x  |
-| 16.x    | 14.x, 13.x              |
-| >= 15.1 | 14.x, 13.x              |
-| < 15.1  | 12.x, 11.x              |
-| 14.x    | 12.x, 11.x              |
+| Angular | Angular Testing Library      |
+| ------- | ---------------------------- |
+| 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                   |
+| >= 15.1 | 14.x, 13.x                   |
+| < 15.1  | 12.x, 11.x                   |
+| 14.x    | 12.x, 11.x                   |
 
 ## Guiding Principles
 

From 68e6b84cf0b61e79fc74a5b3afedbcc5b9e5e785 Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Sat, 22 Jun 2024 15:20:44 +0200
Subject: [PATCH 11/12] fix: schematics output folder (#461)

---
 projects/testing-library/tsconfig.schematics.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/projects/testing-library/tsconfig.schematics.json b/projects/testing-library/tsconfig.schematics.json
index 1311558..c011851 100644
--- a/projects/testing-library/tsconfig.schematics.json
+++ b/projects/testing-library/tsconfig.schematics.json
@@ -8,7 +8,7 @@
     "esModuleInterop": true,
     "resolveJsonModule": true,
     "forceConsistentCasingInFileNames": true,
-    "outDir": "../../dist/@testing-library/angular/schematics/ng-add",
+    "outDir": "../../dist/@testing-library/angular/schematics",
     "removeComments": true,
     "skipLibCheck": true,
     "sourceMap": false

From 0652a14973f3a610e52ae9f67b0cb16148bb5ddf Mon Sep 17 00:00:00 2001
From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com>
Date: Mon, 24 Jun 2024 15:40:37 +0200
Subject: [PATCH 12/12] docs: reword installation steps (#463)

---
 README.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 7ab5040..ce2e906 100644
--- a/README.md
+++ b/README.md
@@ -148,14 +148,14 @@ describe('Counter', () => {
 
 This module is distributed via [npm][npm] which is bundled with [node][node] and
 should be installed as one of your project's `devDependencies`.
-Starting from ATL version 17, you'll also need to install `@testing-library/dom`:
+Starting from ATL version 17, you also need to install `@testing-library/dom`:
 
 ```bash
 npm install --save-dev @testing-library/angular @testing-library/dom
 ```
 
 Or, you can use the `ng add` command.
-This includes the installation of `@testing-library/dom`.
+This sets up your project to use Angular Testing Library, which also includes the installation of `@testing-library/dom`.
 
 ```bash
 ng add @testing-library/angular