Skip to content

Commit

Permalink
Final refactorings
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinpalkovic committed Apr 9, 2024
1 parent 4ea2268 commit 74fbb39
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 94 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { getStoryId, initCreateNewStoryChannel } from './create-new-story-channel';
import { initCreateNewStoryChannel } from './create-new-story-channel';
import path from 'path';
import type { ChannelTransport } from '@storybook/channels';
import { Channel } from '@storybook/channels';
Expand All @@ -15,16 +15,16 @@ vi.mock('@storybook/core-common', async (importOriginal) => {

const mockFs = vi.hoisted(() => {
return {
writeFileSync: vi.fn(),
writeFile: vi.fn(),
};
});

vi.mock('fs', async (importOriginal) => {
const actual = await importOriginal<typeof import('fs')>();
vi.mock('fs/promises', async (importOriginal) => {
const actual = await importOriginal<typeof import('fs/promises')>();
return {
default: {
...actual,
writeFileSync: mockFs.writeFileSync,
writeFile: mockFs.writeFile,
},
};
});
Expand All @@ -40,48 +40,6 @@ describe('createNewStoryChannel', () => {
createNewStoryFileEventListener.mockClear();
});

describe('getStoryId', () => {
it('should return the storyId', async () => {
const cwd = process.cwd();
const options = {
configDir: path.join(cwd, '.storybook'),
presets: {
apply: (val: string) => {
if (val === 'stories') {
return Promise.resolve(['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)']);
}
},
},
} as any;
const storyFilePath = path.join(cwd, 'src', 'components', 'stories', 'Page1.stories.ts');
const exportedStoryName = 'Default';

const storyId = await getStoryId(options, storyFilePath, exportedStoryName);

expect(storyId).toBe('components-stories-page1--default');
});

it('should throw an error if the storyId cannot be calculated', async () => {
const cwd = process.cwd();
const options = {
configDir: path.join(cwd, '.storybook'),
presets: {
apply: (val: string) => {
if (val === 'stories') {
return Promise.resolve(['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)']);
}
},
},
} as any;
const storyFilePath = path.join(cwd, 'not-covered-path', 'stories', 'Page1.stories.ts');
const exportedStoryName = 'Default';

await expect(() =>
getStoryId(options, storyFilePath, exportedStoryName)
).rejects.toThrowError();
});
});

describe('initCreateNewStoryChannel', () => {
it('should emit an event with a story id', async () => {
mockChannel.addListener(CREATE_NEW_STORYFILE_RESULT, createNewStoryFileEventListener);
Expand Down Expand Up @@ -124,7 +82,7 @@ describe('createNewStoryChannel', () => {
mockChannel.addListener(CREATE_NEW_STORYFILE_RESULT, createNewStoryFileEventListener);
const cwd = process.cwd();

mockFs.writeFileSync.mockImplementation(() => {
mockFs.writeFile.mockImplementation(() => {
throw new Error('Failed to write file');
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@ import type { Options } from '@storybook/types';
import type { Channel } from '@storybook/channels';
import { CREATE_NEW_STORYFILE, CREATE_NEW_STORYFILE_RESULT } from '../constants';
import dedent from 'ts-dedent';
import { normalizeStories, normalizeStoryPath } from '@storybook/core-common';
import path from 'path';
import fs from 'fs';
import { storyNameFromExport, toId } from '@storybook/csf';
import slash from 'slash';
import { userOrAutoTitleFromSpecifier } from '@storybook/preview-api';
import fs from 'fs/promises';
import { getNewStoryFile } from '../utils/get-new-story-file';
import { getStoryId } from '../utils/get-story-id';

interface Data {
// The filepath of the component for which the Story should be generated for (relative to the project root)
Expand Down Expand Up @@ -38,11 +34,11 @@ export function initCreateNewStoryChannel(channel: Channel, options: Options) {
options
);

fs.writeFileSync(storyFilePath, storyFileContent, {
await fs.writeFile(storyFilePath, storyFileContent, {
encoding: 'utf-8',
});

const storyId = await getStoryId(options, storyFilePath, exportedStoryName);
const storyId = await getStoryId({ storyFilePath, exportedStoryName }, options);

channel.emit(CREATE_NEW_STORYFILE_RESULT, {
success: true,
Expand All @@ -65,39 +61,3 @@ export function initCreateNewStoryChannel(channel: Channel, options: Options) {

return channel;
}

export async function getStoryId(
options: Options,
storyFilePath: string,
exportedStoryName: string
) {
const stories = await options.presets.apply('stories', [], options);

const workingDir = process.cwd();

const normalizedStories = normalizeStories(stories, {
configDir: options.configDir,
workingDir,
});

const relativePath = path.relative(workingDir, storyFilePath);
const importPath = slash(normalizeStoryPath(relativePath));

const autoTitle = normalizedStories
.map((normalizeStory) => userOrAutoTitleFromSpecifier(importPath, normalizeStory))
.filter(Boolean)[0];

if (autoTitle === undefined) {
// eslint-disable-next-line local-rules/no-uncategorized-errors
throw new Error(dedent`
The generation of your new Story file was successful! But it seems that we are unable to index it.
Please make sure that the new Story file is matched by the 'stories' glob pattern in your Storybook configuration.
The location of the new Story file is: ${relativePath}
`);
}

const storyName = storyNameFromExport(exportedStoryName);
const storyId = toId(autoTitle as string, storyName);

return storyId;
}
5 changes: 3 additions & 2 deletions code/addons/controls/src/utils/get-new-story-file.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ describe('get-new-story-file', () => {

expect(exportedStoryName).toBe('Default');
expect(storyFileContent).toMatchInlineSnapshot(`
"import { Page } from './Page';
import type { Meta, StoryObj } from '@storybook/nextjs';
"import type { Meta, StoryObj } from '@storybook/nextjs';
import { Page } from './Page';
const meta = {
component: Page
Expand Down
45 changes: 45 additions & 0 deletions code/addons/controls/src/utils/get-story-id.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import path from 'path';
import { describe, expect, it } from 'vitest';
import { getStoryId } from './get-story-id';

describe('getStoryId', () => {
it('should return the storyId', async () => {
const cwd = process.cwd();
const options = {
configDir: path.join(cwd, '.storybook'),
presets: {
apply: (val: string) => {
if (val === 'stories') {
return Promise.resolve(['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)']);
}
},
},
} as any;
const storyFilePath = path.join(cwd, 'src', 'components', 'stories', 'Page1.stories.ts');
const exportedStoryName = 'Default';

const storyId = await getStoryId({ storyFilePath, exportedStoryName }, options);

expect(storyId).toBe('components-stories-page1--default');
});

it('should throw an error if the storyId cannot be calculated', async () => {
const cwd = process.cwd();
const options = {
configDir: path.join(cwd, '.storybook'),
presets: {
apply: (val: string) => {
if (val === 'stories') {
return Promise.resolve(['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)']);
}
},
},
} as any;
const storyFilePath = path.join(cwd, 'not-covered-path', 'stories', 'Page1.stories.ts');
const exportedStoryName = 'Default';

await expect(() =>
getStoryId({ storyFilePath, exportedStoryName }, options)
).rejects.toThrowError();
});
});
44 changes: 44 additions & 0 deletions code/addons/controls/src/utils/get-story-id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { Options } from '@storybook/types';
import dedent from 'ts-dedent';
import { normalizeStories, normalizeStoryPath } from '@storybook/core-common';
import path from 'path';
import { storyNameFromExport, toId } from '@storybook/csf';
import slash from 'slash';
import { userOrAutoTitleFromSpecifier } from '@storybook/preview-api';

interface Data {
storyFilePath: string;
exportedStoryName: string;
}

export async function getStoryId(data: Data, options: Options) {
const stories = await options.presets.apply('stories', [], options);

const workingDir = process.cwd();

const normalizedStories = normalizeStories(stories, {
configDir: options.configDir,
workingDir,
});

const relativePath = path.relative(workingDir, data.storyFilePath);
const importPath = slash(normalizeStoryPath(relativePath));

const autoTitle = normalizedStories
.map((normalizeStory) => userOrAutoTitleFromSpecifier(importPath, normalizeStory))
.filter(Boolean)[0];

if (autoTitle === undefined) {
// eslint-disable-next-line local-rules/no-uncategorized-errors
throw new Error(dedent`
The generation of your new Story file was successful! But it seems that we are unable to index it.
Please make sure that the new Story file is matched by the 'stories' glob pattern in your Storybook configuration.
The location of the new Story file is: ${relativePath}
`);
}

const storyName = storyNameFromExport(data.exportedStoryName);
const storyId = toId(autoTitle as string, storyName);

return storyId;
}

0 comments on commit 74fbb39

Please sign in to comment.