diff --git a/lib/api/src/modules/refs.ts b/lib/api/src/modules/refs.ts index b4088eae33a..00595d930ed 100644 --- a/lib/api/src/modules/refs.ts +++ b/lib/api/src/modules/refs.ts @@ -100,7 +100,7 @@ const map = ( return input; }; -export const init: ModuleFn = ({ store, provider, fullAPI }) => { +export const init: ModuleFn = ({ store, provider, fullAPI }, { runCheck = true } = {}) => { const api: SubAPI = { findRef: (source) => { const refs = api.getRefs(); @@ -232,9 +232,11 @@ export const init: ModuleFn = ({ store, provider, fullAPI }) => { r.type = 'unknown'; }); - Object.entries(refs).forEach(([k, v]) => { - api.checkRef(v as SetRefData); - }); + if (runCheck) { + Object.entries(refs).forEach(([k, v]) => { + api.checkRef(v as SetRefData); + }); + } return { api, diff --git a/lib/api/src/tests/refs.test.js b/lib/api/src/tests/refs.test.js index 97786ec15eb..1c54af75597 100644 --- a/lib/api/src/tests/refs.test.js +++ b/lib/api/src/tests/refs.test.js @@ -45,9 +45,55 @@ const store = { }, }, }), - setState: jest.fn(() => { - // console.log('setState!'); - }), + setState: jest.fn(() => {}), +}; + +const emptyResponse = Promise.resolve({ + ok: true, + json: async () => ({}), +}); + +const setupResponses = ( + a = emptyResponse, + b = emptyResponse, + c = emptyResponse, + d = emptyResponse +) => { + fetch.mockClear(); + store.setState.mockClear(); + + fetch.mockImplementation((l, o) => { + if (l.includes('stories') && o.credentials === 'omit') { + return Promise.resolve({ + ok: a.ok, + json: a.response, + }); + } + if (l.includes('stories') && o.credentials === 'include') { + return Promise.resolve({ + ok: b.ok, + json: b.response, + }); + } + if (l.includes('iframe')) { + return Promise.resolve({ + ok: c.ok, + json: c.response, + }); + } + if (l.includes('metadata')) { + return Promise.resolve({ + ok: d.ok, + json: d.response, + }); + } + return Promise.resolve({ + ok: false, + json: () => { + throw new Error('not ok'); + }, + }); + }); }; describe('Refs API', () => { @@ -122,12 +168,30 @@ describe('Refs API', () => { it('checks refs (all fail)', async () => { // given - const { api } = initRefs({ provider, store }); + const { api } = initRefs({ provider, store }, { runCheck: false }); - fetch.mockClear(); - store.setState.mockClear(); + setupResponses( + { + ok: false, + response: async () => { + throw new Error('Failed to fetch'); + }, + }, + { + ok: false, + response: async () => { + throw new Error('Failed to fetch'); + }, + }, + { + ok: false, + response: async () => { + throw new Error('not ok'); + }, + } + ); - const result = await api.checkRef({ + await api.checkRef({ id: 'fake', url: 'https://example.com', title: 'Fake', @@ -192,19 +256,29 @@ describe('Refs API', () => { it('checks refs (success)', async () => { // given - const { api } = initRefs({ provider, store }); + const { api } = initRefs({ provider, store }, { runCheck: false }); - fetch.mockClear(); - store.setState.mockClear(); - - fetch.mockImplementation(() => - Promise.resolve({ + setupResponses( + { ok: true, - json: () => - Promise.resolve({ - stories: {}, - }), - }) + response: async () => ({ stories: {} }), + }, + { + ok: true, + response: async () => ({ stories: {} }), + }, + { + ok: true, + response: async () => { + throw new Error('not ok'); + }, + }, + { + ok: true, + response: async () => ({ + versions: {}, + }), + } ); await api.checkRef({ @@ -253,7 +327,7 @@ describe('Refs API', () => { ] `); - expect(store.setState.mock.calls[1][0]).toMatchInlineSnapshot(` + expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "refs": Object { "fake": Object { @@ -263,6 +337,7 @@ describe('Refs API', () => { "title": "Fake", "type": "lazy", "url": "https://example.com", + "versions": Object {}, }, }, } @@ -271,19 +346,31 @@ describe('Refs API', () => { it('checks refs (auth)', async () => { // given - const { api } = initRefs({ provider, store }); + const { api } = initRefs({ provider, store }, { runCheck: false }); - fetch.mockClear(); - store.setState.mockClear(); - - fetch.mockImplementation(() => - Promise.resolve({ + setupResponses( + { ok: true, - json: () => - Promise.resolve({ - loginUrl: 'https://example.com/login', - }), - }) + response: async () => ({ loginUrl: 'https://example.com/login' }), + }, + { + ok: false, + response: async () => { + throw new Error('not ok'); + }, + }, + { + ok: true, + response: async () => { + throw new Error('not ok'); + }, + }, + { + ok: false, + response: async () => { + throw new Error('not ok'); + }, + } ); await api.checkRef({ @@ -323,17 +410,7 @@ describe('Refs API', () => { "https://example.com/metadata.json", Object { "cache": "no-cache", - "credentials": "include", - "headers": Object { - "Accept": "application/json", - }, - }, - ], - Array [ - "https://example.com/metadata.json", - Object { - "cache": "no-cache", - "credentials": "include", + "credentials": "omit", "headers": Object { "Accept": "application/json", }, @@ -342,7 +419,7 @@ describe('Refs API', () => { ] `); - expect(store.setState.mock.calls[1][0]).toMatchInlineSnapshot(` + expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "refs": Object { "fake": Object { @@ -361,38 +438,33 @@ describe('Refs API', () => { it('checks refs (mixed)', async () => { // given - const { api } = initRefs({ provider, store }); + const { api } = initRefs({ provider, store }, { runCheck: false }); fetch.mockClear(); store.setState.mockClear(); - fetch.mockImplementation((l, o) => { - if (l.includes('stories') && o.credentials === 'omit') { - return Promise.resolve({ - ok: true, - json: () => - Promise.resolve({ - loginUrl: 'https://example.com/login', - }), - }); - } - if (l.includes('stories') && o.credentials === 'include') { - return Promise.resolve({ - ok: true, - json: () => - Promise.resolve({ - stories: {}, - }), - }); - } - return Promise.resolve({ + setupResponses( + { ok: true, - json: () => - Promise.resolve({ - versions: { '1.0.0': 'https://example.com/v1', '2.0.0': 'https://example.com' }, - }), - }); - }); + response: async () => ({ loginUrl: 'https://example.com/login' }), + }, + { + ok: true, + response: async () => ({ stories: {} }), + }, + { + ok: true, + response: async () => { + throw new Error('not ok'); + }, + }, + { + ok: true, + response: async () => ({ + versions: { '1.0.0': 'https://example.com/v1', '2.0.0': 'https://example.com' }, + }), + } + ); await api.checkRef({ id: 'fake', @@ -437,20 +509,10 @@ describe('Refs API', () => { }, }, ], - Array [ - "https://example.com/metadata.json", - Object { - "cache": "no-cache", - "credentials": "include", - "headers": Object { - "Accept": "application/json", - }, - }, - ], ] `); - expect(store.setState.mock.calls[1][0]).toMatchInlineSnapshot(` + expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "refs": Object { "fake": Object { @@ -469,5 +531,88 @@ describe('Refs API', () => { } `); }); + + it('checks refs (cors)', async () => { + // given + const { api } = initRefs({ provider, store }, { runCheck: false }); + + setupResponses( + { + ok: false, + response: async () => { + throw new Error('Failed to fetch'); + }, + }, + { + ok: false, + response: async () => { + throw new Error('Failed to fetch'); + }, + }, + { + ok: true, + response: async () => { + throw new Error('not ok'); + }, + }, + { + ok: false, + response: async () => { + throw new Error('Failed to fetch'); + }, + } + ); + + await api.checkRef({ + id: 'fake', + url: 'https://example.com', + title: 'Fake', + }); + + expect(fetch.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "https://example.com/stories.json", + Object { + "credentials": "include", + "headers": Object { + "Accept": "application/json", + }, + }, + ], + Array [ + "https://example.com/stories.json", + Object { + "credentials": "omit", + "headers": Object { + "Accept": "application/json", + }, + }, + ], + Array [ + "https://example.com/iframe.html", + Object { + "cors": "no-cors", + "credentials": "omit", + }, + ], + ] + `); + + expect(store.setState.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "refs": Object { + "fake": Object { + "id": "fake", + "ready": false, + "stories": undefined, + "title": "Fake", + "type": "auto-inject", + "url": "https://example.com", + }, + }, + } + `); + }); }); });