cleanup(angular): migrate storybook-configuration generator to nx devkit (#5875)

This commit is contained in:
Leosvel Pérez Espinosa 2021-06-04 10:44:54 +01:00 committed by GitHub
parent 223f45508b
commit 06d3654c00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 642 additions and 407 deletions

View File

@ -1,6 +1,6 @@
# storybook-configuration
Create stories/specs for all components declared in a library
Create stories/specs for all components declared in a library.
## Usage
@ -30,7 +30,7 @@ Default: `true`
Type: `boolean`
Run the cypress-configure generator
Specifies whether to configure Cypress or not.
### cypressDirectory
@ -44,7 +44,7 @@ Default: `true`
Type: `boolean`
Automatically generate \*.spec.ts files in the cypress e2e app generated by the cypress-configure generator
Specifies whether to automatically generate \*.spec.ts files in the generated cypress e2e app.
### generateStories
@ -52,7 +52,7 @@ Default: `true`
Type: `boolean`
Automatically generate \*.stories.ts files for components declared in this project?
Specifies whether to automatically generate \*.stories.ts files for components declared in this project or not.
### linter
@ -68,4 +68,4 @@ The tool to use for running lint checks.
Type: `string`
Project name
Project name.

View File

@ -1,6 +1,6 @@
# storybook-configuration
Create stories/specs for all components declared in a library
Create stories/specs for all components declared in a library.
## Usage
@ -30,7 +30,7 @@ Default: `true`
Type: `boolean`
Run the cypress-configure generator
Specifies whether to configure Cypress or not.
### cypressDirectory
@ -44,7 +44,7 @@ Default: `true`
Type: `boolean`
Automatically generate \*.spec.ts files in the cypress e2e app generated by the cypress-configure generator
Specifies whether to automatically generate \*.spec.ts files in the generated cypress e2e app.
### generateStories
@ -52,7 +52,7 @@ Default: `true`
Type: `boolean`
Automatically generate \*.stories.ts files for components declared in this project?
Specifies whether to automatically generate \*.stories.ts files for components declared in this project or not.
### linter
@ -68,4 +68,4 @@ The tool to use for running lint checks.
Type: `string`
Project name
Project name.

View File

@ -1,6 +1,6 @@
# storybook-configuration
Create stories/specs for all components declared in a library
Create stories/specs for all components declared in a library.
## Usage
@ -30,7 +30,7 @@ Default: `true`
Type: `boolean`
Run the cypress-configure generator
Specifies whether to configure Cypress or not.
### cypressDirectory
@ -44,7 +44,7 @@ Default: `true`
Type: `boolean`
Automatically generate \*.spec.ts files in the cypress e2e app generated by the cypress-configure generator
Specifies whether to automatically generate \*.spec.ts files in the generated cypress e2e app.
### generateStories
@ -52,7 +52,7 @@ Default: `true`
Type: `boolean`
Automatically generate \*.stories.ts files for components declared in this project?
Specifies whether to automatically generate \*.stories.ts files for components declared in this project or not.
### linter
@ -68,4 +68,4 @@ The tool to use for running lint checks.
Type: `string`
Project name
Project name.

View File

@ -56,10 +56,9 @@
},
"storybook-configuration": {
"factory": "./src/schematics/storybook-configuration/configuration",
"schema": "./src/schematics/storybook-configuration/schema.json",
"description": "Create stories/specs for all components declared in a library",
"hidden": false
"factory": "./src/generators/storybook-configuration/compat",
"schema": "./src/generators/storybook-configuration/schema.json",
"description": "Create stories/specs for all components declared in a library."
},
"storybook-migrate-defaults-5-to-6": {
@ -144,6 +143,11 @@
"schema": "./src/generators/move/schema.json",
"aliases": ["mv"],
"description": "Move an Angular application or library to another folder"
},
"storybook-configuration": {
"factory": "./src/generators/storybook-configuration/storybook-configuration",
"schema": "./src/generators/storybook-configuration/schema.json",
"description": "Create stories/specs for all components declared in a library."
}
}
}

View File

@ -1,3 +1,6 @@
export * from './src/schematics/generators';
export * from './src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint';
export * from './src/generators/karma/karma';
export * from './src/generators/karma-project/karma-project';
export * from './src/generators/move/move';
export * from './src/generators/storybook-configuration/storybook-configuration';
export * from './src/schematics/generators';

View File

