Skip to content

Commit

Permalink
Merge pull request #16319 from storybookjs/15816-story-index-error-be…
Browse files Browse the repository at this point in the history
…haviour

Core: Add Story Index error handling
  • Loading branch information
shilman authored Oct 13, 2021
2 parents 4e7b64c + 6699ba7 commit 866ec9f
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 24 deletions.
4 changes: 3 additions & 1 deletion lib/api/src/lib/StoryIndexClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export class StoryIndexClient extends EventSource {

async fetch() {
const result = await fetch(PATH);
return result.json() as StoryIndex;
if (result.status === 200) return result.json() as StoryIndex;

throw new Error(await result.text());
}
}
21 changes: 14 additions & 7 deletions lib/api/src/modules/stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,15 +354,22 @@ export const init: ModuleFn = ({
});
},
fetchStoryList: async () => {
const storyIndex = await indexClient.fetch();
try {
const storyIndex = await indexClient.fetch();

// We can only do this if the stories.json is a proper storyIndex
if (storyIndex.v !== 3) {
logger.warn(`Skipping story index with version v${storyIndex.v}, awaiting SET_STORIES.`);
return;
}
// We can only do this if the stories.json is a proper storyIndex
if (storyIndex.v !== 3) {
logger.warn(`Skipping story index with version v${storyIndex.v}, awaiting SET_STORIES.`);
return;
}

await fullAPI.setStoryList(storyIndex);
await fullAPI.setStoryList(storyIndex);
} catch (err) {
store.setState({
storiesConfigured: true,
storiesFailed: err,
});
}
},
setStoryList: async (storyIndex: StoryIndex) => {
const hash = transformStoryIndexToStoriesHash(storyIndex, {
Expand Down
23 changes: 21 additions & 2 deletions lib/api/src/tests/stories.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const mockStories = jest.fn();
jest.mock('../lib/events');
jest.mock('global', () => ({
...jest.requireActual('global'),
fetch: jest.fn(() => ({ json: () => ({ v: 3, stories: mockStories() }) })),
fetch: jest.fn(),
}));

beforeEach(() => {
Expand Down Expand Up @@ -58,6 +58,9 @@ const provider = { getConfig: jest.fn() };
beforeEach(() => {
provider.getConfig.mockReturnValue({});
global.EventSource.reset();
global.fetch
.mockReset()
.mockReturnValue({ status: 200, json: () => ({ v: 3, stories: mockStories() }) });
});

describe('stories API', () => {
Expand Down Expand Up @@ -877,7 +880,23 @@ describe('stories API', () => {
});
});

describe('fetchStoryList', () => {
describe('fetchStoryIndex', () => {
it('deals with 500 errors', async () => {
const navigate = jest.fn();
const store = createMockStore();
const fullAPI = Object.assign(new EventEmitter(), {});

global.fetch.mockReturnValue({ status: 500, text: async () => new Error('sorting error') });
const { api, init } = initStories({ store, navigate, provider, fullAPI });
Object.assign(fullAPI, api);

await init();

const { storiesConfigured, storiesFailed } = store.getState();
expect(storiesConfigured).toBe(true);
expect(storiesFailed.message).toMatch(/sorting error/);
});

it('sets the initial set of stories in the stories hash', async () => {
const navigate = jest.fn();
const store = createMockStore();
Expand Down
2 changes: 1 addition & 1 deletion lib/preview-web/src/PreviewWeb.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jest.mock('global', () => ({
FEATURES: {
storyStoreV7: true,
},
fetch: async () => ({ json: async () => mockStoryIndex }),
fetch: async () => ({ status: 200, json: async () => mockStoryIndex }),
}));

beforeEach(() => {
Expand Down
19 changes: 15 additions & 4 deletions lib/preview-web/src/PreviewWeb.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const { history, document } = global;

const mockStoryIndex = jest.fn(() => storyIndex);

let mockFetchResult;
jest.mock('global', () => ({
...(jest.requireActual('global') as any),
history: { replaceState: jest.fn() },
Expand All @@ -39,7 +40,7 @@ jest.mock('global', () => ({
breakingChangesV7: true,
// xxx
},
fetch: async () => ({ json: mockStoryIndex }),
fetch: async () => mockFetchResult,
}));

jest.mock('@storybook/client-logger');
Expand Down Expand Up @@ -70,10 +71,11 @@ beforeEach(() => {
mockStoryIndex.mockReset().mockReturnValue(storyIndex);

addons.setChannel(mockChannel as any);
mockFetchResult = { status: 200, json: mockStoryIndex, text: () => 'error text' };
});

describe('PreviewWeb', () => {
describe('constructor', () => {
describe('initialize', () => {
it('shows an error if getProjectAnnotations throws', async () => {
const err = new Error('meta error');
const preview = new PreviewWeb();
Expand All @@ -87,9 +89,18 @@ describe('PreviewWeb', () => {
expect(preview.view.showErrorDisplay).toHaveBeenCalled();
expect(mockChannel.emit).toHaveBeenCalledWith(Events.CONFIG_ERROR, err);
});
});

describe('initialize', () => {
it('shows an error if the stories.json endpoint 500s', async () => {
const err = new Error('sort error');
mockFetchResult = { status: 500, text: async () => err.toString() };

const preview = new PreviewWeb();
await preview.initialize({ importFn, getProjectAnnotations });

expect(preview.view.showErrorDisplay).toHaveBeenCalled();
expect(mockChannel.emit).toHaveBeenCalledWith(Events.CONFIG_ERROR, expect.any(Error));
});

it('sets globals from the URL', async () => {
document.location.search = '?id=*&globals=a:c';

Expand Down
22 changes: 14 additions & 8 deletions lib/preview-web/src/PreviewWeb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,21 @@ export class PreviewWeb<TFramework extends AnyFramework> {

if (FEATURES?.storyStoreV7) {
this.indexClient = new StoryIndexClient();
return this.indexClient.fetch().then((fetchedStoryIndex: StoryIndex) => {
this.storyStore.initialize({
getStoryIndex: () => fetchedStoryIndex,
importFn,
projectAnnotations,
cache: false,
return this.indexClient
.fetch()
.then((fetchedStoryIndex: StoryIndex) => {
this.storyStore.initialize({
getStoryIndex: () => fetchedStoryIndex,
importFn,
projectAnnotations,
cache: false,
});
return this.setupListenersAndRenderSelection();
})
.catch((err) => {
logger.warn(err);
this.renderPreviewEntryError(err);
});
return this.setupListenersAndRenderSelection();
});
}

if (!getStoryIndex) {
Expand Down
5 changes: 4 additions & 1 deletion lib/preview-web/src/StoryIndexClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export class StoryIndexClient extends EventSource {

async fetch() {
const result = await fetch(PATH);
return result.json() as StoryIndex;

if (result.status === 200) return result.json() as StoryIndex;

throw new Error(await result.text());
}
}

0 comments on commit 866ec9f

Please sign in to comment.