mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-17 11:03:53 +08:00
G3 is now using RXJS version 7 which makes it possible for the CLI to also be updated to RXJS 7. NB: this change does not remove all usages of the deprecated APIs. Closes #24371
362 lines
13 KiB
TypeScript
362 lines
13 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
/* eslint-disable @typescript-eslint/no-explicit-any, import/no-extraneous-dependencies */
|
|
import { normalize, virtualFs } from '@angular-devkit/core';
|
|
import { HostSink, HostTree, SchematicEngine } from '@angular-devkit/schematics';
|
|
import { FileSystemEngineHost } from '@angular-devkit/schematics/tools';
|
|
import * as path from 'path';
|
|
import { from, lastValueFrom, of as observableOf } from 'rxjs';
|
|
|
|
describe('FileSystemEngineHost', () => {
|
|
// We need to resolve a file that actually exists, and not just a folder.
|
|
const root = path.join(
|
|
path.dirname(require.resolve(__filename)),
|
|
'../../../../tests/angular_devkit/schematics/tools/file-system-engine-host',
|
|
);
|
|
|
|
it('works', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
const testCollection = engine.createCollection('works');
|
|
const schematic1 = engine.createSchematic('schematic1', testCollection);
|
|
|
|
expect(schematic1.description.name).toBe('schematic1');
|
|
});
|
|
|
|
it('understands aliases', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
const testCollection = engine.createCollection('aliases');
|
|
const schematic1 = engine.createSchematic('alias1', testCollection);
|
|
|
|
expect(schematic1).not.toBeNull();
|
|
expect(schematic1.description.name).toBe('schematic1');
|
|
});
|
|
|
|
it('understands multiple aliases for a single schematic', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
const testCollection = engine.createCollection('aliases-many');
|
|
|
|
const schematic1 = engine.createSchematic('alias1', testCollection);
|
|
expect(schematic1).not.toBeNull();
|
|
expect(schematic1.description.name).toBe('schematic1');
|
|
|
|
const schematic2 = engine.createSchematic('alias2', testCollection);
|
|
expect(schematic2).not.toBeNull();
|
|
expect(schematic2.description.name).toBe('schematic1');
|
|
|
|
const schematic3 = engine.createSchematic('alias3', testCollection);
|
|
expect(schematic3).not.toBeNull();
|
|
expect(schematic3.description.name).toBe('schematic1');
|
|
});
|
|
|
|
it('allows dupe aliases for a single schematic', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
const testCollection = engine.createCollection('aliases-dupe');
|
|
|
|
const schematic1 = engine.createSchematic('alias1', testCollection);
|
|
expect(schematic1).not.toBeNull();
|
|
expect(schematic1.description.name).toBe('schematic1');
|
|
|
|
const schematic2 = engine.createSchematic('alias2', testCollection);
|
|
expect(schematic2).not.toBeNull();
|
|
expect(schematic2.description.name).toBe('schematic1');
|
|
|
|
const schematic3 = engine.createSchematic('alias3', testCollection);
|
|
expect(schematic3).not.toBeNull();
|
|
expect(schematic3.description.name).toBe('schematic1');
|
|
});
|
|
|
|
it('lists schematics but not aliases', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
const testCollection = engine.createCollection('aliases');
|
|
const names = testCollection.listSchematicNames();
|
|
|
|
expect(names).not.toBeNull();
|
|
expect(names[0]).toBe('schematic1');
|
|
expect(names[1]).toBe('schematic2');
|
|
});
|
|
|
|
it('extends a collection with string', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
const testCollection = engine.createCollection('extends-basic-string');
|
|
|
|
expect(testCollection.baseDescriptions).not.toBeUndefined();
|
|
expect(testCollection.baseDescriptions && testCollection.baseDescriptions.length).toBe(1);
|
|
|
|
const schematic1 = engine.createSchematic('schematic1', testCollection);
|
|
|
|
expect(schematic1).not.toBeNull();
|
|
expect(schematic1.description.name).toBe('schematic1');
|
|
|
|
const schematic2 = engine.createSchematic('schematic2', testCollection);
|
|
|
|
expect(schematic2).not.toBeNull();
|
|
expect(schematic2.description.name).toBe('schematic2');
|
|
|
|
const names = testCollection.listSchematicNames();
|
|
|
|
expect(names.length).toBe(2);
|
|
});
|
|
|
|
it('extends a collection with array', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
const testCollection = engine.createCollection('extends-basic');
|
|
|
|
expect(testCollection.baseDescriptions).not.toBeUndefined();
|
|
expect(testCollection.baseDescriptions && testCollection.baseDescriptions.length).toBe(1);
|
|
|
|
const schematic1 = engine.createSchematic('schematic1', testCollection);
|
|
|
|
expect(schematic1).not.toBeNull();
|
|
expect(schematic1.description.name).toBe('schematic1');
|
|
|
|
const schematic2 = engine.createSchematic('schematic2', testCollection);
|
|
|
|
expect(schematic2).not.toBeNull();
|
|
expect(schematic2.description.name).toBe('schematic2');
|
|
|
|
const names = testCollection.listSchematicNames();
|
|
|
|
expect(names.length).toBe(2);
|
|
});
|
|
|
|
it('extends a collection with full depth', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
const testCollection = engine.createCollection('extends-deep');
|
|
|
|
expect(testCollection.baseDescriptions).not.toBeUndefined();
|
|
expect(testCollection.baseDescriptions && testCollection.baseDescriptions.length).toBe(2);
|
|
|
|
const schematic1 = engine.createSchematic('schematic1', testCollection);
|
|
|
|
expect(schematic1).not.toBeNull();
|
|
expect(schematic1.description.name).toBe('schematic1');
|
|
|
|
const schematic2 = engine.createSchematic('schematic2', testCollection);
|
|
|
|
expect(schematic2).not.toBeNull();
|
|
expect(schematic2.description.name).toBe('schematic2');
|
|
|
|
const names = testCollection.listSchematicNames();
|
|
|
|
expect(names.length).toBe(2);
|
|
});
|
|
|
|
it('replaces base schematics when extending', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
const testCollection = engine.createCollection('extends-replace');
|
|
|
|
expect(testCollection.baseDescriptions).not.toBeUndefined();
|
|
expect(testCollection.baseDescriptions && testCollection.baseDescriptions.length).toBe(1);
|
|
|
|
const schematic1 = engine.createSchematic('schematic1', testCollection);
|
|
|
|
expect(schematic1).not.toBeNull();
|
|
expect(schematic1.description.name).toBe('schematic1');
|
|
expect(schematic1.description.description).toBe('replaced');
|
|
|
|
const names = testCollection.listSchematicNames();
|
|
|
|
expect(names).not.toBeNull();
|
|
expect(names.length).toBe(1);
|
|
});
|
|
|
|
it('extends multiple collections', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
const testCollection = engine.createCollection('extends-multiple');
|
|
|
|
expect(testCollection.baseDescriptions).not.toBeUndefined();
|
|
expect(testCollection.baseDescriptions && testCollection.baseDescriptions.length).toBe(4);
|
|
|
|
const schematic1 = engine.createSchematic('schematic1', testCollection);
|
|
|
|
expect(schematic1).not.toBeNull();
|
|
expect(schematic1.description.name).toBe('schematic1');
|
|
expect(schematic1.description.description).toBe('replaced');
|
|
|
|
const schematic2 = engine.createSchematic('schematic2', testCollection);
|
|
|
|
expect(schematic2).not.toBeNull();
|
|
expect(schematic2.description.name).toBe('schematic2');
|
|
|
|
const names = testCollection.listSchematicNames();
|
|
|
|
expect(names).not.toBeNull();
|
|
expect(names.length).toBe(2);
|
|
});
|
|
|
|
it('errors on simple circular collections', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
expect(() => engine.createCollection('extends-circular')).toThrow();
|
|
});
|
|
|
|
it('errors on complex circular collections', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
expect(() => engine.createCollection('extends-circular-multiple')).toThrow();
|
|
});
|
|
|
|
it('errors on deep circular collections', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
expect(() => engine.createCollection('extends-circular-deep')).toThrow();
|
|
});
|
|
|
|
it('errors on invalid aliases', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
expect(() => engine.createCollection('invalid-aliases')).toThrow();
|
|
});
|
|
|
|
it('errors on invalid aliases (2)', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
expect(() => engine.createCollection('invalid-aliases-2')).toThrow();
|
|
});
|
|
|
|
it(`does not list hidden schematics when 'includeHidden' is not specified`, () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
const collection = engine.createCollection('hidden-schematics');
|
|
|
|
expect(collection.listSchematicNames(/** includeHidden */)).toEqual([
|
|
'schematic-1',
|
|
'schematic-2',
|
|
]);
|
|
});
|
|
|
|
it(`does not list hidden schematics when 'includeHidden' is false`, () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
const collection = engine.createCollection('hidden-schematics');
|
|
|
|
expect(collection.listSchematicNames(false /** includeHidden */)).toEqual([
|
|
'schematic-1',
|
|
'schematic-2',
|
|
]);
|
|
});
|
|
|
|
it(`does list hidden schematics when 'includeHidden' is true`, () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
const collection = engine.createCollection('hidden-schematics');
|
|
|
|
expect(collection.listSchematicNames(true /** includeHidden */)).toEqual([
|
|
'hidden-schematic',
|
|
'schematic-1',
|
|
'schematic-2',
|
|
]);
|
|
});
|
|
|
|
it('does not list private schematics', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
const collection = engine.createCollection('private-schematics');
|
|
|
|
expect(collection.listSchematicNames()).toEqual(['schematic-1', 'schematic-2']);
|
|
});
|
|
|
|
it('cannot instanciate a private schematic', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
|
|
const collection = engine.createCollection('private-schematics');
|
|
expect(() => engine.createSchematic('schematic-1', collection)).not.toThrow();
|
|
expect(() => engine.createSchematic('private-schematic', collection)).toThrow();
|
|
expect(() => collection.createSchematic('private-schematic')).toThrow();
|
|
});
|
|
|
|
it('allows extra properties on schema', (done) => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
const host = new virtualFs.test.TestHost();
|
|
|
|
const collection = engine.createCollection('extra-properties');
|
|
const schematic = collection.createSchematic('schematic1');
|
|
|
|
lastValueFrom(schematic.call({}, observableOf(new HostTree(host))))
|
|
.then((tree) => {
|
|
return lastValueFrom(new HostSink(host).commit(tree));
|
|
})
|
|
.then(() => {
|
|
expect(host.files as string[]).toEqual(['/extra-schematic']);
|
|
expect(host.sync.read(normalize('/extra-schematic')).toString()).toEqual(
|
|
'extra-collection',
|
|
);
|
|
})
|
|
.then(done, done.fail);
|
|
});
|
|
|
|
it('discovers a file-based task', () => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
|
|
expect(engineHost.hasTaskExecutor('file-tasks/file-task.js')).toBeTruthy();
|
|
});
|
|
|
|
it('creates a file-based task', (done) => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
|
|
engineHost.createTaskExecutor('file-tasks/file-task.js').subscribe((executor) => {
|
|
expect(executor).toBeTruthy();
|
|
lastValueFrom(from(executor(undefined, undefined as any))).then(
|
|
() => done.fail,
|
|
() => done(),
|
|
);
|
|
}, done.fail);
|
|
});
|
|
|
|
it('allows executing a schematic with a file-based task', (done) => {
|
|
const engineHost = new FileSystemEngineHost(root);
|
|
const engine = new SchematicEngine(engineHost);
|
|
const host = new virtualFs.test.TestHost();
|
|
|
|
const collection = engine.createCollection('file-tasks');
|
|
const schematic = collection.createSchematic('schematic-1');
|
|
|
|
lastValueFrom(schematic.call({}, observableOf(new HostTree(host))))
|
|
.then((tree) => {
|
|
return lastValueFrom(new HostSink(host).commit(tree));
|
|
})
|
|
.then(() => engine.executePostTasks().toPromise())
|
|
.then(() => done.fail())
|
|
.catch((reason) => {
|
|
if (reason.message === 'task exception') {
|
|
done();
|
|
} else {
|
|
done.fail();
|
|
}
|
|
});
|
|
});
|
|
});
|