@ -0,0 +1,168 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`StorybookConfiguration generator should configure storybook to use webpack 5 1`] = `
"const rootMain = require('../../../.storybook/main');
rootMain.core = { ...rootMain.core, builder: 'webpack5' };
// Use the following syntax to add addons!
// rootMain.addons.push('');
rootMain.stories.push(...['../src/lib/**/*.stories.mdx', '../src/lib/**/*.stories.@(js|jsx|ts|tsx)'])
module.exports = rootMain;
"
`;
exports[`StorybookConfiguration generator should generate in the correct folder 1`] = `
Array [
".eslintrc.json",
".prettierrc",
".storybook/main.js",
".storybook/tsconfig.json",
".storybook/webpack.config.js",
"apps/one/two/test-ui-lib-e2e/.eslintrc.json",
"apps/one/two/test-ui-lib-e2e/cypress.json",
"apps/one/two/test-ui-lib-e2e/src/fixtures/example.json",
"apps/one/two/test-ui-lib-e2e/src/integration/barrel-button/barrel-button.component.spec.ts",
"apps/one/two/test-ui-lib-e2e/src/integration/nested-button/nested-button.component.spec.ts",
"apps/one/two/test-ui-lib-e2e/src/integration/test-button/test-button.component.spec.ts",
"apps/one/two/test-ui-lib-e2e/src/integration/test-other/test-other.component.spec.ts",
"apps/one/two/test-ui-lib-e2e/src/integration/variable-declare-button/variable-declare-button.component.spec.ts",
"apps/one/two/test-ui-lib-e2e/src/integration/variable-declare-view/variable-declare-view.component.spec.ts",
"apps/one/two/test-ui-lib-e2e/src/plugins/index.js",
"apps/one/two/test-ui-lib-e2e/src/support/commands.ts",
"apps/one/two/test-ui-lib-e2e/src/support/index.ts",
"apps/one/two/test-ui-lib-e2e/tsconfig.e2e.json",
"apps/one/two/test-ui-lib-e2e/tsconfig.json",
"jest.config.js",
"jest.preset.js",
"libs/test-ui-lib/.eslintrc.json",
"libs/test-ui-lib/.storybook/main.js",
"libs/test-ui-lib/.storybook/preview.js",
"libs/test-ui-lib/.storybook/tsconfig.json",
"libs/test-ui-lib/.storybook/webpack.config.js",
"libs/test-ui-lib/jest.config.js",
"libs/test-ui-lib/README.md",
"libs/test-ui-lib/src/index.ts",
"libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.css",
"libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.html",
"libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.spec.ts",
"libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.stories.ts",
"libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.ts",
"libs/test-ui-lib/src/lib/barrel/barrel-button/index.ts",
"libs/test-ui-lib/src/lib/barrel/barrel.module.ts",
"libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.css",
"libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.html",
"libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.spec.ts",
"libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.stories.ts",
"libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.ts",
"libs/test-ui-lib/src/lib/nested/nested.module.ts",
"libs/test-ui-lib/src/lib/test-button/test-button.component.css",
"libs/test-ui-lib/src/lib/test-button/test-button.component.html",
"libs/test-ui-lib/src/lib/test-button/test-button.component.spec.ts",
"libs/test-ui-lib/src/lib/test-button/test-button.component.stories.ts",
"libs/test-ui-lib/src/lib/test-button/test-button.component.ts",
"libs/test-ui-lib/src/lib/test-other/test-other.component.css",
"libs/test-ui-lib/src/lib/test-other/test-other.component.html",
"libs/test-ui-lib/src/lib/test-other/test-other.component.spec.ts",
"libs/test-ui-lib/src/lib/test-other/test-other.component.stories.ts",
"libs/test-ui-lib/src/lib/test-other/test-other.component.ts",
"libs/test-ui-lib/src/lib/test-ui-lib.module.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.css",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.html",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.spec.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.stories.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.css",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.html",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.spec.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.stories.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare.module.ts",
"libs/test-ui-lib/src/test-setup.ts",
"libs/test-ui-lib/tsconfig.json",
"libs/test-ui-lib/tsconfig.lib.json",
"libs/test-ui-lib/tsconfig.spec.json",
"nx.json",
"package.json",
"tsconfig.base.json",
"workspace.json",
]
`;
exports[`StorybookConfiguration generator should generate the right files 1`] = `
Array [
".eslintrc.json",
".prettierrc",
".storybook/main.js",
".storybook/tsconfig.json",
".storybook/webpack.config.js",
"apps/test-ui-lib-e2e/.eslintrc.json",
"apps/test-ui-lib-e2e/cypress.json",
"apps/test-ui-lib-e2e/src/fixtures/example.json",
"apps/test-ui-lib-e2e/src/integration/barrel-button/barrel-button.component.spec.ts",
"apps/test-ui-lib-e2e/src/integration/nested-button/nested-button.component.spec.ts",
"apps/test-ui-lib-e2e/src/integration/test-button/test-button.component.spec.ts",
"apps/test-ui-lib-e2e/src/integration/test-other/test-other.component.spec.ts",
"apps/test-ui-lib-e2e/src/integration/variable-declare-button/variable-declare-button.component.spec.ts",
"apps/test-ui-lib-e2e/src/integration/variable-declare-view/variable-declare-view.component.spec.ts",
"apps/test-ui-lib-e2e/src/plugins/index.js",
"apps/test-ui-lib-e2e/src/support/commands.ts",
"apps/test-ui-lib-e2e/src/support/index.ts",
"apps/test-ui-lib-e2e/tsconfig.e2e.json",
"apps/test-ui-lib-e2e/tsconfig.json",
"jest.config.js",
"jest.preset.js",
"libs/test-ui-lib/.eslintrc.json",
"libs/test-ui-lib/.storybook/main.js",
"libs/test-ui-lib/.storybook/preview.js",
"libs/test-ui-lib/.storybook/tsconfig.json",
"libs/test-ui-lib/.storybook/webpack.config.js",
"libs/test-ui-lib/jest.config.js",
"libs/test-ui-lib/README.md",
"libs/test-ui-lib/src/index.ts",
"libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.css",
"libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.html",
"libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.spec.ts",
"libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.stories.ts",
"libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.ts",
"libs/test-ui-lib/src/lib/barrel/barrel-button/index.ts",
"libs/test-ui-lib/src/lib/barrel/barrel.module.ts",
"libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.css",
"libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.html",
"libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.spec.ts",
"libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.stories.ts",
"libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.ts",
"libs/test-ui-lib/src/lib/nested/nested.module.ts",
"libs/test-ui-lib/src/lib/test-button/test-button.component.css",
"libs/test-ui-lib/src/lib/test-button/test-button.component.html",
"libs/test-ui-lib/src/lib/test-button/test-button.component.spec.ts",
"libs/test-ui-lib/src/lib/test-button/test-button.component.stories.ts",
"libs/test-ui-lib/src/lib/test-button/test-button.component.ts",
"libs/test-ui-lib/src/lib/test-other/test-other.component.css",
"libs/test-ui-lib/src/lib/test-other/test-other.component.html",
"libs/test-ui-lib/src/lib/test-other/test-other.component.spec.ts",
"libs/test-ui-lib/src/lib/test-other/test-other.component.stories.ts",
"libs/test-ui-lib/src/lib/test-other/test-other.component.ts",
"libs/test-ui-lib/src/lib/test-ui-lib.module.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.css",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.html",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.spec.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.stories.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.css",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.html",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.spec.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.stories.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.ts",
"libs/test-ui-lib/src/lib/variable-declare/variable-declare.module.ts",
"libs/test-ui-lib/src/test-setup.ts",
"libs/test-ui-lib/tsconfig.json",
"libs/test-ui-lib/tsconfig.lib.json",
"libs/test-ui-lib/tsconfig.spec.json",
"nx.json",
"package.json",
"tsconfig.base.json",
"workspace.json",
]
`;

