nx/packages/angular/src/generators/storybook-configuration/storybook-configuration.spec.ts
Colum Ferry 85c8916087
fix(core): addPlugin should not conflict on project.json targets (#23264)
<!-- 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` -->

## Current Behavior
<!-- This is the behavior we have today -->
Calculating conflicts in target names does not consider if the
project.json defined targets will actually be impacted by the plugin
that wants to be added creating false negatives

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Calculating conflicts should be more accurate

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #22476
2024-05-13 10:53:09 -04:00

218 lines
6.9 KiB
TypeScript

import 'nx/src/internal-testing-utils/mock-load-nx-plugin';
import { installedCypressVersion } from '@nx/cypress/src/utils/cypress-version';
import type { Tree } from '@nx/devkit';
import { readJson, writeJson } from '@nx/devkit';
import { Linter } from '@nx/eslint/src/generators/utils/linter';
import { componentGenerator } from '../component/component';
import { librarySecondaryEntryPointGenerator } from '../library-secondary-entry-point/library-secondary-entry-point';
import {
createStorybookTestWorkspaceForLib,
generateTestApplication,
} from '../utils/testing';
import type { StorybookConfigurationOptions } from './schema';
import { storybookConfigurationGenerator } from './storybook-configuration';
// need to mock cypress otherwise it'll use the nx installed version from package.json
// which is v9 while we are testing for the new v10 version
jest.mock('@nx/cypress/src/utils/cypress-version');
// nested code imports graph from the repo, which might have innacurate graph version
jest.mock('nx/src/project-graph/project-graph', () => ({
...jest.requireActual<any>('nx/src/project-graph/project-graph'),
createProjectGraphAsync: jest
.fn()
.mockImplementation(async () => ({ nodes: {}, dependencies: {} })),
}));
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';
let mockedInstalledCypressVersion: jest.Mock<
ReturnType<typeof installedCypressVersion>
> = installedCypressVersion as never;
beforeEach(async () => {
mockedInstalledCypressVersion.mockReturnValue(10);
tree = await createStorybookTestWorkspaceForLib(libName);
jest.resetModules();
});
it('should only configure storybook', async () => {
await storybookConfigurationGenerator(tree, <StorybookConfigurationOptions>{
project: libName,
generateStories: false,
skipFormat: true,
});
expect(tree.exists('test-ui-lib/.storybook/main.ts')).toBeTruthy();
expect(tree.exists('test-ui-lib/.storybook/tsconfig.json')).toBeTruthy();
expect(
tree.exists(
'test-ui-lib/src/lib/test-button/test-button.component.stories.ts'
)
).toBeFalsy();
expect(
tree.exists(
'test-ui-lib/src/lib/test-other/test-other.component.stories.ts'
)
).toBeFalsy();
});
it('should configure storybook to use webpack 5', async () => {
await storybookConfigurationGenerator(tree, {
project: libName,
generateStories: false,
linter: Linter.None,
skipFormat: true,
});
expect(
tree.read('test-ui-lib/.storybook/main.ts', 'utf-8')
).toMatchSnapshot();
});
it('should configure storybook with interaction tests and install dependencies', async () => {
await storybookConfigurationGenerator(tree, <StorybookConfigurationOptions>{
project: libName,
generateStories: true,
});
expect(tree.exists('test-ui-lib/.storybook/main.ts')).toBeTruthy();
expect(tree.exists('test-ui-lib/.storybook/tsconfig.json')).toBeTruthy();
expect(
tree.read(
'test-ui-lib/src/lib/test-button/test-button.component.stories.ts',
'utf-8'
)
).toMatchSnapshot();
expect(
tree.read(
'test-ui-lib/src/lib/test-other/test-other.component.stories.ts',
'utf-8'
)
).toMatchSnapshot();
const packageJson = JSON.parse(tree.read('package.json', 'utf-8'));
expect(packageJson.devDependencies['@storybook/angular']).toBeDefined();
expect(
packageJson.devDependencies['@storybook/addon-interactions']
).toBeDefined();
expect(packageJson.devDependencies['@storybook/test-runner']).toBeDefined();
expect(
packageJson.devDependencies['@storybook/testing-library']
).toBeDefined();
});
it('should generate the right files', async () => {
// add standalone component
await componentGenerator(tree, {
name: 'standalone',
project: libName,
standalone: true,
skipFormat: true,
});
// add secondary entrypoint
writeJson(tree, `${libName}/package.json`, { name: libName });
await librarySecondaryEntryPointGenerator(tree, {
library: libName,
name: 'secondary-entry-point',
skipFormat: true,
});
// add a regular component to the secondary entrypoint
await componentGenerator(tree, {
name: 'secondary-button',
project: libName,
path: `${libName}/secondary-entry-point/src/lib`,
export: true,
skipFormat: true,
});
// add a standalone component to the secondary entrypoint
await componentGenerator(tree, {
name: 'secondary-standalone',
project: libName,
path: `${libName}/secondary-entry-point/src/lib`,
standalone: true,
export: true,
skipFormat: true,
});
await storybookConfigurationGenerator(tree, <StorybookConfigurationOptions>{
project: libName,
generateStories: true,
skipFormat: true,
});
expect(listFiles(tree)).toMatchSnapshot();
});
it('should generate in the correct folder', async () => {
// add standalone component
await componentGenerator(tree, {
name: 'standalone',
project: libName,
standalone: true,
skipFormat: true,
});
// add secondary entrypoint
writeJson(tree, `${libName}/package.json`, { name: libName });
await librarySecondaryEntryPointGenerator(tree, {
library: libName,
name: 'secondary-entry-point',
skipFormat: true,
});
// add a regular component to the secondary entrypoint
await componentGenerator(tree, {
name: 'secondary-button',
project: libName,
path: `${libName}/secondary-entry-point/src/lib`,
export: true,
skipFormat: true,
});
// add a standalone component to the secondary entrypoint
await componentGenerator(tree, {
name: 'secondary-standalone',
project: libName,
path: `${libName}/secondary-entry-point/src/lib`,
standalone: true,
export: true,
skipFormat: true,
});
await storybookConfigurationGenerator(tree, <StorybookConfigurationOptions>{
project: libName,
generateStories: true,
skipFormat: true,
});
expect(listFiles(tree)).toMatchSnapshot();
});
it('should exclude Storybook-related files from tsconfig.editor.json for applications', async () => {
await generateTestApplication(tree, { name: 'test-app' });
await storybookConfigurationGenerator(tree, {
project: 'test-app',
generateStories: false,
skipFormat: true,
linter: Linter.EsLint,
});
const tsConfig = readJson(tree, 'test-app/tsconfig.editor.json');
expect(tsConfig.exclude).toStrictEqual(
expect.arrayContaining(['**/*.stories.ts', '**/*.stories.js'])
);
});
});