From b028e11db5e0bc75450d31099c66a46784339b56 Mon Sep 17 00:00:00 2001 From: David LJ Date: Mon, 21 Oct 2024 17:28:48 +0200 Subject: [PATCH] test: refactor `ng-add` to make it easier to add moar tests (#974) --- .../ngx-meta/schematics/ng-add/index.spec.ts | 76 ++++++------------- .../get-app-config-or-app-module-content.ts | 10 +++ .../ng-add/testing/provider-test-case.ts | 18 +++++ .../testing/should-add-root-provider.ts | 26 +++++++ .../schematics/testing/create-test-app.ts | 19 +++++ .../schematics/testing/get-file-content.ts | 12 +++ .../schematics/testing/regexp-escape.ts | 4 + .../schematics/testing/strip-whitespace.ts | 2 + 8 files changed, 113 insertions(+), 54 deletions(-) create mode 100644 projects/ngx-meta/schematics/ng-add/testing/get-app-config-or-app-module-content.ts create mode 100644 projects/ngx-meta/schematics/ng-add/testing/provider-test-case.ts create mode 100644 projects/ngx-meta/schematics/ng-add/testing/should-add-root-provider.ts create mode 100644 projects/ngx-meta/schematics/testing/create-test-app.ts create mode 100644 projects/ngx-meta/schematics/testing/get-file-content.ts create mode 100644 projects/ngx-meta/schematics/testing/regexp-escape.ts create mode 100644 projects/ngx-meta/schematics/testing/strip-whitespace.ts diff --git a/projects/ngx-meta/schematics/ng-add/index.spec.ts b/projects/ngx-meta/schematics/ng-add/index.spec.ts index a2e7da9d..2e244336 100644 --- a/projects/ngx-meta/schematics/ng-add/index.spec.ts +++ b/projects/ngx-meta/schematics/ng-add/index.spec.ts @@ -1,10 +1,11 @@ import { SchematicTestRunner } from '@angular-devkit/schematics/testing' import { Tree } from '@angular-devkit/schematics' -import { beforeEach, describe, expect, it } from '@jest/globals' +import { beforeEach, describe } from '@jest/globals' import { join } from 'path' import { Schema as NgAddSchema } from './schema' -import { Schema as NgNewSchema } from '@schematics/angular/ng-new/schema' -import { LIB_NAME } from '../testing/lib-name' +import { ProviderTestCase } from './testing/provider-test-case' +import { shouldAddRootProvider } from './testing/should-add-root-provider' +import { createTestApp } from '../testing/create-test-app' // https://github.com/angular/components/blob/18.2.8/src/cdk/schematics/ng-add/index.spec.ts // https://github.com/angular/components/blob/18.2.8/src/material/schematics/ng-add/index.spec.ts @@ -24,6 +25,12 @@ describe('ng-add schematic', () => { join(__dirname, '..', 'collection.json'), ) }) + + const CORE_PROVIDER = new ProviderTestCase({ + name: 'core', + symbol: 'provideNgxMetaCore', + }) + ;([true, false] as const).forEach((standalone) => { const appKind = standalone ? 'standalone' : 'module-based' describe(`when the app is ${appKind}`, () => { @@ -34,58 +41,19 @@ describe('ng-add schematic', () => { }) }) - it('should add core provider', async () => { - const tree = await runner.runSchematic( - SCHEMATIC_NAME, - defaultOptions, - appTree, - ) - const appConfigOrAppModule = getAppConfigOrAppModuleContents( - tree, - standalone, - ) - expect(appConfigOrAppModule).toContain( - `import { provideNgxMetaCore } from '${LIB_NAME}/core`, - ) - expect(stripWhitespace(appConfigOrAppModule)).toMatch( - /providers:\[.*provideNgxMetaCore\(\).*]/, - ) + describe('by default', () => { + let tree: Tree + + beforeEach(async () => { + tree = await runner.runSchematic( + SCHEMATIC_NAME, + defaultOptions, + appTree, + ) + }) + + shouldAddRootProvider(CORE_PROVIDER, () => tree, standalone) }) }) }) }) - -// https://github.com/FortAwesome/angular-fontawesome/blob/0.15.0/projects/schematics/src/ng-add/index.spec.ts#L107 -// https://github.com/angular/components/blob/18.2.8/src/cdk/schematics/testing/test-app.ts -const createTestApp = async ( - runner: SchematicTestRunner, - options: Omit & Partial>, -) => { - return runner.runExternalSchematic( - '@schematics/angular', - 'ng-new', - { - version: '9.0.0', - directory: '.', - ...options, - }, - ) -} - -const getAppConfigOrAppModuleContents = (tree: Tree, standalone: boolean) => - standalone - ? getFileContent(tree, '/src/app/app.config.ts') - : getFileContent(tree, '/src/app/app.module.ts') - -// https://github.com/angular/components/blob/18.2.8/src/cdk/schematics/testing/file-content.ts -const getFileContent = (tree: Tree, filePath: string): string => { - const contentBuffer = tree.read(filePath) - - if (!contentBuffer) { - throw new Error(`Cannot read "${filePath}" because it does not exist.`) - } - - return contentBuffer.toString() -} - -const stripWhitespace = (value: string) => value.replace(/\s/g, '') diff --git a/projects/ngx-meta/schematics/ng-add/testing/get-app-config-or-app-module-content.ts b/projects/ngx-meta/schematics/ng-add/testing/get-app-config-or-app-module-content.ts new file mode 100644 index 00000000..20474984 --- /dev/null +++ b/projects/ngx-meta/schematics/ng-add/testing/get-app-config-or-app-module-content.ts @@ -0,0 +1,10 @@ +import { Tree } from '@angular-devkit/schematics' +import { getFileContent } from '../../testing/get-file-content' + +export const getAppConfigOrAppModuleContent = ( + tree: Tree, + standalone: boolean, +) => + standalone + ? getFileContent(tree, '/src/app/app.config.ts') + : getFileContent(tree, '/src/app/app.module.ts') diff --git a/projects/ngx-meta/schematics/ng-add/testing/provider-test-case.ts b/projects/ngx-meta/schematics/ng-add/testing/provider-test-case.ts new file mode 100644 index 00000000..9e5f7891 --- /dev/null +++ b/projects/ngx-meta/schematics/ng-add/testing/provider-test-case.ts @@ -0,0 +1,18 @@ +export class ProviderTestCase { + readonly name: string + readonly symbol: string + readonly code: string + readonly entrypoint: string + + constructor(opts: { + name: string + symbol: string + code?: string + entrypoint?: string + }) { + this.name = opts.name + this.symbol = opts.symbol + this.code = opts.code ?? `${this.symbol}()` + this.entrypoint = opts.entrypoint ?? this.name + } +} diff --git a/projects/ngx-meta/schematics/ng-add/testing/should-add-root-provider.ts b/projects/ngx-meta/schematics/ng-add/testing/should-add-root-provider.ts new file mode 100644 index 00000000..76b8ef1b --- /dev/null +++ b/projects/ngx-meta/schematics/ng-add/testing/should-add-root-provider.ts @@ -0,0 +1,26 @@ +import { ProviderTestCase } from './provider-test-case' +import { Tree } from '@angular-devkit/schematics' +import { expect, it } from '@jest/globals' +import { getAppConfigOrAppModuleContent } from './get-app-config-or-app-module-content' +import { LIB_NAME } from '../../testing/lib-name' +import { stripWhitespace } from '../../testing/strip-whitespace' +import { regexpEscape } from '../../testing/regexp-escape' + +export const shouldAddRootProvider = ( + providerTestCase: ProviderTestCase, + treeFactory: () => Tree, + standalone: boolean, +) => { + it(`should add ${providerTestCase.name} provider`, () => { + const appConfigOrAppModuleContents = getAppConfigOrAppModuleContent( + treeFactory(), + standalone, + ) + expect(appConfigOrAppModuleContents).toContain( + `import { ${providerTestCase.symbol} } from '${LIB_NAME}/${providerTestCase.entrypoint}`, + ) + expect(stripWhitespace(appConfigOrAppModuleContents)).toMatch( + new RegExp(`providers:\\[.*${regexpEscape(providerTestCase.code)}.*]`), + ) + }) +} diff --git a/projects/ngx-meta/schematics/testing/create-test-app.ts b/projects/ngx-meta/schematics/testing/create-test-app.ts new file mode 100644 index 00000000..5380283f --- /dev/null +++ b/projects/ngx-meta/schematics/testing/create-test-app.ts @@ -0,0 +1,19 @@ +import { SchematicTestRunner } from '@angular-devkit/schematics/testing' +import { Schema as NgNewSchema } from '@schematics/angular/ng-new/schema' + +// https://github.com/FortAwesome/angular-fontawesome/blob/0.15.0/projects/schematics/src/ng-add/index.spec.ts#L107 +// https://github.com/angular/components/blob/18.2.8/src/cdk/schematics/testing/test-app.ts +export const createTestApp = async ( + runner: SchematicTestRunner, + options: Omit & Partial>, +) => { + return runner.runExternalSchematic( + '@schematics/angular', + 'ng-new', + { + version: '9.0.0', + directory: '.', + ...options, + }, + ) +} diff --git a/projects/ngx-meta/schematics/testing/get-file-content.ts b/projects/ngx-meta/schematics/testing/get-file-content.ts new file mode 100644 index 00000000..880cc2af --- /dev/null +++ b/projects/ngx-meta/schematics/testing/get-file-content.ts @@ -0,0 +1,12 @@ +import { Tree } from '@angular-devkit/schematics' + +// https://github.com/angular/components/blob/18.2.8/src/cdk/schematics/testing/file-content.ts +export const getFileContent = (tree: Tree, filePath: string): string => { + const contentBuffer = tree.read(filePath) + + if (!contentBuffer) { + throw new Error(`Cannot read "${filePath}" because it does not exist.`) + } + + return contentBuffer.toString() +} diff --git a/projects/ngx-meta/schematics/testing/regexp-escape.ts b/projects/ngx-meta/schematics/testing/regexp-escape.ts new file mode 100644 index 00000000..d3a07fa5 --- /dev/null +++ b/projects/ngx-meta/schematics/testing/regexp-escape.ts @@ -0,0 +1,4 @@ +// https://stackoverflow.com/a/9310752/3263250 +// https://github.com/tc39/proposal-regex-escaping +export const regexpEscape = (string: string) => + string.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') diff --git a/projects/ngx-meta/schematics/testing/strip-whitespace.ts b/projects/ngx-meta/schematics/testing/strip-whitespace.ts new file mode 100644 index 00000000..59626238 --- /dev/null +++ b/projects/ngx-meta/schematics/testing/strip-whitespace.ts @@ -0,0 +1,2 @@ +// https://github.com/angular/angular-cli/blob/18.2.9/packages/schematics/angular/utility/standalone/rules_spec.ts#L45-L47 +export const stripWhitespace = (value: string) => value.replace(/\s/g, '')