View File

@ -0,0 +1,4 @@
import { convertNxGenerator } from '@nrwl/devkit';
import { storybookConfigurationGenerator } from './storybook-configuration';
export default convertNxGenerator(storybookConfigurationGenerator);

View File

@ -0,0 +1,14 @@
import { lt } from 'semver';
export function assertCompatibleStorybookVersion() {
let storybookVersion: string;
try {
storybookVersion = require(require.resolve(
'@storybook/angular/package.json'
)).version;
} catch {}
if (storybookVersion && lt(storybookVersion, '6.2.0')) {
throw new Error('Incompatible Storybook Version');
}
}

View File

@ -0,0 +1,28 @@
import { getE2eProjectName } from '@nrwl/cypress/src/utils/project-name';
import type { Tree } from '@nrwl/devkit';
import { readProjectConfiguration } from '@nrwl/devkit';
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
import type { StorybookConfigurationOptions } from '../schema';
export async function generateStories(
tree: Tree,
options: StorybookConfigurationOptions
) {
const project = readProjectConfiguration(tree, options.name);
const e2eProjectName = getE2eProjectName(
options.name,
project.root,
options.cypressDirectory
);
const storiesGenerator = wrapAngularDevkitSchematic(
'@nrwl/angular',
'stories'
);
await storiesGenerator(tree, {
name: options.name,
generateCypressSpecs:
options.configureCypress && options.generateCypressSpecs,
cypressProject: e2eProjectName,
});
}

View File

@ -0,0 +1,20 @@
import type { Tree } from '@nrwl/devkit';
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
import type { StorybookConfigurationOptions } from '../schema';
export async function generateStorybookConfiguration(
tree: Tree,
options: StorybookConfigurationOptions
): Promise<void> {
const storybookConfigGenerator = wrapAngularDevkitSchematic(
'@nrwl/storybook',
'configuration'
);
await storybookConfigGenerator(tree, {
name: options.name,
uiFramework: '@storybook/angular',
configureCypress: options.configureCypress,
linter: options.linter,
cypressDirectory: options.cypressDirectory,
});
}

View File

@ -0,0 +1,9 @@
import type { StorybookConfigurationOptions } from '../schema';
export function validateOptions(options: StorybookConfigurationOptions): void {
if (options.generateCypressSpecs && !options.generateStories) {
throw new Error(
'Cannot set generateCypressSpecs to true when generateStories is set to false.'
);
}
}

View File

