Skip to content

Commit

Permalink
feat(storybook): interaction testing story generator React
Browse files Browse the repository at this point in the history
  • Loading branch information
mandarini committed Jul 12, 2023
1 parent 810e082 commit b4e119f
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 55 deletions.
6 changes: 6 additions & 0 deletions docs/generated/packages/react/generators/component-story.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
"type": "boolean",
"default": false,
"x-priority": "internal"
},
"interactionTests": {
"type": "boolean",
"description": "Set up Storybook interaction tests.",
"default": true,
"x-priority": "important"
}
},
"required": ["project", "componentPath"],
Expand Down
13 changes: 10 additions & 3 deletions docs/generated/packages/react/generators/stories.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,19 @@
"generateCypressSpecs": {
"type": "boolean",
"description": "Automatically generate `*.spec.ts` files in the cypress e2e app generated by the cypress-configure generator.",
"x-prompt": "Do you want to generate Cypress specs as well?",
"x-priority": "important"
"x-deprecated": "Please use Storybook Interaction Testing instead."
},
"cypressProject": {
"type": "string",
"description": "The Cypress project to generate the stories under. This is inferred from `project` by default."
"description": "The Cypress project to generate the stories under. This is inferred from `project` by default.",
"x-deprecated": "Please use Storybook Interaction Testing instead."
},
"interactionTests": {
"type": "boolean",
"description": "Set up Storybook interaction tests.",
"x-prompt": "Do you want to set up Storybook Interaction Tests?",
"x-priority": "important",
"default": true
},
"js": {
"type": "boolean",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('react:component-story', () => {
await componentStoryGenerator(appTree, {
componentPath: 'lib/test-ui-lib.tsx',
project: 'test-ui-lib',
interactionTests: true,
});
} catch (e) {
expect(e.message).toContain(
Expand Down
22 changes: 8 additions & 14 deletions packages/react/src/generators/component-story/component-story.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ let tsModule: typeof import('typescript');
export interface CreateComponentStoriesFileSchema {
project: string;
componentPath: string;
interactionTests?: boolean;
skipFormat?: boolean;
}

export function createComponentStoriesFile(
host: Tree,
{ project, componentPath }: CreateComponentStoriesFileSchema
{ project, componentPath, interactionTests }: CreateComponentStoriesFileSchema
) {
if (!tsModule) {
tsModule = ensureTypescript();
Expand All @@ -42,12 +43,6 @@ export function createComponentStoriesFile(

const isPlainJs =
componentFilePath.endsWith('.jsx') || componentFilePath.endsWith('.js');
let fileExt = 'tsx';
if (componentFilePath.endsWith('.jsx')) {
fileExt = 'jsx';
} else if (componentFilePath.endsWith('.js')) {
fileExt = 'js';
}

const componentFileName = componentFilePath
.slice(componentFilePath.lastIndexOf('/') + 1)
Expand Down Expand Up @@ -81,8 +76,8 @@ export function createComponentStoriesFile(
declaration,
componentDirectory,
name,
interactionTests,
isPlainJs,
fileExt,
componentNodes.length > 1
);
});
Expand All @@ -98,8 +93,8 @@ export function createComponentStoriesFile(
cmpDeclaration,
componentDirectory,
name,
isPlainJs,
fileExt
interactionTests,
isPlainJs
);
}
}
Expand All @@ -110,8 +105,8 @@ export function findPropsAndGenerateFile(
cmpDeclaration: ts.Node,
componentDirectory: string,
name: string,
interactionTests: boolean,
isPlainJs: boolean,
fileExt: string,
fromNodeArray?: boolean
) {
const { propsTypeName, props, argTypes } = getDefaultsForComponent(
Expand All @@ -121,7 +116,7 @@ export function findPropsAndGenerateFile(

generateFiles(
host,
joinPathFragments(__dirname, './files'),
joinPathFragments(__dirname, `${'./files' + isPlainJs ? '/jsx' : '/tsx'}`),
normalizePath(componentDirectory),
{
componentFileName: fromNodeArray
Expand All @@ -132,8 +127,7 @@ export function findPropsAndGenerateFile(
props,
argTypes,
componentName: (cmpDeclaration as any).name.text,
isPlainJs,
fileExt,
interactionTests,
}
);
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import componentName from './<%= componentImportFileName %>';
<% if ( interactionTests ) { %>
import { within } from '@storybook/testing-library';
import { expect } from '@storybook/jest';
<% } %>

export default {
component: <%= componentName %>,
title: '<%= componentName %>',<% if ( argTypes && argTypes.length > 0 ) { %>
argTypes: {<% for (let argType of argTypes) { %>
<%= argType.name %>: { <%- argType.type %> : "<%- argType.actionText %>" },<% } %>
}
<% } %>
};

export const Primary = {
args: {<% for (let prop of props) { %>
<%= prop.name %>: <%- prop.defaultValue %>,<% } %>
},
};

<% if ( interactionTests ) { %>
export const Heading: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(canvas.getByText(/Welcome to <%=componentName%>!/gi)).toBeTruthy();
},
};
<% } %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { Meta, StoryObj } from '@storybook/react';
import { <%= componentName %> } from './<%= componentImportFileName %>';
<% if ( interactionTests ) { %>
import { within } from '@storybook/testing-library';
import { expect } from '@storybook/jest';
<% } %>

const meta: Meta<typeof <%= componentName %>> = {
component: <%= componentName %>,
title: '<%= componentName %>',<% if ( argTypes && argTypes.length > 0 ) { %>
argTypes: {<% for (let argType of argTypes) { %>
<%= argType.name %>: { <%- argType.type %> : "<%- argType.actionText %>" },<% } %>
}
<% } %>
};
export default meta;
type Story = StoryObj<typeof <%= componentName %>>;


export const Primary = {
args: {<% for (let prop of props) { %>
<%= prop.name %>: <%- prop.defaultValue %>,<% } %>
},
};

<% if ( interactionTests ) { %>
export const Heading: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
expect(canvas.getByText(/Welcome to <%=componentName%>!/gi)).toBeTruthy();
},
};
<% } %>
6 changes: 6 additions & 0 deletions packages/react/src/generators/component-story/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
"type": "boolean",
"default": false,
"x-priority": "internal"
},
"interactionTests": {
"type": "boolean",
"description": "Set up Storybook interaction tests.",
"default": true,
"x-priority": "important"
}
},
"required": ["project", "componentPath"]
Expand Down
13 changes: 10 additions & 3 deletions packages/react/src/generators/stories/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,19 @@
"generateCypressSpecs": {
"type": "boolean",
"description": "Automatically generate `*.spec.ts` files in the cypress e2e app generated by the cypress-configure generator.",
"x-prompt": "Do you want to generate Cypress specs as well?",
"x-priority": "important"
"x-deprecated": "Please use Storybook Interaction Testing instead."
},
"cypressProject": {
"type": "string",
"description": "The Cypress project to generate the stories under. This is inferred from `project` by default."
"description": "The Cypress project to generate the stories under. This is inferred from `project` by default.",
"x-deprecated": "Please use Storybook Interaction Testing instead."
},
"interactionTests": {
"type": "boolean",
"description": "Set up Storybook interaction tests.",
"x-prompt": "Do you want to set up Storybook Interaction Tests?",
"x-priority": "important",
"default": true
},
"js": {
"type": "boolean",
Expand Down
10 changes: 7 additions & 3 deletions packages/react/src/generators/stories/stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ let tsModule: typeof import('typescript');

export interface StorybookStoriesSchema {
project: string;
generateCypressSpecs: boolean;
interactionTests: boolean;
js?: boolean;
cypressProject?: string;
generateCypressSpecs?: boolean;
ignorePaths?: string[];
skipFormat?: boolean;
}
Expand Down Expand Up @@ -84,8 +85,9 @@ export function containsComponentDeclaration(
export async function createAllStories(
tree: Tree,
projectName: string,
generateCypressSpecs: boolean,
interactionTests: boolean,
js: boolean,
generateCypressSpecs?: boolean,
cypressProject?: string,
ignorePaths?: string[]
) {
Expand Down Expand Up @@ -142,6 +144,7 @@ export async function createAllStories(
componentPath: relativeCmpDir,
project: projectName,
skipFormat: true,
interactionTests,
});

if (generateCypressSpecs && e2eProject) {
Expand All @@ -164,8 +167,9 @@ export async function storiesGenerator(
await createAllStories(
host,
schema.project,
schema.generateCypressSpecs,
schema.interactionTests,
schema.js,
schema.generateCypressSpecs,
schema.cypressProject,
schema.ignorePaths
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ async function generateStories(host: Tree, schema: StorybookConfigureSchema) {
cypressProject,
ignorePaths: schema.ignorePaths,
skipFormat: true,
interactionTests: schema.interactionTests,
});
}

Expand Down

0 comments on commit b4e119f

Please sign in to comment.