angular-cli/packages/angular_devkit/schematics/tools/file-system-engine-host_spec.ts
Ash Ramirez 434a3740f0 refactor(@angular/cli): update aio links -> adev links
Updates for all angular.io links to the new angular.dev domain. Additionally, adjustment to new resources where the equivalent does not exist on the new site (e.g. Tour of Heroes tutorial)
2024-06-06 11:12:06 +02:00

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.dev/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();
}
});
});
});