From 45edf2f6fbf95be972eca21a2183747120cc6228 Mon Sep 17 00:00:00 2001 From: John Dengis Date: Tue, 7 Jun 2022 02:45:04 -0700 Subject: [PATCH 1/4] feat: upgrade Angular 14 - update @angular/core - update @angular/cli - updated @angular/material - fix standalone components --- apps/example-app/src/app/examples/03-forms.ts | 4 +- .../app/examples/04-forms-with-material.ts | 4 +- .../examples/19-standalone-component.spec.ts | 10 +++++ .../app/examples/19-standalone-component.ts | 8 ++++ package.json | 35 ++++++++-------- projects/testing-library/package.json | 8 ++-- .../src/lib/testing-library.ts | 42 ++++++++++--------- 7 files changed, 67 insertions(+), 44 deletions(-) create mode 100644 apps/example-app/src/app/examples/19-standalone-component.spec.ts create mode 100644 apps/example-app/src/app/examples/19-standalone-component.ts diff --git a/apps/example-app/src/app/examples/03-forms.ts b/apps/example-app/src/app/examples/03-forms.ts index f68766e4..df861a3c 100644 --- a/apps/example-app/src/app/examples/03-forms.ts +++ b/apps/example-app/src/app/examples/03-forms.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { FormBuilder, Validators } from '@angular/forms'; +import { UntypedFormBuilder, Validators } from '@angular/forms'; @Component({ selector: 'app-fixture', @@ -41,7 +41,7 @@ export class FormsComponent { color: ['', Validators.required], }); - constructor(private formBuilder: FormBuilder) {} + constructor(private formBuilder: UntypedFormBuilder) {} get formErrors() { return Object.keys(this.form.controls) diff --git a/apps/example-app/src/app/examples/04-forms-with-material.ts b/apps/example-app/src/app/examples/04-forms-with-material.ts index f27f4f1e..ed33dd3f 100644 --- a/apps/example-app/src/app/examples/04-forms-with-material.ts +++ b/apps/example-app/src/app/examples/04-forms-with-material.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { FormBuilder, Validators } from '@angular/forms'; +import { UntypedFormBuilder, Validators } from '@angular/forms'; @Component({ selector: 'app-fixture', @@ -66,7 +66,7 @@ export class MaterialFormsComponent { color: [null, Validators.required], }); - constructor(private formBuilder: FormBuilder) {} + constructor(private formBuilder: UntypedFormBuilder) {} get colorControlDisplayValue(): string | undefined { const selectedId = this.form.get('color')?.value; diff --git a/apps/example-app/src/app/examples/19-standalone-component.spec.ts b/apps/example-app/src/app/examples/19-standalone-component.spec.ts new file mode 100644 index 00000000..73a86ab2 --- /dev/null +++ b/apps/example-app/src/app/examples/19-standalone-component.spec.ts @@ -0,0 +1,10 @@ +import { render, screen } from "@testing-library/angular"; +import { StandaloneComponent } from "./19-standalone-component"; + +test('is possible to render a standalone component', async () => { + await render(StandaloneComponent); + + const content = screen.getByTestId('standalone'); + + expect(content).toHaveTextContent("Standalone Component") +}); diff --git a/apps/example-app/src/app/examples/19-standalone-component.ts b/apps/example-app/src/app/examples/19-standalone-component.ts new file mode 100644 index 00000000..1807c544 --- /dev/null +++ b/apps/example-app/src/app/examples/19-standalone-component.ts @@ -0,0 +1,8 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: 'app-standalone', + template: `
Standalone Component
`, + standalone: true, +}) +export class StandaloneComponent {} diff --git a/package.json b/package.json index 977d7a88..95c5c980 100644 --- a/package.json +++ b/package.json @@ -28,15 +28,15 @@ "prepare": "git config core.hookspath .githooks" }, "dependencies": { - "@angular/animations": "13.1.1", - "@angular/cdk": "13.1.1", - "@angular/common": "13.1.1", - "@angular/compiler": "13.1.1", - "@angular/core": "13.1.1", - "@angular/material": "13.1.1", - "@angular/platform-browser": "13.1.1", - "@angular/platform-browser-dynamic": "13.1.1", - "@angular/router": "13.1.1", + "@angular/animations": "14.0.0", + "@angular/cdk": "14.0.0", + "@angular/common": "14.0.0", + "@angular/compiler": "14.0.0", + "@angular/core": "14.0.0", + "@angular/material": "14.0.0", + "@angular/platform-browser": "14.0.0", + "@angular/platform-browser-dynamic": "14.0.0", + "@angular/router": "14.0.0", "@ngrx/store": "13.0.2", "@nrwl/angular": "13.4.3", "@nrwl/nx-cloud": "13.0.2", @@ -46,14 +46,14 @@ "zone.js": "~0.11.4" }, "devDependencies": { - "@angular-devkit/build-angular": "13.1.2", + "@angular-devkit/build-angular": "14.0.0", "@angular-eslint/eslint-plugin": "13.0.1", "@angular-eslint/eslint-plugin-template": "13.0.1", "@angular-eslint/template-parser": "13.0.1", - "@angular/cli": "13.1.2", - "@angular/compiler-cli": "13.1.1", - "@angular/forms": "13.1.1", - "@angular/language-service": "13.1.1", + "@angular/cli": "14.0.0", + "@angular/compiler-cli": "14.0.0", + "@angular/forms": "14.0.0", + "@angular/language-service": "14.0.0", "@nrwl/cli": "13.4.3", "@nrwl/eslint-plugin-nx": "13.4.3", "@nrwl/jest": "13.4.3", @@ -79,8 +79,9 @@ "eslint-plugin-testing-library": "~5.0.1", "jasmine-core": "^3.10.1", "jasmine-spec-reporter": "^7.0.0", - "jest": "27.4.7", - "jest-preset-angular": "11.0.1", + "jest": "28.0.0", + "jest-environment-jsdom": "^28.1.1", + "jest-preset-angular": "12.1.0", "karma": "^6.3.9", "karma-chrome-launcher": "^3.1.0", "karma-jasmine": "^4.0.1", @@ -96,6 +97,6 @@ "semantic-release": "^18.0.0", "ts-jest": "27.1.2", "ts-node": "~10.4.0", - "typescript": "4.5.4" + "typescript": "4.7.2" } } diff --git a/projects/testing-library/package.json b/projects/testing-library/package.json index 7d14c654..59ac5d28 100644 --- a/projects/testing-library/package.json +++ b/projects/testing-library/package.json @@ -29,10 +29,10 @@ "migrations": "./schematics/migrations/migration.json" }, "peerDependencies": { - "@angular/common": ">= 13.0.0", - "@angular/platform-browser": ">= 13.0.0", - "@angular/router": ">= 13.0.0", - "@angular/core": ">= 13.0.0", + "@angular/common": ">= 14.0.0", + "@angular/platform-browser": ">= 14.0.0", + "@angular/router": ">= 14.0.0", + "@angular/core": ">= 14.0.0", "rxjs": ">= 7.4.0" }, "dependencies": { diff --git a/projects/testing-library/src/lib/testing-library.ts b/projects/testing-library/src/lib/testing-library.ts index baa2dce9..07fdf71d 100644 --- a/projects/testing-library/src/lib/testing-library.ts +++ b/projects/testing-library/src/lib/testing-library.ts @@ -7,6 +7,7 @@ import { OnChanges, SimpleChanges, ApplicationInitStatus, + ɵisStandalone, } from '@angular/core'; import { ComponentFixture, TestBed, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; @@ -76,7 +77,7 @@ export async function render( excludeComponentDeclaration, wrapper, }), - imports: addAutoImports({ + imports: addAutoImports(sut,{ imports: imports.concat(defaultImports), routes, }), @@ -128,23 +129,23 @@ export async function render( const [path, params] = (basePath + href).split('?'); const queryParams = params ? params.split('&').reduce((qp, q) => { - const [key, value] = q.split('='); - const currentValue = qp[key]; - if (typeof currentValue === 'undefined') { - qp[key] = value; - } else if (Array.isArray(currentValue)) { - qp[key] = [...currentValue, value]; - } else { - qp[key] = [currentValue, value]; - } - return qp; - }, {} as Record) + const [key, value] = q.split('='); + const currentValue = qp[key]; + if (typeof currentValue === 'undefined') { + qp[key] = value; + } else if (Array.isArray(currentValue)) { + qp[key] = [...currentValue, value]; + } else { + qp[key] = [currentValue, value]; + } + return qp; + }, {} as Record) : undefined; const navigateOptions: NavigationExtras | undefined = queryParams ? { - queryParams, - } + queryParams, + } : undefined; const doNavigate = () => { @@ -296,11 +297,14 @@ function addAutoDeclarations( return [...declarations, wrapper]; } - const components = () => (excludeComponentDeclaration ? [] : [sut]); + const components = () => (excludeComponentDeclaration || ɵisStandalone(sut) ? [] : [sut]); return [...declarations, ...components()]; } -function addAutoImports({ imports = [], routes }: Pick, 'imports' | 'routes'>) { +function addAutoImports( + sut: Type | string, + { imports = [], routes }: Pick, 'imports' | 'routes'>, +) { const animations = () => { const animationIsDefined = imports.indexOf(NoopAnimationsModule) > -1 || imports.indexOf(BrowserAnimationsModule) > -1; @@ -308,8 +312,8 @@ function addAutoImports({ imports = [], routes }: Pick (routes ? [RouterTestingModule.withRoutes(routes)] : []); - - return [...imports, ...animations(), ...routing()]; + const components = () => (typeof sut !== 'string' && ɵisStandalone(sut) ? [sut] : []); + return [...imports, ...components(), ...animations(), ...routing()]; } /** @@ -394,7 +398,7 @@ if (typeof process === 'undefined' || !process.env?.ATL_SKIP_AUTO_CLEANUP) { } @Component({ selector: 'atl-wrapper-component', template: '' }) -class WrapperComponent {} +class WrapperComponent { } /** * Wrap findBy queries to poke the Angular change detection cycle From a70bedafb0d617b4b4863f918db2b674643c4bf5 Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Wed, 8 Jun 2022 10:48:30 +0200 Subject: [PATCH 2/4] chore: update deps --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 95c5c980..818f0dd6 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "@angular/platform-browser": "14.0.0", "@angular/platform-browser-dynamic": "14.0.0", "@angular/router": "14.0.0", - "@ngrx/store": "13.0.2", + "@ngrx/store": "14.0.0-beta.0", "@nrwl/angular": "13.4.3", "@nrwl/nx-cloud": "13.0.2", "@testing-library/dom": "^8.11.1", @@ -79,7 +79,7 @@ "eslint-plugin-testing-library": "~5.0.1", "jasmine-core": "^3.10.1", "jasmine-spec-reporter": "^7.0.0", - "jest": "28.0.0", + "jest": "28.1.1", "jest-environment-jsdom": "^28.1.1", "jest-preset-angular": "12.1.0", "karma": "^6.3.9", @@ -87,7 +87,7 @@ "karma-jasmine": "^4.0.1", "karma-jasmine-html-reporter": "^1.7.0", "lint-staged": "^12.1.6", - "ng-packagr": "13.1.2", + "ng-packagr": "14.0.0", "postcss": "^8.4.5", "postcss-import": "^14.0.2", "postcss-preset-env": "^7.2.0", @@ -95,7 +95,7 @@ "prettier": "^2.4.1", "rimraf": "^3.0.2", "semantic-release": "^18.0.0", - "ts-jest": "27.1.2", + "ts-jest": "28.0.4", "ts-node": "~10.4.0", "typescript": "4.7.2" } From b204303f9a6853ae8354ba1b6584e25bca60c39e Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Wed, 8 Jun 2022 11:37:29 +0200 Subject: [PATCH 3/4] ci: remove Node.js v12 support (Angular 14) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ecfd98d..69e0fda3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: build_test_release: strategy: matrix: - node-version: ${{ fromJSON((github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') && '[16]' || '[12,14,16]') }} + node-version: ${{ fromJSON((github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') && '[16]' || '[14,16]') }} os: ${{ fromJSON((github.ref == 'refs/heads/main' || github.ref == 'refs/heads/beta') && '["ubuntu-latest"]' || '["ubuntu-latest", "windows-latest"]') }} runs-on: ${{ matrix.os }} From 50e6bb8be646cb1a853e99bd82f53dda0ba450e9 Mon Sep 17 00:00:00 2001 From: John Dengis Date: Wed, 8 Jun 2022 10:51:09 -0700 Subject: [PATCH 4/4] test: add a standalone component test with child --- .../examples/19-standalone-component.spec.ts | 18 +++++++++++++++--- .../app/examples/19-standalone-component.ts | 17 +++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/apps/example-app/src/app/examples/19-standalone-component.spec.ts b/apps/example-app/src/app/examples/19-standalone-component.spec.ts index 73a86ab2..b21b3d7a 100644 --- a/apps/example-app/src/app/examples/19-standalone-component.spec.ts +++ b/apps/example-app/src/app/examples/19-standalone-component.spec.ts @@ -1,10 +1,22 @@ -import { render, screen } from "@testing-library/angular"; -import { StandaloneComponent } from "./19-standalone-component"; +import { render, screen } from '@testing-library/angular'; +import { StandaloneComponent, StandaloneWithChildComponent } from './19-standalone-component'; test('is possible to render a standalone component', async () => { await render(StandaloneComponent); const content = screen.getByTestId('standalone'); - expect(content).toHaveTextContent("Standalone Component") + expect(content).toHaveTextContent('Standalone Component'); +}); + +test('is possibl to render a standalone component with a child', async () => { + await render(StandaloneWithChildComponent, { + componentProperties: { name: 'Bob' }, + }); + + const childContent = screen.getByTestId('standalone'); + expect(childContent).toHaveTextContent('Standalone Component'); + + expect(screen.getByText('Hi Bob')).toBeInTheDocument(); + expect(screen.getByText('This has a child')).toBeInTheDocument(); }); diff --git a/apps/example-app/src/app/examples/19-standalone-component.ts b/apps/example-app/src/app/examples/19-standalone-component.ts index 1807c544..e203991d 100644 --- a/apps/example-app/src/app/examples/19-standalone-component.ts +++ b/apps/example-app/src/app/examples/19-standalone-component.ts @@ -1,8 +1,21 @@ -import { Component } from "@angular/core"; +import { Component, Input } from '@angular/core'; @Component({ selector: 'app-standalone', template: `
Standalone Component
`, standalone: true, }) -export class StandaloneComponent {} +export class StandaloneComponent { } + +@Component({ + selector: 'app-standalone-with-child', + template: `

Hi {{ name }}

+

This has a child

+ `, + standalone: true, + imports: [StandaloneComponent], +}) +export class StandaloneWithChildComponent { + @Input() + name?: string; +}