Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: support stories config with configuration objects #424

Merged
merged 2 commits into from
Feb 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 50 additions & 1 deletion app/react-native/scripts/__snapshots__/loader.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,55 @@ import \\"@storybook/addon-ondevice-actions/register\\";
"
`;

exports[`loader writeRequires when there is a configuration object writes the story imports 1`] = `
"
/* do not change this file, it is auto generated by storybook. */

import { configure, addDecorator, addParameters, addArgsEnhancer, clearDecorators } from '@storybook/react-native';

global.STORIES = [{\\"titlePrefix\\":\\"ComponentsPrefix\\",\\"files\\":\\"**/*.stories.tsx\\",\\"directory\\":\\"./scripts/mocks/configuration-objects/components\\",\\"importPathMatcher\\":\\"^\\\\\\\\.[\\\\\\\\\\\\\\\\/](?:scripts\\\\\\\\/mocks\\\\\\\\/configuration-objects\\\\\\\\/components(?:\\\\\\\\/(?!\\\\\\\\.)(?:(?:(?!(?:^|\\\\\\\\/)\\\\\\\\.).)*?)\\\\\\\\/|\\\\\\\\/|$)(?!\\\\\\\\.)(?=.)[^/]*?\\\\\\\\.stories\\\\\\\\.tsx)$\\"}]

import \\"@storybook/addon-ondevice-notes/register\\";
import \\"@storybook/addon-ondevice-controls/register\\";
import \\"@storybook/addon-ondevice-backgrounds/register\\";
import \\"@storybook/addon-ondevice-actions/register\\";

import { argsEnhancers } from \\"@storybook/addon-actions/dist/modern/preset/addArgs\\"


import { decorators, parameters } from './preview';

if (decorators) {
if(__DEV__){
// stops the warning from showing on every HMR
require('react-native').LogBox.ignoreLogs([
'\`clearDecorators\` is deprecated and will be removed in Storybook 7.0',
]);
}
// workaround for global decorators getting infinitely applied on HMR, see https://github.com/storybookjs/react-native/issues/185
clearDecorators();
decorators.forEach((decorator) => addDecorator(decorator));
}

if (parameters) {
addParameters(parameters);
}



try {
argsEnhancers.forEach(enhancer => addArgsEnhancer(enhancer));
} catch{}


const getStories=() => {
return {\\"./scripts/mocks/configuration-objects/components/FakeStory.stories.tsx\\": require(\\"./components/FakeStory.stories.tsx\\")};
}

configure(getStories, module, false)
"
`;

exports[`loader writeRequires when there is a story glob and exclude paths globs writes the story imports 1`] = `
"
/* do not change this file, it is auto generated by storybook. */
Expand Down Expand Up @@ -91,7 +140,7 @@ import \\"@storybook/addon-ondevice-actions/register\\";


const getStories=() => {
return {\\"./scripts/mocks/exclude-config-files/include-components/FakeStory.stories.tsx\\": require(\\"include-components/FakeStory.stories.tsx\\")};
return {\\"./scripts/mocks/exclude-config-files/include-components/FakeStory.stories.tsx\\": require(\\"./include-components/FakeStory.stories.tsx\\")};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed this snapshot but it seems correct now?

}

configure(getStories, module, false)
Expand Down
45 changes: 29 additions & 16 deletions app/react-native/scripts/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ function getPreviewExists({ configPath }) {
return !!getFilePathExtension({ configPath }, 'preview');
}

function ensureRelativePathHasDot(relativePath) {
return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
}

function writeRequires({ configPath, absolute = false }) {
const storybookRequiresLocation = path.resolve(cwd, configPath, 'storybook.requires.js');

Expand All @@ -81,13 +85,30 @@ function writeRequires({ configPath, absolute = false }) {
const excludePaths = reactNativeOptions && reactNativeOptions.excludePaths;
const normalizedExcludePaths = normalizeExcludePaths(excludePaths);

const storyPaths = main.stories.reduce((acc, storyGlob) => {
const paths = glob.sync(storyGlob, {
cwd: path.resolve(cwd, configPath),
absolute,
// default to always ignore (exclude) anything in node_modules
ignore: normalizedExcludePaths !== undefined ? normalizedExcludePaths : ['**/node_modules'],
});
const storiesSpecifiers = normalizeStories(main.stories, {
configDir: configPath,
workingDir: cwd,
});

const storyRequires = storiesSpecifiers.reduce((acc, specifier) => {
const paths = glob
.sync(specifier.files, {
cwd: path.resolve(cwd, specifier.directory),
absolute,
// default to always ignore (exclude) anything in node_modules
ignore: normalizedExcludePaths !== undefined ? normalizedExcludePaths : ['**/node_modules'],
})
.map((storyPath) => {
const pathWithDirectory = path.join(specifier.directory, storyPath);
const requirePath = absolute
? storyPath
: ensureRelativePathHasDot(path.relative(configPath, pathWithDirectory));

const absolutePath = absolute ? requirePath : path.resolve(configPath, requirePath);
const pathRelativeToCwd = path.relative(cwd, absolutePath);

return `"./${pathRelativeToCwd}": require("${requirePath}")`;
});
return [...acc, ...paths];
}, []);

Expand All @@ -97,15 +118,7 @@ function writeRequires({ configPath, absolute = false }) {

let previewJs = previewExists ? previewImports : '';

const storyRequires = storyPaths
.map((storyPath) => {
const storyPathToAbsolute = path.resolve(configPath, storyPath);
const relative = path.relative(cwd, storyPathToAbsolute);
return `"./${relative}": require("${storyPath}")`;
})
.join(',');

const path_obj_str = `{${storyRequires}}`;
const path_obj_str = `{${storyRequires.join(',')}}`;

const registerAddons = main.addons?.map((addon) => `import "${addon}/register";`).join('\n');
let enhancersImport = '';
Expand Down
10 changes: 10 additions & 0 deletions app/react-native/scripts/loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,5 +171,15 @@ describe('loader', () => {
);
});
});

describe('when there is a configuration object', () => {
it('writes the story imports', () => {
writeRequires({ configPath: 'scripts/mocks/configuration-objects' });
expect(pathMock).toEqual(
path.resolve(__dirname, 'mocks/configuration-objects/storybook.requires.js')
);
expect(fileContentMock).toMatchSnapshot();
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const FakeComponent = () => null;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { FakeComponent } from './FakeComponent';

export default {
component: FakeComponent,
};

export const Basic = {
args: {},
};
15 changes: 15 additions & 0 deletions app/react-native/scripts/mocks/configuration-objects/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = {
stories: [
{
files: '**/*.stories.tsx',
directory: './components',
titlePrefix: 'ComponentsPrefix',
},
],
addons: [
'@storybook/addon-ondevice-notes',
'@storybook/addon-ondevice-controls',
'@storybook/addon-ondevice-backgrounds',
'@storybook/addon-ondevice-actions',
],
};
24 changes: 24 additions & 0 deletions app/react-native/scripts/mocks/configuration-objects/preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { withBackgrounds } from '@storybook/addon-ondevice-backgrounds';

export const decorators = [
(StoryFn) => (
<View style={styles.container}>
<StoryFn />
</View>
),
withBackgrounds,
];
export const parameters = {
my_param: 'anything',
backgrounds: [
{ name: 'plain', value: 'white', default: true },
{ name: 'warm', value: 'hotpink' },
{ name: 'cool', value: 'deepskyblue' },
],
};

const styles = StyleSheet.create({
container: { padding: 8, flex: 1 },
});