mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-06 07:21:16 +08:00
475 lines
13 KiB
JavaScript
475 lines
13 KiB
JavaScript
function wrapPreset(basePresets) {
|
|
return {
|
|
babel: async (config, args) => basePresets.apply('babel', config, args),
|
|
webpack: async (config, args) => basePresets.apply('webpack', config, args),
|
|
};
|
|
}
|
|
|
|
function mockPreset(name, mockPresetObject) {
|
|
jest.mock(name, () => mockPresetObject, { virtual: true });
|
|
}
|
|
|
|
jest.mock('@storybook/node-logger', () => ({
|
|
logger: {
|
|
info: jest.fn(),
|
|
warn: jest.fn(),
|
|
error: jest.fn(),
|
|
},
|
|
}));
|
|
|
|
jest.mock('./utils/resolve-file', () => ({
|
|
resolveFile: (name) => {
|
|
const KNOWN_FILES = [
|
|
'@storybook/addon-actions/register',
|
|
'@storybook/addon-docs',
|
|
'@storybook/addon-docs/preset',
|
|
'@storybook/addon-knobs',
|
|
'@storybook/addon-notes/register-panel',
|
|
'@storybook/preset-typescript',
|
|
'addon-bar/preset.js',
|
|
'addon-baz/register.js',
|
|
'addon-foo/register.js',
|
|
];
|
|
if (KNOWN_FILES.includes(name)) {
|
|
return name;
|
|
}
|
|
throw new Error(`Cannot find module '${name}'`);
|
|
},
|
|
}));
|
|
|
|
describe('presets', () => {
|
|
it('does not throw when there is no preset file', async () => {
|
|
const getPresets = jest.requireActual('./presets').default;
|
|
let presets;
|
|
|
|
async function testPresets() {
|
|
presets = wrapPreset(getPresets());
|
|
await presets.webpack();
|
|
await presets.babel();
|
|
}
|
|
|
|
await expect(testPresets()).resolves.toBeUndefined();
|
|
|
|
expect(presets).toBeDefined();
|
|
});
|
|
|
|
it('does not throw when presets are empty', async () => {
|
|
const getPresets = jest.requireActual('./presets').default;
|
|
const presets = wrapPreset(getPresets([]));
|
|
|
|
async function testPresets() {
|
|
await presets.webpack();
|
|
await presets.babel();
|
|
}
|
|
|
|
await expect(testPresets()).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('does not throw when preset can not be loaded', async () => {
|
|
const getPresets = jest.requireActual('./presets').default;
|
|
const presets = wrapPreset(getPresets(['preset-foo']));
|
|
|
|
async function testPresets() {
|
|
await presets.webpack();
|
|
await presets.babel();
|
|
}
|
|
|
|
await expect(testPresets()).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('loads and applies presets when they are combined in another preset', async () => {
|
|
mockPreset('preset-foo', {
|
|
foo: (exec) => exec.concat('foo'),
|
|
});
|
|
|
|
mockPreset('preset-bar', {
|
|
foo: (exec) => exec.concat('bar'),
|
|
});
|
|
|
|
mockPreset('preset-got', [
|
|
'preset-dracarys',
|
|
{ name: 'preset-valar', options: { custom: 'morghulis' } },
|
|
]);
|
|
|
|
mockPreset('preset-dracarys', {
|
|
foo: (exec) => exec.concat('dracarys'),
|
|
});
|
|
|
|
mockPreset('preset-valar', {
|
|
foo: (exec, options) => exec.concat(`valar ${options.custom}`),
|
|
});
|
|
|
|
const getPresets = jest.requireActual('./presets').default;
|
|
const presets = getPresets(['preset-foo', 'preset-got', 'preset-bar']);
|
|
|
|
const result = await presets.apply('foo', []);
|
|
|
|
expect(result).toEqual(['foo', 'dracarys', 'valar morghulis', 'bar']);
|
|
});
|
|
|
|
it('loads and applies presets when they are declared as a string', async () => {
|
|
const mockPresetFooExtendWebpack = jest.fn();
|
|
const mockPresetBarExtendBabel = jest.fn();
|
|
|
|
mockPreset('preset-foo', {
|
|
webpack: mockPresetFooExtendWebpack,
|
|
});
|
|
|
|
mockPreset('preset-bar', {
|
|
babel: mockPresetBarExtendBabel,
|
|
});
|
|
|
|
const getPresets = jest.requireActual('./presets').default;
|
|
const presets = wrapPreset(getPresets(['preset-foo', 'preset-bar']));
|
|
|
|
async function testPresets() {
|
|
await presets.webpack();
|
|
await presets.babel();
|
|
}
|
|
|
|
await expect(testPresets()).resolves.toBeUndefined();
|
|
|
|
expect(mockPresetFooExtendWebpack).toHaveBeenCalled();
|
|
expect(mockPresetBarExtendBabel).toHaveBeenCalled();
|
|
});
|
|
|
|
it('loads and applies presets when they are declared as an object without props', async () => {
|
|
const mockPresetFooExtendWebpack = jest.fn();
|
|
const mockPresetBarExtendBabel = jest.fn();
|
|
|
|
mockPreset('preset-foo', {
|
|
webpack: mockPresetFooExtendWebpack,
|
|
});
|
|
|
|
mockPreset('preset-bar', {
|
|
babel: mockPresetBarExtendBabel,
|
|
});
|
|
|
|
const getPresets = jest.requireActual('./presets').default;
|
|
const presets = wrapPreset(getPresets([{ name: 'preset-foo' }, { name: 'preset-bar' }]));
|
|
|
|
async function testPresets() {
|
|
await presets.webpack();
|
|
await presets.babel();
|
|
}
|
|
|
|
await expect(testPresets()).resolves.toBeUndefined();
|
|
|
|
expect(mockPresetFooExtendWebpack).toHaveBeenCalled();
|
|
expect(mockPresetBarExtendBabel).toHaveBeenCalled();
|
|
});
|
|
|
|
it('loads and applies presets when they are declared as an object with props', async () => {
|
|
const mockPresetFooExtendWebpack = jest.fn();
|
|
const mockPresetBarExtendBabel = jest.fn();
|
|
|
|
mockPreset('preset-foo', {
|
|
webpack: mockPresetFooExtendWebpack,
|
|
});
|
|
|
|
mockPreset('preset-bar', {
|
|
babel: mockPresetBarExtendBabel,
|
|
});
|
|
|
|
const getPresets = jest.requireActual('./presets').default;
|
|
const presets = wrapPreset(
|
|
getPresets([
|
|
{ name: 'preset-foo', options: { foo: 1 } },
|
|
{ name: 'preset-bar', options: { bar: 'a' } },
|
|
])
|
|
);
|
|
|
|
async function testPresets() {
|
|
await presets.webpack({});
|
|
await presets.babel({});
|
|
}
|
|
|
|
await expect(testPresets()).resolves.toBeUndefined();
|
|
|
|
expect(mockPresetFooExtendWebpack).toHaveBeenCalledWith(expect.anything(), {
|
|
foo: 1,
|
|
presetsList: expect.anything(),
|
|
});
|
|
expect(mockPresetBarExtendBabel).toHaveBeenCalledWith(expect.anything(), {
|
|
bar: 'a',
|
|
presetsList: expect.anything(),
|
|
});
|
|
});
|
|
|
|
it('loads and applies presets when they are declared as a string and as an object', async () => {
|
|
const mockPresetFooExtendWebpack = jest.fn();
|
|
const mockPresetBarExtendBabel = jest.fn();
|
|
|
|
mockPreset('preset-foo', {
|
|
webpack: mockPresetFooExtendWebpack,
|
|
});
|
|
|
|
mockPreset('preset-bar', {
|
|
babel: mockPresetBarExtendBabel,
|
|
});
|
|
|
|
const getPresets = jest.requireActual('./presets').default;
|
|
const presets = wrapPreset(
|
|
getPresets([
|
|
'preset-foo',
|
|
{
|
|
name: 'preset-bar',
|
|
options: {
|
|
bar: 'a',
|
|
},
|
|
},
|
|
])
|
|
);
|
|
|
|
async function testPresets() {
|
|
await presets.webpack({});
|
|
await presets.babel({});
|
|
}
|
|
|
|
await expect(testPresets()).resolves.toBeUndefined();
|
|
|
|
expect(mockPresetFooExtendWebpack).toHaveBeenCalled();
|
|
expect(mockPresetBarExtendBabel).toHaveBeenCalledWith(expect.anything(), {
|
|
bar: 'a',
|
|
presetsList: expect.arrayContaining([
|
|
expect.objectContaining({ name: 'preset-foo' }),
|
|
expect.objectContaining({ name: 'preset-bar' }),
|
|
]),
|
|
});
|
|
});
|
|
|
|
it('applies presets in chain', async () => {
|
|
const mockPresetFooExtendWebpack = jest.fn(() => ({}));
|
|
const mockPresetBarExtendWebpack = jest.fn(() => ({}));
|
|
|
|
mockPreset('preset-foo', {
|
|
webpack: mockPresetFooExtendWebpack,
|
|
});
|
|
|
|
mockPreset('preset-bar', {
|
|
webpack: mockPresetBarExtendWebpack,
|
|
});
|
|
|
|
const getPresets = jest.requireActual('./presets').default;
|
|
const presets = wrapPreset(
|
|
getPresets([
|
|
'preset-foo',
|
|
{
|
|
name: 'preset-bar',
|
|
options: {
|
|
bar: 'a',
|
|
presetsList: expect.arrayContaining([
|
|
expect.objectContaining({ name: 'preset-foo' }),
|
|
expect.objectContaining({ name: 'preset-bar' }),
|
|
]),
|
|
},
|
|
},
|
|
])
|
|
);
|
|
|
|
async function testPresets() {
|
|
await presets.webpack();
|
|
await presets.babel();
|
|
}
|
|
|
|
await expect(testPresets()).resolves.toBeUndefined();
|
|
|
|
expect(mockPresetFooExtendWebpack).toHaveBeenCalled();
|
|
expect(mockPresetBarExtendWebpack).toHaveBeenCalledWith(expect.anything(), {
|
|
bar: 'a',
|
|
presetsList: expect.arrayContaining([
|
|
expect.objectContaining({ name: 'preset-foo' }),
|
|
expect.objectContaining({ name: 'preset-bar' }),
|
|
]),
|
|
});
|
|
});
|
|
|
|
it('allows for presets to export presets array', async () => {
|
|
const getPresets = jest.requireActual('./presets').default;
|
|
const input = {};
|
|
const mockPresetBar = jest.fn(() => input);
|
|
|
|
mockPreset('preset-foo', {
|
|
presets: ['preset-bar'],
|
|
});
|
|
|
|
mockPreset('preset-bar', {
|
|
bar: mockPresetBar,
|
|
});
|
|
|
|
const presets = getPresets(['preset-foo']);
|
|
|
|
const output = await presets.apply('bar');
|
|
|
|
expect(mockPresetBar).toHaveBeenCalledWith(undefined, expect.any(Object));
|
|
|
|
expect(input).toBe(output);
|
|
});
|
|
|
|
it('allows for presets to export presets fn', async () => {
|
|
const getPresets = jest.requireActual('./presets').default;
|
|
const input = {};
|
|
const storybookOptions = { a: 1 };
|
|
const presetOptions = { b: 2 };
|
|
const mockPresetBar = jest.fn(() => input);
|
|
const mockPresetFoo = jest.fn(() => ['preset-bar']);
|
|
|
|
mockPreset('preset-foo', {
|
|
presets: mockPresetFoo,
|
|
});
|
|
|
|
mockPreset('preset-bar', {
|
|
bar: mockPresetBar,
|
|
});
|
|
|
|
const presets = getPresets([{ name: 'preset-foo', options: { b: 2 } }], storybookOptions);
|
|
|
|
const output = await presets.apply('bar');
|
|
|
|
expect(mockPresetFoo).toHaveBeenCalledWith({ ...storybookOptions, ...presetOptions });
|
|
expect(mockPresetBar).toHaveBeenCalledWith(undefined, expect.any(Object));
|
|
|
|
expect(input).toBe(output);
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.resetModules();
|
|
});
|
|
});
|
|
|
|
describe('resolveAddonName', () => {
|
|
const { resolveAddonName } = jest.requireActual('./presets');
|
|
|
|
it('should resolve packages with metadata (relative path)', () => {
|
|
expect(resolveAddonName('@storybook/addon-docs')).toEqual({
|
|
name: '@storybook/addon-docs/preset',
|
|
type: 'presets',
|
|
});
|
|
});
|
|
|
|
it('should resolve packages with metadata (absolute path)', () => {
|
|
expect(resolveAddonName('@storybook/addon-knobs')).toEqual({
|
|
name: '@storybook/addon-knobs',
|
|
type: 'presets',
|
|
});
|
|
});
|
|
|
|
it('should resolve packages without metadata', () => {
|
|
expect(resolveAddonName('@storybook/preset-create-react-app')).toEqual({
|
|
name: '@storybook/preset-create-react-app',
|
|
type: 'presets',
|
|
});
|
|
});
|
|
|
|
it('should resolve managerEntries', () => {
|
|
expect(resolveAddonName('@storybook/addon-actions/register')).toEqual({
|
|
name: '@storybook/addon-actions/register',
|
|
type: 'managerEntries',
|
|
});
|
|
});
|
|
|
|
it('should resolve presets', () => {
|
|
expect(resolveAddonName('@storybook/addon-docs')).toEqual({
|
|
name: '@storybook/addon-docs/preset',
|
|
type: 'presets',
|
|
});
|
|
});
|
|
|
|
it('should resolve preset packages', () => {
|
|
expect(resolveAddonName('@storybook/addon-essentials')).toEqual({
|
|
name: '@storybook/addon-essentials',
|
|
type: 'presets',
|
|
});
|
|
});
|
|
|
|
it('should error on invalid inputs', () => {
|
|
expect(() => resolveAddonName(null)).toThrow();
|
|
});
|
|
});
|
|
|
|
describe('loadPreset', () => {
|
|
const { loadPreset } = jest.requireActual('./presets');
|
|
|
|
mockPreset('@storybook/preset-typescript', {});
|
|
mockPreset('@storybook/addon-docs', {});
|
|
mockPreset('@storybook/addon-actions/register', {});
|
|
mockPreset('addon-foo/register.js', {});
|
|
mockPreset('addon-bar/preset.js', {});
|
|
mockPreset('addon-baz/register.js', {});
|
|
mockPreset('@storybook/addon-notes/register-panel', {});
|
|
|
|
it('should resolve all addons & presets in correct order', () => {
|
|
const loaded = loadPreset({
|
|
type: 'managerEntries',
|
|
name: '',
|
|
presets: ['@storybook/preset-typescript'],
|
|
addons: [
|
|
'@storybook/addon-docs',
|
|
'@storybook/addon-actions/register',
|
|
'addon-foo/register.js',
|
|
'addon-bar',
|
|
'addon-baz/register.tsx',
|
|
'@storybook/addon-notes/register-panel',
|
|
],
|
|
});
|
|
expect(loaded).toEqual([
|
|
{
|
|
name: '@storybook/preset-typescript',
|
|
options: {},
|
|
preset: {},
|
|
},
|
|
{
|
|
name: '@storybook/addon-actions/register_additionalManagerEntries',
|
|
options: {},
|
|
preset: {
|
|
managerEntries: ['@storybook/addon-actions/register'],
|
|
},
|
|
},
|
|
{
|
|
name: 'addon-foo/register.js_additionalManagerEntries',
|
|
options: {},
|
|
preset: {
|
|
managerEntries: ['addon-foo/register.js'],
|
|
},
|
|
},
|
|
// should be there, but some file mocking problem is causing it to not resolve
|
|
// {
|
|
// name: 'addon-bar',
|
|
// options: {},
|
|
// preset: {},
|
|
// },
|
|
{
|
|
name: 'addon-baz/register.tsx_additionalManagerEntries',
|
|
options: {},
|
|
preset: {
|
|
managerEntries: ['addon-baz/register.tsx'],
|
|
},
|
|
},
|
|
{
|
|
name: '@storybook/addon-notes/register-panel_additionalManagerEntries',
|
|
options: {},
|
|
preset: {
|
|
managerEntries: ['@storybook/addon-notes/register-panel'],
|
|
},
|
|
},
|
|
{
|
|
name: {
|
|
presets: ['@storybook/preset-typescript'],
|
|
addons: [
|
|
'@storybook/addon-docs',
|
|
'@storybook/addon-actions/register',
|
|
'addon-foo/register.js',
|
|
'addon-bar',
|
|
'addon-baz/register.tsx',
|
|
'@storybook/addon-notes/register-panel',
|
|
],
|
|
name: '',
|
|
type: 'managerEntries',
|
|
},
|
|
options: {},
|
|
preset: {},
|
|
},
|
|
]);
|
|
});
|
|
});
|