diff --git a/designer/server/src/routes/admin/index.js b/designer/server/src/routes/admin/index.js index 8c212adeb..ba38ee20a 100644 --- a/designer/server/src/routes/admin/index.js +++ b/designer/server/src/routes/admin/index.js @@ -150,11 +150,7 @@ async function processForm(metadata, token, archive) { archive.append(metadataJson, { name: metadataName }) // Then append definitions under {id}/definition_*.json - const definition = await getFormDefinitions( - metadata.id, - !!metadata.draft, - token - ) + const definition = await getFormDefinitions(metadata.id, token) appendFormDefinitionsToArchive(metadata.id, archive, definition) } @@ -322,21 +318,30 @@ function appendManifestToArchive(archive, totalForms, manifestEntities) { /** * Retrieve both live and draft form definitions * @param {string} id - The form metadata ID - * @param { boolean } includeDraft - Whether to include draft definition * @param {string} token - Auth token - * @returns {Promise<{ liveDefinition: FormDefinition | null, draftDefinition: FormDefinition | null }>} + * @returns {Promise<{ liveDefinition?: FormDefinition , draftDefinition?: FormDefinition }>} */ -async function getFormDefinitions(id, includeDraft, token) { +async function getFormDefinitions(id, token) { const [liveDefinition, draftDefinition] = await Promise.all([ - forms.getLiveFormDefinition(id, token), - includeDraft - ? forms.getDraftFormDefinition(id, token) - : Promise.resolve(null) + forms.getLiveFormDefinition(id, token).catch(ignore404Error), + forms.getDraftFormDefinition(id, token).catch(ignore404Error) ]) return { liveDefinition, draftDefinition } } +/** + * + * @param {Error & {data?:{statusCode: StatusCodes}}} err + * @returns {undefined | never} + */ +function ignore404Error(err) { + if (err.data?.statusCode === StatusCodes.NOT_FOUND) { + return undefined + } + throw err +} + /** * Append form definitions using id-based folder paths * @param {string} id form ID @@ -358,5 +363,5 @@ function appendFormDefinitionsToArchive(id, archive, definition) { /** * @import { ServerRoute , Request, ResponseToolkit, ResponseObject} from '@hapi/hapi' - * @import { FormMetadata, FormDefinition ,FormMetadataState} from '@defra/forms-model' + * @import { FormMetadata, FormDefinition } from '@defra/forms-model' */ diff --git a/designer/server/src/routes/admin/index.test.js b/designer/server/src/routes/admin/index.test.js index 874c78da0..6cd143beb 100644 --- a/designer/server/src/routes/admin/index.test.js +++ b/designer/server/src/routes/admin/index.test.js @@ -368,10 +368,18 @@ describe('System admin routes', () => { yield formWithoutDraft }) + const notFoundError = Object.assign(new Error('Not found'), { + data: { statusCode: StatusCodes.NOT_FOUND } + }) + jest .mocked(forms.getLiveFormDefinition) .mockResolvedValue(testFormDefinitionWithSinglePage) + jest + .mocked(forms.getDraftFormDefinition) + .mockRejectedValueOnce(notFoundError) + const options = { method: 'post', url: '/admin/index', @@ -383,10 +391,10 @@ describe('System admin routes', () => { expect(response.statusCode).toBe(StatusCodes.OK) - // Verify only live definition was requested (draft wasn't fetched because metadata.draft is undefined) + // Verify live definition was requested expect(forms.getLiveFormDefinition).toHaveBeenCalledTimes(1) - // Draft definition should not be called when form.draft is undefined - expect(forms.getDraftFormDefinition).not.toHaveBeenCalled() + // Draft definition is always requested and 404 is ignored + expect(forms.getDraftFormDefinition).toHaveBeenCalledTimes(1) // Verify audit event published expect(publishFormsBackupRequestedEvent).toHaveBeenCalledWith( @@ -396,7 +404,7 @@ describe('System admin routes', () => { ) }) - test('should throw error if one of the api calls fails', async () => { + test('should throw error if one of the api calls fails (non 404 error)', async () => { const form1 = Promise.resolve(testFormMetadata) const form2 = Promise.resolve({ ...testFormMetadata, @@ -437,6 +445,82 @@ describe('System admin routes', () => { // Verify definitions were requested expect(publishFormsBackupRequestedEvent).not.toHaveBeenCalled() expect(forms.getLiveFormDefinition).toHaveBeenCalledTimes(2) + expect(forms.getDraftFormDefinition).toHaveBeenCalledTimes(2) + }) + + test('should ignore 404 when fetching live definition', async () => { + const form1 = Promise.resolve(testFormMetadata) + + jest.mocked(forms.listAll).mockImplementationOnce(async function* () { + yield await form1 + }) + + const notFoundError = Object.assign(new Error('Not found'), { + data: { statusCode: StatusCodes.NOT_FOUND } + }) + + jest + .mocked(forms.getLiveFormDefinition) + .mockRejectedValueOnce(notFoundError) + + jest + .mocked(forms.getDraftFormDefinition) + .mockResolvedValueOnce(testFormDefinitionWithSinglePage) + + const options = { + method: 'post', + url: '/admin/index', + auth, + payload: { action: 'download' } + } + + const response = await server.inject(options) + + expect(response.statusCode).toBe(StatusCodes.OK) + expect(publishFormsBackupRequestedEvent).toHaveBeenCalledWith( + expect.any(Object), + 1, + expect.any(Number) + ) + expect(forms.getLiveFormDefinition).toHaveBeenCalledTimes(1) + expect(forms.getDraftFormDefinition).toHaveBeenCalledTimes(1) + }) + + test('should ignore 404 when fetching draft definition', async () => { + const form1 = Promise.resolve(testFormMetadata) + + jest.mocked(forms.listAll).mockImplementationOnce(async function* () { + yield await form1 + }) + + const notFoundError = Object.assign(new Error('Not found'), { + data: { statusCode: StatusCodes.NOT_FOUND } + }) + + jest + .mocked(forms.getLiveFormDefinition) + .mockResolvedValueOnce(testFormDefinitionWithSinglePage) + + jest + .mocked(forms.getDraftFormDefinition) + .mockRejectedValueOnce(notFoundError) + + const options = { + method: 'post', + url: '/admin/index', + auth, + payload: { action: 'download' } + } + + const response = await server.inject(options) + + expect(response.statusCode).toBe(StatusCodes.OK) + expect(publishFormsBackupRequestedEvent).toHaveBeenCalledWith( + expect.any(Object), + 1, + expect.any(Number) + ) + expect(forms.getLiveFormDefinition).toHaveBeenCalledTimes(1) expect(forms.getDraftFormDefinition).toHaveBeenCalledTimes(1) })