Got Storyshots working

This commit is contained in:
Tom Coleman 2021-10-29 14:10:25 +11:00
parent b985baf299
commit 133ff93f5e
3 changed files with 61 additions and 48 deletions

View File

@ -6,7 +6,7 @@ import integrityTest from './integrityTestTemplate';
import loadFramework from '../frameworks/frameworkLoader';
import { StoryshotsOptions } from './StoryshotsOptions';
const { describe } = global;
const { describe, window: globalWindow } = global;
global.STORYBOOK_REACT_CLASSES = global.STORYBOOK_REACT_CLASSES || {};
type TestMethod = 'beforeAll' | 'beforeEach' | 'afterEach' | 'afterAll';
@ -48,55 +48,62 @@ function testStorySnapshots(options: StoryshotsOptions = {}) {
stories2snapsConverter,
};
const data = storybook.raw().reduce(
(acc, item) => {
if (storyNameRegex && !item.name.match(storyNameRegex)) {
return acc;
}
if (storyKindRegex && !item.kind.match(storyKindRegex)) {
return acc;
}
const { kind, storyFn: render, parameters } = item;
const existing = acc.find((i: any) => i.kind === kind);
const { fileName } = item.parameters;
if (!isDisabled(parameters.storyshots)) {
if (existing) {
existing.children.push({ ...item, render, fileName });
} else {
acc.push({
kind,
children: [{ ...item, render, fileName }],
});
// NOTE: as the store + preview's initialization process entirely uses
// `SychronousPromise`s in the v6 store case, the callback to the `then()` here
// will run *immediately* (in the same tick), and thus the `snapshotsTests`, and
// subsequent calls to `it()` etc will all happen within this tick, which is required
// by Jest (cannot add tests asynchronously)
globalWindow.__STORYBOOK_STORY_STORE__.initializationPromise.then(() => {
const data = storybook.raw().reduce(
(acc, item) => {
if (storyNameRegex && !item.name.match(storyNameRegex)) {
return acc;
}
}
return acc;
},
[] as {
kind: string;
children: any[];
}[]
);
if (data.length) {
callTestMethodGlobals(testMethod);
if (storyKindRegex && !item.kind.match(storyKindRegex)) {
return acc;
}
snapshotsTests({
data,
asyncJest,
suite,
framework,
testMethod,
testMethodParams,
snapshotSerializers,
});
const { kind, storyFn: render, parameters } = item;
const existing = acc.find((i: any) => i.kind === kind);
const { fileName } = item.parameters;
integrityTest(integrityOptions, stories2snapsConverter);
} else {
throw new Error('storyshots found 0 stories');
}
if (!isDisabled(parameters.storyshots)) {
if (existing) {
existing.children.push({ ...item, render, fileName });
} else {
acc.push({
kind,
children: [{ ...item, render, fileName }],
});
}
}
return acc;
},
[] as {
kind: string;
children: any[];
}[]
);
if (data.length) {
callTestMethodGlobals(testMethod);
snapshotsTests({
data,
asyncJest,
suite,
framework,
testMethod,
testMethodParams,
snapshotSerializers,
});
integrityTest(integrityOptions, stories2snapsConverter);
} else {
throw new Error('storyshots found 0 stories');
}
});
}
export default testStorySnapshots;

View File

@ -94,6 +94,12 @@ export class PreviewWeb<TFramework extends AnyFramework> {
);
}
// NOTE: the reason that the preview and store's initialization code is written in a promise
// style and not `async-await`, and the use of `SynchronousPromise`s is in order to allow
// storyshots to immediately call `raw()` on the store without waiting for a later tick.
// (Even simple things like `Promise.resolve()` and `await` involve the callback happening
// in the next promise "tick").
// See the comment in `storyshots-core/src/api/index.ts` for more detail.
initialize({
getStoryIndex,
importFn,

View File

@ -99,7 +99,7 @@ export class StoryStore<TFramework extends AnyFramework> {
this.prepareStoryWithCache = memoize(STORY_CACHE_SIZE)(prepareStory) as typeof prepareStory;
// We cannot call `loadStory()` until we've been initialized properly. But we can wait for it.
this.initializationPromise = new Promise((resolve) => {
this.initializationPromise = new SynchronousPromise((resolve) => {
this.resolveInitializationPromise = resolve;
});
}
@ -168,7 +168,7 @@ export class StoryStore<TFramework extends AnyFramework> {
}))
);
return Promise.all(csfFilePromiseList).then((list) =>
return SynchronousPromise.all(csfFilePromiseList).then((list) =>
list.reduce((acc, { importPath, csfFile }) => {
acc[importPath] = csfFile;
return acc;