<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> Artifact generators don't handle consistently receiving a file extension in the `path` option. ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> Artifact generators should handle receiving a file extension in the `path` option. If the file extension is passed, the file path will be treated as "complete" and used fully as provided. If the `path` provided doesn't contain a file extension, the default extension will be appended to it (or the one provided in a related option, e.g. `--language`, `--js`, etc) together with the suffix for generators that use it. ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
306 lines
8.7 KiB
TypeScript
306 lines
8.7 KiB
TypeScript
import { addProjectConfiguration, writeJson } from '@nx/devkit';
|
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
|
import { scamDirectiveGenerator } from './scam-directive';
|
|
|
|
describe('SCAM Directive Generator', () => {
|
|
it('should create the inline scam directive correctly', async () => {
|
|
// ARRANGE
|
|
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
addProjectConfiguration(tree, 'app1', {
|
|
projectType: 'application',
|
|
sourceRoot: 'apps/app1/src',
|
|
root: 'apps/app1',
|
|
});
|
|
|
|
// ACT
|
|
await scamDirectiveGenerator(tree, {
|
|
name: 'example',
|
|
path: 'apps/app1/src/app/example',
|
|
inlineScam: true,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const directiveSource = tree.read(
|
|
'apps/app1/src/app/example.directive.ts',
|
|
'utf-8'
|
|
);
|
|
expect(directiveSource).toMatchInlineSnapshot(`
|
|
"import { Directive, NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
|
|
@Directive({
|
|
selector: '[example]',
|
|
standalone: false
|
|
})
|
|
export class ExampleDirective {
|
|
constructor() {}
|
|
}
|
|
|
|
@NgModule({
|
|
imports: [CommonModule],
|
|
declarations: [ExampleDirective],
|
|
exports: [ExampleDirective],
|
|
})
|
|
export class ExampleDirectiveModule {}
|
|
"
|
|
`);
|
|
});
|
|
|
|
it('should create the separate scam directive correctly', async () => {
|
|
// ARRANGE
|
|
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
addProjectConfiguration(tree, 'app1', {
|
|
projectType: 'application',
|
|
sourceRoot: 'apps/app1/src',
|
|
root: 'apps/app1',
|
|
});
|
|
|
|
// ACT
|
|
await scamDirectiveGenerator(tree, {
|
|
name: 'example',
|
|
path: 'apps/app1/src/app/example',
|
|
inlineScam: false,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const directiveModuleSource = tree.read(
|
|
'apps/app1/src/app/example.module.ts',
|
|
'utf-8'
|
|
);
|
|
expect(directiveModuleSource).toMatchInlineSnapshot(`
|
|
"import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { ExampleDirective } from './example.directive';
|
|
|
|
@NgModule({
|
|
imports: [CommonModule],
|
|
declarations: [ExampleDirective],
|
|
exports: [ExampleDirective],
|
|
})
|
|
export class ExampleDirectiveModule {}
|
|
"
|
|
`);
|
|
});
|
|
|
|
it('should handle path with file extension', async () => {
|
|
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
addProjectConfiguration(tree, 'app1', {
|
|
projectType: 'application',
|
|
sourceRoot: 'apps/app1/src',
|
|
root: 'apps/app1',
|
|
});
|
|
|
|
await scamDirectiveGenerator(tree, {
|
|
name: 'example',
|
|
path: 'apps/app1/src/app/example.directive.ts',
|
|
inlineScam: true,
|
|
skipFormat: true,
|
|
});
|
|
|
|
const directiveSource = tree.read(
|
|
'apps/app1/src/app/example.directive.ts',
|
|
'utf-8'
|
|
);
|
|
expect(directiveSource).toMatchInlineSnapshot(`
|
|
"import { Directive, NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
|
|
@Directive({
|
|
selector: '[example]',
|
|
standalone: false
|
|
})
|
|
export class ExampleDirective {
|
|
constructor() {}
|
|
}
|
|
|
|
@NgModule({
|
|
imports: [CommonModule],
|
|
declarations: [ExampleDirective],
|
|
exports: [ExampleDirective],
|
|
})
|
|
export class ExampleDirectiveModule {}
|
|
"
|
|
`);
|
|
});
|
|
|
|
it('should create the scam directive correctly and export it for a secondary entrypoint', async () => {
|
|
// ARRANGE
|
|
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
addProjectConfiguration(tree, 'lib1', {
|
|
projectType: 'library',
|
|
sourceRoot: 'libs/lib1/src',
|
|
root: 'libs/lib1',
|
|
});
|
|
tree.write('libs/lib1/feature/src/index.ts', '');
|
|
writeJson(tree, 'libs/lib1/feature/ng-package.json', {
|
|
lib: { entryFile: './src/index.ts' },
|
|
});
|
|
|
|
// ACT
|
|
await scamDirectiveGenerator(tree, {
|
|
name: 'example',
|
|
path: 'libs/lib1/feature/src/lib/example/example',
|
|
inlineScam: false,
|
|
export: true,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const directiveModuleSource = tree.read(
|
|
'libs/lib1/feature/src/lib/example/example.module.ts',
|
|
'utf-8'
|
|
);
|
|
expect(directiveModuleSource).toMatchInlineSnapshot(`
|
|
"import { NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { ExampleDirective } from './example.directive';
|
|
|
|
@NgModule({
|
|
imports: [CommonModule],
|
|
declarations: [ExampleDirective],
|
|
exports: [ExampleDirective],
|
|
})
|
|
export class ExampleDirectiveModule {}
|
|
"
|
|
`);
|
|
const secondaryEntryPointSource = tree.read(
|
|
`libs/lib1/feature/src/index.ts`,
|
|
'utf-8'
|
|
);
|
|
expect(secondaryEntryPointSource).toMatchInlineSnapshot(`
|
|
"export * from './lib/example/example.directive';
|
|
export * from './lib/example/example.module';"
|
|
`);
|
|
});
|
|
|
|
it('should error when the class name is invalid', async () => {
|
|
const tree = createTreeWithEmptyWorkspace();
|
|
addProjectConfiguration(tree, 'app1', {
|
|
projectType: 'application',
|
|
sourceRoot: 'apps/app1/src',
|
|
root: 'apps/app1',
|
|
});
|
|
|
|
await expect(
|
|
scamDirectiveGenerator(tree, {
|
|
name: '404',
|
|
path: 'apps/app1/src/app/example',
|
|
})
|
|
).rejects.toThrow('Class name "404Directive" is invalid.');
|
|
});
|
|
|
|
describe('--path', () => {
|
|
it('should not throw when the path does not exist under project', async () => {
|
|
// ARRANGE
|
|
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
addProjectConfiguration(tree, 'app1', {
|
|
projectType: 'application',
|
|
sourceRoot: 'apps/app1/src',
|
|
root: 'apps/app1',
|
|
});
|
|
|
|
// ACT
|
|
await scamDirectiveGenerator(tree, {
|
|
name: 'example',
|
|
path: 'apps/app1/src/app/random/example/example',
|
|
inlineScam: true,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const directiveSource = tree.read(
|
|
'apps/app1/src/app/random/example/example.directive.ts',
|
|
'utf-8'
|
|
);
|
|
expect(directiveSource).toMatchInlineSnapshot(`
|
|
"import { Directive, NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
|
|
@Directive({
|
|
selector: '[example]',
|
|
standalone: false
|
|
})
|
|
export class ExampleDirective {
|
|
constructor() {}
|
|
}
|
|
|
|
@NgModule({
|
|
imports: [CommonModule],
|
|
declarations: [ExampleDirective],
|
|
exports: [ExampleDirective],
|
|
})
|
|
export class ExampleDirectiveModule {}
|
|
"
|
|
`);
|
|
});
|
|
|
|
it('should not matter if the path starts with a slash', async () => {
|
|
// ARRANGE
|
|
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
addProjectConfiguration(tree, 'app1', {
|
|
projectType: 'application',
|
|
sourceRoot: 'apps/app1/src',
|
|
root: 'apps/app1',
|
|
});
|
|
|
|
// ACT
|
|
await scamDirectiveGenerator(tree, {
|
|
name: 'example',
|
|
path: '/apps/app1/src/app/random/example/example',
|
|
inlineScam: true,
|
|
skipFormat: true,
|
|
});
|
|
|
|
// ASSERT
|
|
const directiveSource = tree.read(
|
|
'apps/app1/src/app/random/example/example.directive.ts',
|
|
'utf-8'
|
|
);
|
|
expect(directiveSource).toMatchInlineSnapshot(`
|
|
"import { Directive, NgModule } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
|
|
@Directive({
|
|
selector: '[example]',
|
|
standalone: false
|
|
})
|
|
export class ExampleDirective {
|
|
constructor() {}
|
|
}
|
|
|
|
@NgModule({
|
|
imports: [CommonModule],
|
|
declarations: [ExampleDirective],
|
|
exports: [ExampleDirective],
|
|
})
|
|
export class ExampleDirectiveModule {}
|
|
"
|
|
`);
|
|
});
|
|
|
|
it('should throw when the path does not exist under project', async () => {
|
|
// ARRANGE
|
|
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
addProjectConfiguration(tree, 'app1', {
|
|
projectType: 'application',
|
|
sourceRoot: 'apps/app1/src',
|
|
root: 'apps/app1',
|
|
});
|
|
|
|
// ACT & ASSERT
|
|
expect(
|
|
scamDirectiveGenerator(tree, {
|
|
name: 'example',
|
|
path: 'libs/proj/src/lib/random/example/example',
|
|
inlineScam: true,
|
|
skipFormat: true,
|
|
})
|
|
).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
`"The provided directory resolved relative to the current working directory "libs/proj/src/lib/random/example" does not exist under any project root. Please make sure to navigate to a location or provide a directory that exists under a project root."`
|
|
);
|
|
});
|
|
});
|
|
});
|