diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 51e4fa6f..db976dcf 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-18-bullseye", + "image": "mcr.microsoft.com/devcontainers/typescript-node:0-20-bullseye", // Features to add to the dev container. More info: https://containers.dev/features. "features": { diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c708307..78880ebe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,19 +22,18 @@ jobs: strategy: matrix: - node-version: ${{ fromJSON((github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') && '[16]' || '[16, 18]') }} + node-version: ${{ fromJSON((github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') && '[20]' || '[16, 18, 20]') }} os: ${{ fromJSON((github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') && '["ubuntu-latest"]' || '["ubuntu-latest", "windows-latest"]') }} runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: use Node.js ${{ matrix.node-version }} on ${{ matrix.os }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: install - # ng-mocks needs to add ng 17 to their peer dependencies - run: npm install --force + run: npm install - name: build run: npm run build -- --skip-nx-cache - name: test diff --git a/.node-version b/.node-version index b6a7d89c..914d1a73 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -16 +20.9 \ No newline at end of file diff --git a/README.md b/README.md index 3aa070fa..569dff2c 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,12 @@

@testing-library/angular

- - hedgehog - +Octopus with the Angular logo

Simple and complete Angular testing utilities that encourage good testing practices.

diff --git a/apps/example-app-karma/project.json b/apps/example-app-karma/project.json index bab8526c..733fe68d 100644 --- a/apps/example-app-karma/project.json +++ b/apps/example-app-karma/project.json @@ -53,13 +53,6 @@ }, "lint": { "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": [ - "apps/example-app-karma/**/*.ts", - "apps/example-app-karma/**/*.html", - "apps/example-app-karma/src/**/*.html" - ] - }, "outputs": ["{options.outputFile}"] }, "test": { diff --git a/apps/example-app/project.json b/apps/example-app/project.json index 2122cfc3..8af56975 100644 --- a/apps/example-app/project.json +++ b/apps/example-app/project.json @@ -60,9 +60,6 @@ }, "lint": { "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": ["apps/example-app/**/*.ts", "apps/example-app/**/*.html", "apps/example-app/src/**/*.html"] - }, "outputs": ["{options.outputFile}"] }, "test": { diff --git a/other/hedgehog.png b/other/hedgehog.png deleted file mode 100644 index 3d84640a..00000000 Binary files a/other/hedgehog.png and /dev/null differ diff --git a/other/logo-icon.svg b/other/logo-icon.svg new file mode 100644 index 00000000..48d2878c --- /dev/null +++ b/other/logo-icon.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/other/logo-transparent.svg b/other/logo-transparent.svg new file mode 100644 index 00000000..795caf7c --- /dev/null +++ b/other/logo-transparent.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/other/logo.jpg b/other/logo.jpg new file mode 100644 index 00000000..4d627712 Binary files /dev/null and b/other/logo.jpg differ diff --git a/other/logo.png b/other/logo.png new file mode 100644 index 00000000..599227aa Binary files /dev/null and b/other/logo.png differ diff --git a/other/logo.svg b/other/logo.svg new file mode 100644 index 00000000..d0f25fe6 --- /dev/null +++ b/other/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/package.json b/package.json index d8aa9a8d..49500260 100644 --- a/package.json +++ b/package.json @@ -28,63 +28,62 @@ "prepare": "git config core.hookspath .githooks" }, "dependencies": { - "@angular/animations": "17.0.2", - "@angular/cdk": "17.0.0", - "@angular/common": "17.0.2", - "@angular/compiler": "17.0.2", - "@angular/core": "17.0.2", - "@angular/material": "17.0.0", - "@angular/platform-browser": "17.0.2", - "@angular/platform-browser-dynamic": "17.0.2", - "@angular/router": "17.0.2", - "@ngrx/store": "17.0.0-rc.0", - "@nx/angular": "17.1.1", + "@angular/animations": "17.1.0", + "@angular/cdk": "17.1.0", + "@angular/common": "17.1.0", + "@angular/compiler": "17.1.0", + "@angular/core": "17.1.0", + "@angular/material": "17.1.0", + "@angular/platform-browser": "17.1.0", + "@angular/platform-browser-dynamic": "17.1.0", + "@angular/router": "17.1.0", + "@ngrx/store": "17.1.0", + "@nx/angular": "17.2.8", "@testing-library/dom": "^9.0.0", "rxjs": "7.8.0", "tslib": "~2.3.1", "zone.js": "0.14.2" }, "devDependencies": { - "@angular-devkit/build-angular": "17.0.0", - "@angular-devkit/core": "17.0.0", - "@angular-devkit/schematics": "17.0.0", + "@angular-devkit/build-angular": "17.1.0", + "@angular-devkit/core": "17.1.0", + "@angular-devkit/schematics": "17.1.0", "@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.0.0", - "@angular/compiler-cli": "17.0.2", - "@angular/forms": "17.0.2", - "@angular/language-service": "17.0.2", - "@nx/eslint-plugin": "17.1.1", - "@nx/jest": "17.1.1", - "@nx/node": "17.1.1", - "@nx/plugin": "17.1.1", - "@nx/workspace": "17.1.1", - "@schematics/angular": "17.0.0", + "@angular/cli": "~17.1.0", + "@angular/compiler-cli": "17.1.0", + "@angular/forms": "17.1.0", + "@angular/language-service": "17.1.0", + "@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.1.0", "@testing-library/jasmine-dom": "^1.2.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/user-event": "^14.4.3", "@types/jasmine": "4.3.1", "@types/jest": "29.5.1", - "@types/node": "20.1.4", + "@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", "cpy-cli": "^3.1.1", - "eslint": "8.46.0", + "eslint": "8.48.0", "eslint-config-prettier": "9.0.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", "jasmine-core": "4.2.0", "jasmine-spec-reporter": "7.0.0", "jest": "29.5.0", "jest-environment-jsdom": "29.5.0", - "jest-preset-angular": "13.1.3", + "jest-preset-angular": "13.1.6", "karma": "6.4.0", "karma-chrome-launcher": "^3.1.0", "karma-coverage": "^2.2.1", @@ -92,8 +91,8 @@ "karma-jasmine-html-reporter": "2.0.0", "lint-staged": "^12.1.6", "ng-mocks": "^14.11.0", - "ng-packagr": "17.0.0", - "nx": "17.1.1", + "ng-packagr": "17.1.0", + "nx": "17.2.8", "postcss": "^8.4.5", "postcss-import": "14.1.0", "postcss-preset-env": "7.5.0", @@ -104,6 +103,6 @@ "ts-jest": "29.1.0", "ts-node": "10.9.1", "typescript": "5.2.2", - "@nx/eslint": "17.1.1" + "@nx/eslint": "17.2.8" } } diff --git a/projects/testing-library/.eslintrc.json b/projects/testing-library/.eslintrc.json index a3f4c7c1..5a9d6905 100644 --- a/projects/testing-library/.eslintrc.json +++ b/projects/testing-library/.eslintrc.json @@ -5,7 +5,15 @@ { "files": ["*.ts"], "rules": { - "@typescript-eslint/ban-ts-comment": "off" + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_", + "caughtErrorsIgnorePattern": "^_" + } + ] } }, { diff --git a/projects/testing-library/project.json b/projects/testing-library/project.json index d54c5f78..b91e85c5 100644 --- a/projects/testing-library/project.json +++ b/projects/testing-library/project.json @@ -23,9 +23,6 @@ }, "lint": { "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": ["projects/testing-library/**/*.ts", "projects/testing-library/**/*.html"] - }, "outputs": ["{options.outputFile}"] }, "build": { diff --git a/projects/testing-library/src/lib/models.ts b/projects/testing-library/src/lib/models.ts index 257bef0c..fad33947 100644 --- a/projects/testing-library/src/lib/models.ts +++ b/projects/testing-library/src/lib/models.ts @@ -1,5 +1,5 @@ import { Type, DebugElement } from '@angular/core'; -import { ComponentFixture, DeferBlockState, TestBed } from '@angular/core/testing'; +import {ComponentFixture, DeferBlockBehavior, DeferBlockState, TestBed} from '@angular/core/testing'; import { Routes } from '@angular/router'; import { BoundFunction, Queries, queries, Config as dtlConfig, PrettyDOMOptions } from '@testing-library/dom'; @@ -369,7 +369,17 @@ export interface RenderComponentOptions void; + /** + * @description + * Set the initial state of a deferrable block. + */ deferBlockStates?: DeferBlockState | { deferBlockState: DeferBlockState; deferBlockIndex: number }[]; + + /** + * @description + * Set the defer blocks behavior. + */ + deferBlockBehavior?: DeferBlockBehavior } export interface ComponentOverride { diff --git a/projects/testing-library/src/lib/testing-library.ts b/projects/testing-library/src/lib/testing-library.ts index 1be2f222..2b3ac757 100644 --- a/projects/testing-library/src/lib/testing-library.ts +++ b/projects/testing-library/src/lib/testing-library.ts @@ -1,32 +1,32 @@ import { + ApplicationInitStatus, ChangeDetectorRef, Component, - Type, + isStandalone, NgZone, - SimpleChange, OnChanges, + SimpleChange, SimpleChanges, - ApplicationInitStatus, - isStandalone, + Type, } from '@angular/core'; -import { ComponentFixture, DeferBlockState, TestBed, tick } from '@angular/core/testing'; -import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { NavigationExtras, Router } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; +import {ComponentFixture, DeferBlockState, TestBed, tick} from '@angular/core/testing'; +import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {NavigationExtras, Router} from '@angular/router'; +import {RouterTestingModule} from '@angular/router/testing'; +import type {BoundFunctions, Queries} from '@testing-library/dom'; import { + configure as dtlConfigure, getQueriesForElement as dtlGetQueriesForElement, prettyDOM as dtlPrettyDOM, + queries as dtlQueries, + screen as dtlScreen, waitFor as dtlWaitFor, waitForElementToBeRemoved as dtlWaitForElementToBeRemoved, - screen as dtlScreen, - within as dtlWithin, waitForOptions as dtlWaitForOptions, - configure as dtlConfigure, - queries as dtlQueries, + within as dtlWithin, } from '@testing-library/dom'; -import type { Queries, BoundFunctions } from '@testing-library/dom'; -import { RenderComponentOptions, RenderTemplateOptions, RenderResult, ComponentOverride } from './models'; -import { getConfig } from './config'; +import {ComponentOverride, RenderComponentOptions, RenderResult, RenderTemplateOptions} from './models'; +import {getConfig} from './config'; const mountedFixtures = new Set>(); const safeInject = TestBed.inject || TestBed.get; @@ -66,6 +66,7 @@ export async function render( defaultImports = [], initialRoute = '', deferBlockStates = undefined, + deferBlockBehavior = undefined, configureTestBed = () => { /* noop*/ }, @@ -94,6 +95,7 @@ export async function render( }), providers: [...providers], schemas: [...schemas], + deferBlockBehavior: deferBlockBehavior as any }); overrideComponentImports(sut, componentImports); overrideChildComponentProviders(childComponentOverrides); diff --git a/projects/testing-library/tests/defer-blocks.spec.ts b/projects/testing-library/tests/defer-blocks.spec.ts index 9c2985b0..147c5c73 100644 --- a/projects/testing-library/tests/defer-blocks.spec.ts +++ b/projects/testing-library/tests/defer-blocks.spec.ts @@ -1,6 +1,7 @@ -import { Component } from '@angular/core'; -import { DeferBlockState } from '@angular/core/testing'; -import { render, screen } from '../src/public_api'; +import {Component} from '@angular/core'; +import {DeferBlockBehavior, DeferBlockState} from '@angular/core/testing'; +import {render, screen} from '../src/public_api'; +import {fireEvent} from "@testing-library/dom"; test('renders a defer block in different states using the official API', async () => { const { fixture } = await render(FixtureComponent); @@ -28,6 +29,26 @@ test('renders a defer block in different states using ATL', async () => { expect(screen.queryByText(/load/i)).not.toBeInTheDocument(); }); +test('renders a defer block in different states using DeferBlockBehavior.Playthrough', async () => { + await render(FixtureComponent, { + deferBlockBehavior: DeferBlockBehavior.Playthrough + }); + + expect(await screen.findByText(/loading/i)).toBeInTheDocument(); + expect(await screen.findByText(/Defer block content/i)).toBeInTheDocument(); +}); + +test('renders a defer block in different states using DeferBlockBehavior.Playthrough event', async () => { + await render(FixtureComponentWithEvents, { + deferBlockBehavior: DeferBlockBehavior.Playthrough + }); + + const button = screen.getByRole('button', {name: /click/i}); + fireEvent.click(button) + + expect(screen.getByText(/empty defer block/i)).toBeInTheDocument(); +}); + test('renders a defer block initially in the loading state', async () => { await render(FixtureComponent, { deferBlockStates: DeferBlockState.Loading, @@ -65,3 +86,14 @@ test('renders a defer block in an initial state using the array syntax', async ( `, }) class FixtureComponent {} + +@Component({ + template: ` + + @defer(on interaction(trigger)) { +
empty defer block
+ } + `, +}) +class FixtureComponentWithEvents {} + diff --git a/projects/testing-library/tests/issues/issue-422-view-already-destroyed.spec.ts b/projects/testing-library/tests/issues/issue-422-view-already-destroyed.spec.ts new file mode 100644 index 00000000..05e6e11a --- /dev/null +++ b/projects/testing-library/tests/issues/issue-422-view-already-destroyed.spec.ts @@ -0,0 +1,28 @@ +import { Component, ElementRef } from '@angular/core'; +import { NgIf } from '@angular/common'; +import { render } from '../../src/public_api'; + +test('declaration specific dependencies should be available for components', async () => { + @Component({ + selector: 'atl-test', + standalone: true, + template: `
Test
`, + }) + class TestComponent { + constructor(_elementRef: ElementRef) {} + } + + await expect(async () => await render(TestComponent)).not.toThrow(); +}); + +test('standalone directives imported in standalone components', async () => { + @Component({ + selector: 'atl-test', + standalone: true, + imports: [NgIf], + template: `
Test
`, + }) + class TestComponent {} + + await render(TestComponent); +}); diff --git a/projects/vscode-atl-render/package.json b/projects/vscode-atl-render/package.json index a6462d92..d5bcbe7a 100644 --- a/projects/vscode-atl-render/package.json +++ b/projects/vscode-atl-render/package.json @@ -3,7 +3,7 @@ "displayName": "Angular Testing Library Render Highlighting", "description": "HTML highlighting in ATL the render method", "version": "0.0.3", - "icon": "other/hedgehog.png", + "icon": "other/logo.png", "publisher": "timdeschryver", "license": "MIT", "repository": {