@ -1,10 +1,10 @@
import { Linter } from '@nrwl/workspace';
import type { Linter } from '@nrwl/linter';
export interface StorybookConfigureSchema {
name: string;
export interface StorybookConfigurationOptions {
configureCypress: boolean;
generateStories: boolean;
generateCypressSpecs: boolean;
generateStories: boolean;
linter: Exclude<Linter, Linter.TsLint>;
name: string;
cypressDirectory?: string;
}

View File

@ -1,11 +1,12 @@
{
"$schema": "http://json-schema.org/schema",
"$id": "NxAngularStorybookConfigure",
"$id": "NxAngularStorybookConfigurationGenerator",
"cli": "nx",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Project name",
"description": "Project name.",
"$default": {
"$source": "argv",
"index": 0
@ -13,20 +14,20 @@
},
"configureCypress": {
"type": "boolean",
"description": "Run the cypress-configure generator",
"description": "Specifies whether to configure Cypress or not.",
"x-prompt": "Configure a cypress e2e app to run against the storybook instance?",
"default": true
},
"generateStories": {
"type": "boolean",
"description": "Automatically generate *.stories.ts files for components declared in this project?",
"description": "Specifies whether to automatically generate *.stories.ts files for components declared in this project or not.",
"x-prompt": "Automatically generate *.stories.ts files for components declared in this project?",
"default": true
},
"generateCypressSpecs": {
"type": "boolean",
"description": "Automatically generate *.spec.ts files in the cypress e2e app generated by the cypress-configure generator",
"x-prompt": "Automatically generate *.spec.ts files in the cypress e2e app generated by the cypress-configure generator?",
"description": "Specifies whether to automatically generate *.spec.ts files in the generated cypress e2e app.",
"x-prompt": "Automatically generate *.spec.ts files in the generated cypress e2e app?",
"default": true
},
"cypressDirectory": {

View File

@ -0,0 +1,176 @@
import type { Tree } from '@nrwl/devkit';
import { joinPathFragments } from '@nrwl/devkit';
import { overrideCollectionResolutionForTesting } from '@nrwl/devkit/ngcli-adapter';
import * as fileUtils from '@nrwl/workspace/src/core/file-utils';
import { Linter } from 'packages/linter/src/generators/utils/linter';
import { createStorybookTestWorkspaceForLib } from '../utils/testing';
import type { StorybookConfigurationOptions } from './schema';
import { storybookConfigurationGenerator } from './storybook-configuration';
function listFiles(tree: Tree): string[] {
const files = new Set<string>();
tree.listChanges().forEach((change) => {
if (change.type !== 'DELETE') {
files.add(change.path);
}
});
return Array.from(files).sort((a, b) => a.localeCompare(b));
}
describe('StorybookConfiguration generator', () => {
let tree: Tree;
const libName = 'test-ui-lib';
beforeEach(async () => {
tree = await createStorybookTestWorkspaceForLib(libName);
overrideCollectionResolutionForTesting({
'@nrwl/storybook': joinPathFragments(
__dirname,
'../../../../storybook/collection.json'
),
});
jest.resetModuleRegistry();
jest.doMock('@storybook/angular/package.json', () => ({
version: '6.2.0',
}));
jest.spyOn(fileUtils, 'readPackageJson').mockReturnValue({
devDependencies: {
'@storybook/addon-essentials': '^6.0.21',
'@storybook/react': '^6.0.21',
},
});
});
it('should throw when the @storybook/angular version is lower than 6.2.0', async () => {
jest.doMock('@storybook/angular/package.json', () => ({
version: '5.1.0',
}));
await expect(
storybookConfigurationGenerator(tree, <StorybookConfigurationOptions>{
name: libName,
})
).rejects.toThrow('Incompatible Storybook Version');
});
it('should throw when generateCypressSpecs is true and generateStories is false', async () => {
await expect(
storybookConfigurationGenerator(tree, <StorybookConfigurationOptions>{
name: libName,
generateCypressSpecs: true,
generateStories: false,
})
).rejects.toThrow(
'Cannot set generateCypressSpecs to true when generateStories is set to false.'
);
});
it('should only configure storybook', async () => {
await storybookConfigurationGenerator(tree, <StorybookConfigurationOptions>{
name: libName,
configureCypress: false,
generateCypressSpecs: false,
generateStories: false,
});
expect(tree.exists('libs/test-ui-lib/.storybook/main.js')).toBeTruthy();
expect(
tree.exists('libs/test-ui-lib/.storybook/tsconfig.json')
).toBeTruthy();
expect(tree.exists('apps/test-ui-lib-e2e/cypress.json')).toBeFalsy();
expect(
tree.exists(
'libs/test-ui-lib/src/lib/test-button/test-button.component.stories.ts'
)
).toBeFalsy();
expect(
tree.exists(
'libs/test-ui-lib/src/lib/test-other/test-other.component.stories.ts'
)
).toBeFalsy();
expect(
tree.exists(
'apps/test-ui-lib-e2e/src/integration/test-button/test-button.component.spec.ts'
)
).toBeFalsy();
expect(
tree.exists(
'apps/test-ui-lib-e2e/src/integration/test-other/test-other.component.spec.ts'
)
).toBeFalsy();
});
it('should configure storybook to use webpack 5', async () => {
await storybookConfigurationGenerator(tree, {
name: libName,
configureCypress: false,
generateCypressSpecs: false,
generateStories: false,
linter: Linter.None,
});
expect(
tree.read('libs/test-ui-lib/.storybook/main.js').toString()
).toMatchSnapshot();
});
it('should configure everything at once', async () => {
await storybookConfigurationGenerator(tree, <StorybookConfigurationOptions>{
name: libName,
configureCypress: true,
generateCypressSpecs: true,
generateStories: true,
});
expect(tree.exists('libs/test-ui-lib/.storybook/main.js')).toBeTruthy();
expect(
tree.exists('libs/test-ui-lib/.storybook/tsconfig.json')
).toBeTruthy();
expect(tree.exists('apps/test-ui-lib-e2e/cypress.json')).toBeTruthy();
expect(
tree.exists(
'libs/test-ui-lib/src/lib/test-button/test-button.component.stories.ts'
)
).toBeTruthy();
expect(
tree.exists(
'libs/test-ui-lib/src/lib/test-other/test-other.component.stories.ts'
)
).toBeTruthy();
expect(
tree.exists(
'apps/test-ui-lib-e2e/src/integration/test-button/test-button.component.spec.ts'
)
).toBeTruthy();
expect(
tree.exists(
'apps/test-ui-lib-e2e/src/integration/test-other/test-other.component.spec.ts'
)
).toBeTruthy();
});
it('should generate the right files', async () => {
await storybookConfigurationGenerator(tree, <StorybookConfigurationOptions>{
name: libName,
configureCypress: true,
generateCypressSpecs: true,
generateStories: true,
});
expect(listFiles(tree)).toMatchSnapshot();
});
it('should generate in the correct folder', async () => {
await storybookConfigurationGenerator(tree, <StorybookConfigurationOptions>{
name: libName,
configureCypress: true,
generateCypressSpecs: true,
generateStories: true,
cypressDirectory: 'one/two',
});
expect(listFiles(tree)).toMatchSnapshot();
});
});

View File

@ -0,0 +1,21 @@
import type { Tree } from '@nrwl/devkit';
import { assertCompatibleStorybookVersion } from './lib/assert-compatible-storybook-version';
import { generateStories } from './lib/generate-stories';
import { generateStorybookConfiguration } from './lib/generate-storybook-configuration';
import { validateOptions } from './lib/validate-options';
import type { StorybookConfigurationOptions } from './schema';
export async function storybookConfigurationGenerator(
tree: Tree,
options: StorybookConfigurationOptions
) {
assertCompatibleStorybookVersion();
validateOptions(options);
await generateStorybookConfiguration(tree, options);
if (options.generateStories) {
await generateStories(tree, options);
}
}
export default storybookConfigurationGenerator;

View File

@ -0,0 +1,155 @@
import type { Tree } from '@nrwl/devkit';
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
export async function createStorybookTestWorkspaceForLib(
libName: string
): Promise<Tree> {
let tree = createTreeWithEmptyWorkspace();
const libGenerator = wrapAngularDevkitSchematic('@nrwl/angular', 'library');
const moduleGenerator = wrapAngularDevkitSchematic(
'@schematics/angular',
'module'
);
const componentGenerator = wrapAngularDevkitSchematic(
'@schematics/angular',
'component'
);
await libGenerator(tree, { name: libName });
await componentGenerator(tree, {
name: 'test-button',
project: libName,
});
tree.write(
`libs/${libName}/src/lib/test-button/test-button.component.ts`,
`import { Component, OnInit, Input } from '@angular/core';
export type ButtonStyle = 'default' | 'primary' | 'accent';
@Component({
selector: 'proj-test-button',
templateUrl: './test-button.component.html',
styleUrls: ['./test-button.component.css']
})
export class TestButtonComponent implements OnInit {
@Input('buttonType') type = 'button';
@Input() style: ButtonStyle = 'default';
@Input() age: number;
@Input() isOn = false;
constructor() { }
ngOnInit() {
}
}`
);
tree.write(
`libs/${libName}/src/lib/test-button/test-button.component.html`,
`<button [attr.type]="type" [ngClass]="style"></button>`
);
const modulePath = `libs/${libName}/src/lib/${libName}.module.ts`;
tree.write(
modulePath,
`import * as ButtonExports from './test-button/test-button.component';
${tree.read(modulePath)}`
);
// create a module with component that gets exported in a barrel file
await moduleGenerator(tree, {
name: 'barrel',
project: libName,
});
await componentGenerator(tree, {
name: 'barrel-button',
project: libName,
path: `libs/${libName}/src/lib/barrel`,
module: 'barrel',
});
tree.write(
`libs/${libName}/src/lib/barrel/barrel-button/index.ts`,
`export * from './barrel-button.component';`
);
tree.write(
`libs/${libName}/src/lib/barrel/barrel.module.ts`,
`import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BarrelButtonComponent } from './barrel-button';
@NgModule({
imports: [CommonModule],
declarations: [BarrelButtonComponent],
})
export class BarrelModule {}`
);
// create a module with components that get Angular exported and declared by variable
await moduleGenerator(tree, {
name: 'variable-declare',
project: libName,
});
await componentGenerator(tree, {
name: 'variable-declare-button',
project: libName,
path: `libs/${libName}/src/lib/variable-declare`,
module: 'variable-declare',
});
await componentGenerator(tree, {
name: 'variable-declare-view',
project: libName,
path: `libs/${libName}/src/lib/variable-declare`,
module: 'variable-declare',
});
tree.write(
`libs/${libName}/src/lib/variable-declare/variable-declare.module.ts`,
`import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { VariableDeclareButtonComponent } from './variable-declare-button/variable-declare-button.component';
import { VariableDeclareViewComponent } from './variable-declare-view/variable-declare-view.component';
const COMPONENTS = [
VariableDeclareButtonComponent,
VariableDeclareViewComponent
]
@NgModule({
imports: [CommonModule],
declarations: COMPONENTS,
exports: COMPONENTS
})
export class VariableDeclareModule {}`
);
// create another button in a nested subpath
await moduleGenerator(tree, {
name: 'nested',
project: libName,
path: `libs/${libName}/src/lib`,
});
await componentGenerator(tree, {
name: 'nested-button',
project: libName,
module: 'nested',
path: `libs/${libName}/src/lib/nested`,
});
await componentGenerator(tree, {
name: 'test-other',
project: libName,
});
return tree;
}

View File

@ -1,4 +1,3 @@
export { applicationGenerator } from './application/application';
export { libraryGenerator } from './library/library';
export { ngrxGenerator } from './ngrx/ngrx';
export { storybookConfigurationGenerator } from './storybook-configuration/configuration';

View File

@ -1,168 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`schematic:configuration should configure storybook to use webpack 5 1`] = `
"const rootMain = require('../../../.storybook/main');
rootMain.core = { ...rootMain.core, builder: 'webpack5' };
// Use the following syntax to add addons!
// rootMain.addons.push('');
rootMain.stories.push(...['../src/lib/**/*.stories.mdx', '../src/lib/**/*.stories.@(js|jsx|ts|tsx)'])
module.exports = rootMain;
"
`;
exports[`schematic:configuration should generate in the correct folder 1`] = `
Array [
"/workspace.json",
"/package.json",
"/nx.json",
"/tsconfig.base.json",
"/tslint.json",
"/jest.config.js",
"/jest.preset.js",
"/.eslintrc.json",
"/libs/test-ui-lib/README.md",
"/libs/test-ui-lib/tsconfig.lib.json",
"/libs/test-ui-lib/tsconfig.json",
"/libs/test-ui-lib/jest.config.js",
"/libs/test-ui-lib/tsconfig.spec.json",
"/libs/test-ui-lib/.eslintrc.json",
"/libs/test-ui-lib/src/index.ts",
"/libs/test-ui-lib/src/test-setup.ts",
"/libs/test-ui-lib/src/lib/test-ui-lib.module.ts",
"/libs/test-ui-lib/src/lib/test-button/test-button.component.css",
"/libs/test-ui-lib/src/lib/test-button/test-button.component.html",
"/libs/test-ui-lib/src/lib/test-button/test-button.component.spec.ts",
"/libs/test-ui-lib/src/lib/test-button/test-button.component.ts",
"/libs/test-ui-lib/src/lib/test-button/test-button.component.stories.ts",
"/libs/test-ui-lib/src/lib/barrel/barrel.module.ts",
"/libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.css",
"/libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.html",
"/libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.spec.ts",
"/libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.ts",
"/libs/test-ui-lib/src/lib/barrel/barrel-button/index.ts",
"/libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.stories.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare.module.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.css",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.html",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.spec.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.stories.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.css",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.html",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.spec.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.stories.ts",
"/libs/test-ui-lib/src/lib/nested/nested.module.ts",
"/libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.css",
"/libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.html",
"/libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.spec.ts",
"/libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.ts",
"/libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.stories.ts",
"/libs/test-ui-lib/src/lib/test-other/test-other.component.css",
"/libs/test-ui-lib/src/lib/test-other/test-other.component.html",
"/libs/test-ui-lib/src/lib/test-other/test-other.component.spec.ts",
"/libs/test-ui-lib/src/lib/test-other/test-other.component.ts",
"/libs/test-ui-lib/src/lib/test-other/test-other.component.stories.ts",
"/libs/test-ui-lib/.storybook/main.js",
"/libs/test-ui-lib/.storybook/preview.js",
"/libs/test-ui-lib/.storybook/tsconfig.json",
"/libs/test-ui-lib/.storybook/webpack.config.js",
"/.storybook/main.js",
"/.storybook/tsconfig.json",
"/.storybook/webpack.config.js",
"/apps/one/two/test-ui-lib-e2e/cypress.json",
"/apps/one/two/test-ui-lib-e2e/tsconfig.e2e.json",
"/apps/one/two/test-ui-lib-e2e/tsconfig.json",
"/apps/one/two/test-ui-lib-e2e/.eslintrc.json",
"/apps/one/two/test-ui-lib-e2e/src/fixtures/example.json",
"/apps/one/two/test-ui-lib-e2e/src/plugins/index.js",
"/apps/one/two/test-ui-lib-e2e/src/support/commands.ts",
"/apps/one/two/test-ui-lib-e2e/src/support/index.ts",
"/apps/one/two/test-ui-lib-e2e/src/integration/test-button/test-button.component.spec.ts",
"/apps/one/two/test-ui-lib-e2e/src/integration/test-other/test-other.component.spec.ts",
"/apps/one/two/test-ui-lib-e2e/src/integration/barrel-button/barrel-button.component.spec.ts",
"/apps/one/two/test-ui-lib-e2e/src/integration/variable-declare-button/variable-declare-button.component.spec.ts",
"/apps/one/two/test-ui-lib-e2e/src/integration/variable-declare-view/variable-declare-view.component.spec.ts",
"/apps/one/two/test-ui-lib-e2e/src/integration/nested-button/nested-button.component.spec.ts",
]
`;
exports[`schematic:configuration should generate the right files 1`] = `
Array [
"/workspace.json",
"/package.json",
"/nx.json",
"/tsconfig.base.json",
"/tslint.json",
"/jest.config.js",
"/jest.preset.js",
"/.eslintrc.json",
"/libs/test-ui-lib/README.md",
"/libs/test-ui-lib/tsconfig.lib.json",
"/libs/test-ui-lib/tsconfig.json",
"/libs/test-ui-lib/jest.config.js",
"/libs/test-ui-lib/tsconfig.spec.json",
"/libs/test-ui-lib/.eslintrc.json",
"/libs/test-ui-lib/src/index.ts",
"/libs/test-ui-lib/src/test-setup.ts",
"/libs/test-ui-lib/src/lib/test-ui-lib.module.ts",
"/libs/test-ui-lib/src/lib/test-button/test-button.component.css",
"/libs/test-ui-lib/src/lib/test-button/test-button.component.html",
"/libs/test-ui-lib/src/lib/test-button/test-button.component.spec.ts",
"/libs/test-ui-lib/src/lib/test-button/test-button.component.ts",
"/libs/test-ui-lib/src/lib/test-button/test-button.component.stories.ts",
"/libs/test-ui-lib/src/lib/barrel/barrel.module.ts",
"/libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.css",
"/libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.html",
"/libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.spec.ts",
"/libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.ts",
"/libs/test-ui-lib/src/lib/barrel/barrel-button/index.ts",
"/libs/test-ui-lib/src/lib/barrel/barrel-button/barrel-button.component.stories.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare.module.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.css",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.html",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.spec.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-button/variable-declare-button.component.stories.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.css",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.html",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.spec.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.ts",
"/libs/test-ui-lib/src/lib/variable-declare/variable-declare-view/variable-declare-view.component.stories.ts",
"/libs/test-ui-lib/src/lib/nested/nested.module.ts",
"/libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.css",
"/libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.html",
"/libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.spec.ts",
"/libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.ts",
"/libs/test-ui-lib/src/lib/nested/nested-button/nested-button.component.stories.ts",
"/libs/test-ui-lib/src/lib/test-other/test-other.component.css",
"/libs/test-ui-lib/src/lib/test-other/test-other.component.html",
"/libs/test-ui-lib/src/lib/test-other/test-other.component.spec.ts",
"/libs/test-ui-lib/src/lib/test-other/test-other.component.ts",
"/libs/test-ui-lib/src/lib/test-other/test-other.component.stories.ts",
"/libs/test-ui-lib/.storybook/main.js",
"/libs/test-ui-lib/.storybook/preview.js",
"/libs/test-ui-lib/.storybook/tsconfig.json",
"/libs/test-ui-lib/.storybook/webpack.config.js",
"/.storybook/main.js",
"/.storybook/tsconfig.json",
"/.storybook/webpack.config.js",
"/apps/test-ui-lib-e2e/cypress.json",
"/apps/test-ui-lib-e2e/tsconfig.e2e.json",
"/apps/test-ui-lib-e2e/tsconfig.json",
"/apps/test-ui-lib-e2e/.eslintrc.json",
"/apps/test-ui-lib-e2e/src/fixtures/example.json",
"/apps/test-ui-lib-e2e/src/plugins/index.js",
"/apps/test-ui-lib-e2e/src/support/commands.ts",
"/apps/test-ui-lib-e2e/src/support/index.ts",
"/apps/test-ui-lib-e2e/src/integration/test-button/test-button.component.spec.ts",
"/apps/test-ui-lib-e2e/src/integration/test-other/test-other.component.spec.ts",
"/apps/test-ui-lib-e2e/src/integration/barrel-button/barrel-button.component.spec.ts",
"/apps/test-ui-lib-e2e/src/integration/variable-declare-button/variable-declare-button.component.spec.ts",
"/apps/test-ui-lib-e2e/src/integration/variable-declare-view/variable-declare-view.component.spec.ts",
"/apps/test-ui-lib-e2e/src/integration/nested-button/nested-button.component.spec.ts",
]
`;

View File

@ -1,140 +0,0 @@
import { Tree } from '@angular-devkit/schematics';
import { runSchematic } from '../../utils/testing';
import { StorybookConfigureSchema } from './schema';
import { createTestUILib } from '../stories/stories-lib.spec';
import * as fileUtils from '@nrwl/workspace/src/core/file-utils';
describe('schematic:configuration', () => {
let appTree: Tree;
beforeEach(async () => {
appTree = await createTestUILib('test-ui-lib');
jest.spyOn(fileUtils, 'readPackageJson').mockReturnValue({
devDependencies: {
'@storybook/addon-essentials': '^6.0.21',
'@storybook/react': '^6.0.21',
},
});
});
it('should only configure storybook', async () => {
const tree = await runSchematic(
'storybook-configuration',
<StorybookConfigureSchema>{
name: 'test-ui-lib',
configureCypress: false,
generateCypressSpecs: false,
generateStories: false,
},
appTree
);
expect(tree.exists('libs/test-ui-lib/.storybook/main.js')).toBeTruthy();
expect(
tree.exists('libs/test-ui-lib/.storybook/tsconfig.json')
).toBeTruthy();
expect(tree.exists('apps/test-ui-lib-e2e/cypress.json')).toBeFalsy();
expect(
tree.exists(
'libs/test-ui-lib/src/lib/test-button/test-button.component.stories.ts'
)
).toBeFalsy();
expect(
tree.exists(
'libs/test-ui-lib/src/lib/test-other/test-other.component.stories.ts'
)
).toBeFalsy();
expect(
tree.exists(
'apps/test-ui-lib-e2e/src/integration/test-button/test-button.component.spec.ts'
)
).toBeFalsy();
expect(
tree.exists(
'apps/test-ui-lib-e2e/src/integration/test-other/test-other.component.spec.ts'
)
).toBeFalsy();
});
it('should configure storybook to use webpack 5', async () => {
const tree = await runSchematic(
'storybook-configuration',
<StorybookConfigureSchema>{
name: 'test-ui-lib',
configureCypress: false,
generateCypressSpecs: false,
generateStories: false,
},
appTree
);
expect(
tree.readContent('libs/test-ui-lib/.storybook/main.js')
).toMatchSnapshot();
});
it('should configure everything at once', async () => {
const tree = await runSchematic(
'storybook-configuration',
<StorybookConfigureSchema>{
name: 'test-ui-lib',
configureCypress: true,
generateCypressSpecs: true,
generateStories: true,
},
appTree
);
expect(tree.exists('libs/test-ui-lib/.storybook/main.js')).toBeTruthy();
expect(
tree.exists('libs/test-ui-lib/.storybook/tsconfig.json')
).toBeTruthy();
expect(tree.exists('apps/test-ui-lib-e2e/cypress.json')).toBeTruthy();
expect(
tree.exists(
'libs/test-ui-lib/src/lib/test-button/test-button.component.stories.ts'
)
).toBeTruthy();
expect(
tree.exists(
'libs/test-ui-lib/src/lib/test-other/test-other.component.stories.ts'
)
).toBeTruthy();
expect(
tree.exists(
'apps/test-ui-lib-e2e/src/integration/test-button/test-button.component.spec.ts'
)
).toBeTruthy();
expect(
tree.exists(
'apps/test-ui-lib-e2e/src/integration/test-other/test-other.component.spec.ts'
)
).toBeTruthy();
});
it('should generate the right files', async () => {
const tree = await runSchematic(
'storybook-configuration',
<StorybookConfigureSchema>{
name: 'test-ui-lib',
configureCypress: true,
generateCypressSpecs: true,
generateStories: true,
},
appTree
);
expect(tree.files).toMatchSnapshot();
});
it('should generate in the correct folder', async () => {
const tree = await runSchematic(
'storybook-configuration',
<StorybookConfigureSchema>{
name: 'test-ui-lib',
configureCypress: true,
generateCypressSpecs: true,
generateStories: true,
cypressDirectory: 'one/two',
},
appTree
);
expect(tree.files).toMatchSnapshot();
});
});

View File

@ -1,68 +0,0 @@
import {
chain,
externalSchematic,
Rule,
schematic,
noop,
Tree,
} from '@angular-devkit/schematics';
import { StorybookStoriesSchema } from '../stories/stories';
import { StorybookConfigureSchema } from './schema';
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
import { getE2eProjectName } from '@nrwl/cypress/src/utils/project-name';
import { getWorkspace } from '@nrwl/workspace';
import { lt } from 'semver';
function assertCompatibleStorybookVersion() {
let storybookVersion: string;
try {
require(require.resolve('@storybook/angular/package.json')).version;
} catch {}
if (storybookVersion && lt(storybookVersion, '6.2.0')) {
throw new Error('Incompatible Storybook Version');
}
}
export default function (schema: StorybookConfigureSchema): Rule {
assertCompatibleStorybookVersion();
if (schema.generateCypressSpecs && !schema.generateStories) {
throw new Error(
'Cannot set generateCypressSpecs to true when generateStories is set to false.'
);
}
return chain([
externalSchematic('@nrwl/storybook', 'configuration', {
name: schema.name,
uiFramework: '@storybook/angular',
configureCypress: schema.configureCypress,
linter: schema.linter,
cypressDirectory: schema.cypressDirectory,
}),
schema.generateStories ? generateStories(schema) : noop(),
]);
}
function generateStories(schema: StorybookConfigureSchema): Rule {
return async (tree: Tree, context) => {
const workspace = await getWorkspace(tree);
const project = workspace.projects.get(schema.name);
const e2eProjectName = getE2eProjectName(
schema.name,
project.root,
schema.cypressDirectory
);
return schematic<StorybookStoriesSchema>('stories', {
name: schema.name,
generateCypressSpecs:
schema.configureCypress && schema.generateCypressSpecs,
cypressProject: e2eProjectName,
});
};
}
export const storybookConfigurationGenerator = wrapAngularDevkitSchematic(
'@nrwl/angular',
'storybook-configuration'
);

View File

@ -3,11 +3,20 @@ import { readJsonInTree, updateJsonInTree } from '@nrwl/workspace';
import { createTestUILib } from '../stories/stories-lib.spec';
import { callRule, runSchematic } from '../../utils/testing';
import { storybookVersion } from '../../../../storybook/src/utils/versions';
import { overrideCollectionResolutionForTesting } from '@nrwl/devkit/ngcli-adapter';
import { joinPathFragments } from '@nrwl/devkit';
describe('migrate-defaults-5-to-6 schematic', () => {
let appTree: Tree;
beforeEach(async () => {
overrideCollectionResolutionForTesting({
'@nrwl/storybook': joinPathFragments(
__dirname,
'../../../../storybook/collection.json'
),
});
appTree = await createTestUILib('test-ui-lib');
appTree = await callRule(