diff --git a/src/lib/schematics/update/test-cases/index.spec.ts b/src/lib/schematics/update/test-cases/index.spec.ts index 1ac26af6cee..c665fdb0ea0 100644 --- a/src/lib/schematics/update/test-cases/index.spec.ts +++ b/src/lib/schematics/update/test-cases/index.spec.ts @@ -1,8 +1,11 @@ import {getSystemPath, normalize} from '@angular-devkit/core'; import {TempScopedNodeJsSyncHost} from '@angular-devkit/core/node/testing'; import * as virtualFs from '@angular-devkit/core/src/virtual-fs/host'; -import {readFileSync} from 'fs'; -import {createTestApp} from '../../test-setup/test-app'; +import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; +import {runPostScheduledTasks} from '../../test-setup/post-scheduled-tasks'; +import {readFileSync, writeFileSync, mkdirpSync} from 'fs-extra'; +import {join, dirname} from 'path'; +import {createTestApp, migrationCollection} from '../../test-setup/test-app'; /** Module name suffix for data files of the `jasmine_node_test` Bazel rule. */ const bazelModuleSuffix = 'angular_material/src/lib/schematics/update/test-cases'; @@ -25,15 +28,13 @@ export function resolveBazelDataFile(filePath: string) { } /** - * Creates a test app schematic tree that includes the specified test case as TypeScript - * entry point file. Also writes the app tree to a real file system location in order to be - * able to test the tslint fix rules. + * Creates a test app schematic tree that will be copied over to a real filesystem location. + * This is necessary because TSLint is not able to read from the virtual filesystem tree. */ -export function createTestAppWithTestCase(testCaseInputPath: string) { +export function createFileSystemTestApp() { const tempFileSystemHost = new TempScopedNodeJsSyncHost(); const appTree = createTestApp(); - - appTree.overwrite('/projects/material/src/main.ts', readFileContent(testCaseInputPath)); + const tempPath = getSystemPath(tempFileSystemHost.root); // Since the TSLint fix task expects all files to be present on the real file system, we // map every file in the app tree to a temporary location on the file system. @@ -41,8 +42,40 @@ export function createTestAppWithTestCase(testCaseInputPath: string) { tempFileSystemHost.sync.write(f, virtualFs.stringToFileBuffer(appTree.readContent(f))); }); - // Switch to the new temporary directory because otherwise TSLint cannot read the files. - process.chdir(getSystemPath(tempFileSystemHost.root)); - - return appTree; + return {appTree, tempPath}; +} + +export async function runTestCases(migrationName: string, inputs: {[name: string]: string}) { + const runner = new SchematicTestRunner('schematics', migrationCollection); + const inputNames = Object.keys(inputs); + const initialWorkingDir = process.cwd(); + + let logOutput = ''; + runner.logger.subscribe(entry => logOutput += entry.message); + + const {appTree, tempPath} = createFileSystemTestApp(); + + // Write each test-case input to the file-system. This is necessary because otherwise + // TSLint won't be able to pick up the test cases. + inputNames.forEach(inputName => { + const tempInputPath = join(tempPath, `projects/material/src/test-cases/${inputName}.ts`); + + mkdirpSync(dirname(tempInputPath)); + writeFileSync(tempInputPath, readFileContent(inputs[inputName])); + }); + + runner.runSchematic(migrationName, {}, appTree); + + // Switch to the new temporary directory because otherwise TSLint cannot read the files. + process.chdir(tempPath); + + // Run the scheduled TSLint fix task from the update schematic. This task is responsible for + // identifying outdated code parts and performs the fixes. Since tasks won't run automatically + // within a `SchematicTestRunner`, we manually need to run the scheduled task. + await runPostScheduledTasks(runner, 'tslint-fix').toPromise(); + + // Switch back to the initial working directory. + process.chdir(initialWorkingDir); + + return {tempPath, logOutput}; } diff --git a/src/lib/schematics/update/test-cases/misc/constructor-checks.spec.ts b/src/lib/schematics/update/test-cases/misc/constructor-checks.spec.ts index 9efa909f40c..d57393ea2fc 100644 --- a/src/lib/schematics/update/test-cases/misc/constructor-checks.spec.ts +++ b/src/lib/schematics/update/test-cases/misc/constructor-checks.spec.ts @@ -1,51 +1,42 @@ -import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; -import {runPostScheduledTasks} from '../../../test-setup/post-scheduled-tasks'; -import {migrationCollection} from '../../../test-setup/test-app'; -import {createTestAppWithTestCase, resolveBazelDataFile} from '../index.spec'; +import {resolveBazelDataFile, runTestCases} from '../index.spec'; describe('constructor checks', () => { it('should properly report invalid constructor expression signatures', async () => { - const inputPath = resolveBazelDataFile(`misc/constructor-checks_input.ts`); - const runner = new SchematicTestRunner('schematics', migrationCollection); + const {logOutput} = await runTestCases('migration-01', { + 'constructor-checks': resolveBazelDataFile(`misc/constructor-checks_input.ts`) + }); - runner.runSchematic('migration-01', {}, createTestAppWithTestCase(inputPath)); - - let output = ''; - runner.logger.subscribe(entry => output += entry.message); - - await runPostScheduledTasks(runner, 'tslint-fix').toPromise(); - - expect(output).toMatch(/\[22.*Found "NativeDateAdapter"/, + expect(logOutput).toMatch(/\[22.*Found "NativeDateAdapter"/, 'Expected the constructor checks to report if an argument is not assignable.'); - expect(output).not.toMatch(/\[26.*Found "NativeDateAdapter".*/, + expect(logOutput).not.toMatch(/\[26.*Found "NativeDateAdapter".*/, 'Expected the constructor to not report if an argument is assignable.'); - expect(output).not.toMatch(/Found "NonMaterialClass".*: new NonMaterialClass\(\)/); + expect(logOutput).not.toMatch(/Found "NonMaterialClass".*: new NonMaterialClass\(\)/); - expect(output).toMatch(/Found "NativeDateAdapter".*super.*: super\(string, Platform\)/); - expect(output).toMatch(/Found "NativeDateAdapter".*: new \w+\(string, Platform\)/); + expect(logOutput).toMatch(/Found "NativeDateAdapter".*super.*: super\(string, Platform\)/); + expect(logOutput).toMatch(/Found "NativeDateAdapter".*: new \w+\(string, Platform\)/); - expect(output).toMatch(/Found "MatAutocomplete".*super.*: super\(any, any, string\[]\)/); - expect(output).toMatch(/Found "MatAutocomplete".*: new \w+\(any, any, string\[]\)/); + expect(logOutput).toMatch(/Found "MatAutocomplete".*super.*: super\(any, any, string\[]\)/); + expect(logOutput).toMatch(/Found "MatAutocomplete".*: new \w+\(any, any, string\[]\)/); - expect(output).toMatch(/Found "MatTooltip".*super.*: super\((any, ){10}{ opt1: string; }\)/); - expect(output).toMatch(/Found "MatTooltip".*: new \w+\((any, ){10}{ opt1: string; }\)/); + expect(logOutput).toMatch(/Found "MatTooltip".*super.*: super\((any, ){10}{ opt1: string; }\)/); + expect(logOutput).toMatch(/Found "MatTooltip".*: new \w+\((any, ){10}{ opt1: string; }\)/); - expect(output).toMatch(/Found "MatIconRegistry".*super.*: super\(any, any, Document\)/); - expect(output).toMatch(/Found "MatIconRegistry".*: new \w+\(any, any, Document\)/); + expect(logOutput).toMatch(/Found "MatIconRegistry".*super.*: super\(any, any, Document\)/); + expect(logOutput).toMatch(/Found "MatIconRegistry".*: new \w+\(any, any, Document\)/); - expect(output).toMatch(/Found "MatCalendar".*super.*: super\(any, any, any, any\)/); - expect(output).toMatch(/Found "MatCalendar".*: new \w+\(any, any, any, any\)/); + expect(logOutput).toMatch(/Found "MatCalendar".*super.*: super\(any, any, any, any\)/); + expect(logOutput).toMatch(/Found "MatCalendar".*: new \w+\(any, any, any, any\)/); - expect(output).toMatch(/Found "MatDrawerContent".*super.*: super\((any, ){4}any\)/); - expect(output).toMatch(/Found "MatDrawerContent".*: new \w+\((any, ){4}any\)/); + expect(logOutput).toMatch(/Found "MatDrawerContent".*super.*: super\((any, ){4}any\)/); + expect(logOutput).toMatch(/Found "MatDrawerContent".*: new \w+\((any, ){4}any\)/); - expect(output).toMatch(/Found "MatSidenavContent".*super.*: super\((any, ){4}any\)/); - expect(output).toMatch(/Found "MatSidenavContent".*: new \w+\((any, ){4}any\)/); + expect(logOutput).toMatch(/Found "MatSidenavContent".*super.*: super\((any, ){4}any\)/); + expect(logOutput).toMatch(/Found "MatSidenavContent".*: new \w+\((any, ){4}any\)/); - expect(output).toMatch(/Found "ExtendedDateAdapter".*super.*: super\(string, Platform\)/); - expect(output).toMatch(/Found "ExtendedDateAdapter".*: new \w+\(string, Platform\)/); + expect(logOutput).toMatch(/Found "ExtendedDateAdapter".*super.*: super\(string, Platform\)/); + expect(logOutput).toMatch(/Found "ExtendedDateAdapter".*: new \w+\(string, Platform\)/); }); }); diff --git a/src/lib/schematics/update/test-cases/misc/import-checks.spec.ts b/src/lib/schematics/update/test-cases/misc/import-checks.spec.ts index e5f1e2dc46b..77956203ea2 100644 --- a/src/lib/schematics/update/test-cases/misc/import-checks.spec.ts +++ b/src/lib/schematics/update/test-cases/misc/import-checks.spec.ts @@ -1,23 +1,14 @@ -import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; -import {runPostScheduledTasks} from '../../../test-setup/post-scheduled-tasks'; -import {migrationCollection} from '../../../test-setup/test-app'; -import {createTestAppWithTestCase, resolveBazelDataFile} from '../index.spec'; +import {resolveBazelDataFile, runTestCases} from '../index.spec'; describe('v6 import misc checks', () => { it('should report imports for deleted animation constants', async () => { - const inputPath = resolveBazelDataFile(`misc/import-checks_input.ts`); - const runner = new SchematicTestRunner('schematics', migrationCollection); + const {logOutput} = await runTestCases('migration-01', { + 'import-checks': resolveBazelDataFile(`misc/import-checks_input.ts`) + }); - runner.runSchematic('migration-01', {}, createTestAppWithTestCase(inputPath)); - - let output = ''; - runner.logger.subscribe(entry => output += entry.message); - - await runPostScheduledTasks(runner, 'tslint-fix').toPromise(); - - expect(output).toMatch(/Found deprecated symbol "SHOW_ANIMATION"/); - expect(output).toMatch(/Found deprecated symbol "HIDE_ANIMATION"/); + expect(logOutput).toMatch(/Found deprecated symbol "SHOW_ANIMATION"/); + expect(logOutput).toMatch(/Found deprecated symbol "HIDE_ANIMATION"/); }); }); diff --git a/src/lib/schematics/update/test-cases/misc/method-call-checks.spec.ts b/src/lib/schematics/update/test-cases/misc/method-call-checks.spec.ts index c2e262e247a..839d3f4e554 100644 --- a/src/lib/schematics/update/test-cases/misc/method-call-checks.spec.ts +++ b/src/lib/schematics/update/test-cases/misc/method-call-checks.spec.ts @@ -1,24 +1,15 @@ -import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; -import {runPostScheduledTasks} from '../../../test-setup/post-scheduled-tasks'; -import {migrationCollection} from '../../../test-setup/test-app'; -import {createTestAppWithTestCase, resolveBazelDataFile} from '../index.spec'; +import {resolveBazelDataFile, runTestCases} from '../index.spec'; describe('v6 method call checks', () => { it('should properly report invalid method calls', async () => { - const inputPath = resolveBazelDataFile(`misc/method-call-checks_input.ts`); - const runner = new SchematicTestRunner('schematics', migrationCollection); + const {logOutput} = await runTestCases('migration-01', { + 'method-call-checks': resolveBazelDataFile(`misc/method-call-checks_input.ts`) + }); - runner.runSchematic('migration-01', {}, createTestAppWithTestCase(inputPath)); - - let output = ''; - runner.logger.subscribe(entry => output += entry.message); - - await runPostScheduledTasks(runner, 'tslint-fix').toPromise(); - - expect(output) + expect(logOutput) .toMatch(/\[15,.*Found call to "FocusMonitor\.monitor".*renderer.*has been removed/); - expect(output) + expect(logOutput) .toMatch(/\[16,.*Found call to "FocusMonitor\.monitor".*renderer.*has been removed/); }); }); diff --git a/src/lib/schematics/update/test-cases/v6-test-cases.spec.ts b/src/lib/schematics/update/test-cases/v6-test-cases.spec.ts index 145a6ec0b11..1d4ee7a619c 100644 --- a/src/lib/schematics/update/test-cases/v6-test-cases.spec.ts +++ b/src/lib/schematics/update/test-cases/v6-test-cases.spec.ts @@ -1,7 +1,5 @@ -import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; -import {runPostScheduledTasks} from '../../test-setup/post-scheduled-tasks'; -import {migrationCollection} from '../../test-setup/test-app'; -import {createTestAppWithTestCase, readFileContent, resolveBazelDataFile} from './index.spec'; +import {join} from 'path'; +import {readFileContent, resolveBazelDataFile, runTestCases} from './index.spec'; describe('v6 upgrade test cases', () => { @@ -19,24 +17,27 @@ describe('v6 upgrade test cases', () => { 'v6/property-names', ]; + let testCasesOutputPath: string; + + beforeAll(async () => { + const testCaseInputs = testCases.reduce((inputs, testCaseName) => { + inputs[testCaseName] = resolveBazelDataFile(`${testCaseName}_input.ts`); + return inputs; + }, {}); + + const {tempPath} = await runTestCases('migration-01', testCaseInputs); + + testCasesOutputPath = join(tempPath, 'projects/material/src/test-cases/'); + }); + // Iterates through every test case directory and generates a jasmine test block that will - // verify that the update schematics properly update the test input to the expected output. + // verify that the update schematics properly updated the test input to the expected output. testCases.forEach(testCaseName => { - const inputPath = resolveBazelDataFile(`${testCaseName}_input.ts`); const expectedOutputPath = resolveBazelDataFile(`${testCaseName}_expected_output.ts`); it(`should apply update schematics to test case: ${testCaseName}`, () => { - const runner = new SchematicTestRunner('schematics', migrationCollection); - - runner.runSchematic('migration-01', {}, createTestAppWithTestCase(inputPath)); - - // Run the scheduled TSLint fix task from the update schematic. This task is responsible for - // identifying outdated code parts and performs the fixes. Since tasks won't run automatically - // within a `SchematicTestRunner`, we manually need to run the scheduled task. - return runPostScheduledTasks(runner, 'tslint-fix').toPromise().then(() => { - expect(readFileContent('projects/material/src/main.ts')) - .toBe(readFileContent(expectedOutputPath)); - }); + expect(readFileContent(join(testCasesOutputPath, `${testCaseName}.ts`))) + .toBe(readFileContent(expectedOutputPath)); }); }); }); diff --git a/src/lib/schematics/update/test-cases/v7-test-cases.spec.ts b/src/lib/schematics/update/test-cases/v7-test-cases.spec.ts index 7bf50ad6775..880110171eb 100644 --- a/src/lib/schematics/update/test-cases/v7-test-cases.spec.ts +++ b/src/lib/schematics/update/test-cases/v7-test-cases.spec.ts @@ -1,7 +1,5 @@ -import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; -import {runPostScheduledTasks} from '../../test-setup/post-scheduled-tasks'; -import {migrationCollection} from '../../test-setup/test-app'; -import {createTestAppWithTestCase, readFileContent, resolveBazelDataFile} from './index.spec'; +import {join} from 'path'; +import {readFileContent, resolveBazelDataFile, runTestCases} from './index.spec'; describe('v7 upgrade test cases', () => { @@ -14,26 +12,28 @@ describe('v7 upgrade test cases', () => { 'v7/ripple-speed-factor', ]; + let testCasesOutputPath: string; + + beforeAll(async () => { + const testCaseInputs = testCases.reduce((inputs, testCaseName) => { + inputs[testCaseName] = resolveBazelDataFile(`${testCaseName}_input.ts`); + return inputs; + }, {}); + + const {tempPath} = await runTestCases('migration-02', testCaseInputs); + + testCasesOutputPath = join(tempPath, 'projects/material/src/test-cases/'); + }); + // Iterates through every test case directory and generates a jasmine test block that will - // verify that the update schematics properly update the test input to the expected output. + // verify that the update schematics properly updated the test input to the expected output. testCases.forEach(testCaseName => { - const inputPath = resolveBazelDataFile(`${testCaseName}_input.ts`); const expectedOutputPath = resolveBazelDataFile(`${testCaseName}_expected_output.ts`); it(`should apply update schematics to test case: ${testCaseName}`, () => { - const runner = new SchematicTestRunner('schematics', migrationCollection); - - runner.runSchematic('migration-02', {}, createTestAppWithTestCase(inputPath)); - - // Run the scheduled TSLint fix task from the update schematic. This task is responsible for - // identifying outdated code parts and performs the fixes. Since tasks won't run automatically - // within a `SchematicTestRunner`, we manually need to run the scheduled task. - return runPostScheduledTasks(runner, 'tslint-fix').toPromise().then(() => { - expect(readFileContent('projects/material/src/main.ts')) - .toBe(readFileContent(expectedOutputPath)); - }); + expect(readFileContent(join(testCasesOutputPath, `${testCaseName}.ts`))) + .toBe(readFileContent(expectedOutputPath)); }); }); }); -