From 1c5a96742d72979599ed40ebe9136831c9fc4b1e Mon Sep 17 00:00:00 2001 From: Josh Wooding <12938082+joshwooding@users.noreply.github.com> Date: Mon, 8 Jul 2024 10:18:13 +0100 Subject: [PATCH] Fix Figma source when project has multiple files (#623) --- .changeset/sixty-gifts-prove.md | 5 ++ .../source-figma/src/__tests__/index.test.ts | 84 ++++++++++++++++--- packages/source-figma/src/index.ts | 24 ++++-- 3 files changed, 93 insertions(+), 20 deletions(-) create mode 100644 .changeset/sixty-gifts-prove.md diff --git a/.changeset/sixty-gifts-prove.md b/.changeset/sixty-gifts-prove.md new file mode 100644 index 00000000..bae4c93c --- /dev/null +++ b/.changeset/sixty-gifts-prove.md @@ -0,0 +1,5 @@ +--- +'@jpmorganchase/mosaic-source-figma': patch +--- + +Fixed projects with multiple files not working. diff --git a/packages/source-figma/src/__tests__/index.test.ts b/packages/source-figma/src/__tests__/index.test.ts index afa019f6..5d6cdf6c 100644 --- a/packages/source-figma/src/__tests__/index.test.ts +++ b/packages/source-figma/src/__tests__/index.test.ts @@ -44,13 +44,11 @@ const options = { const getProjectById = (id: number) => options.projects.find(item => item.id === id) || { meta: { tags: [] } }; -const createProjectsResponse = (fileId: string) => ({ +const createProjectsResponse = (fileIds: string[]) => ({ name: 'Figma Test Patterns', - files: [ - { - key: fileId - } - ] + files: fileIds.map(fileId => ({ + key: fileId + })) }); const createProjectFilesResponse = (patternId: string, nodeId: string) => ({ @@ -93,7 +91,7 @@ const successHandlers = [ // Projects rest.get('https://myfigma.com/getproject/:project_id/*', (req, res, ctx) => { const { project_id } = req.params; - const fileId = project_id === '888' ? 'file888' : 'file999'; + const fileId = project_id === '888' ? ['file888'] : ['file999']; return res(ctx.status(200), ctx.json(createProjectsResponse(fileId))); }), // Files @@ -116,18 +114,47 @@ const successHandlers = [ ); }) ]; + +const multiHandlers = [ + // Projects + rest.get('https://myfigma.com/getproject/:project_id/*', (req, res, ctx) => { + const { project_id } = req.params; + const fileIds = project_id === '888' ? ['file111', 'file222'] : []; + return res(ctx.status(200), ctx.json(createProjectsResponse(fileIds))); + }), + // Files + rest.get('https://myfigma.com/getfile/:file_id', (req, res, ctx) => { + const { file_id } = req.params; + const title = file_id.toString().replace('file', ''); + const pattern = `jpmSaltPattern_${title}_pattern1`; + return res(ctx.status(200), ctx.json(createProjectFilesResponse(pattern, '2:0'))); + }), + // Thumbnails + rest.get('https://myfigma.com/generatethumb/:project_id', (req, res, ctx) => { + const { project_id } = req.params; + const url = new URL(req.url); + const nodeId = url.searchParams.get('ids') as string; + return res( + ctx.status(200), + ctx.json({ + images: { [nodeId]: `/thumbnail/${project_id}/${nodeId}` } + }) + ); + }) +]; + describe('GIVEN a Figma Source ', () => { describe('WHEN a fetch is successful', () => { const server = setupServer(); - beforeAll(() => { - server.use(...successHandlers); - server.listen({ onUnhandledRequest: 'warn' }); - }); + afterAll(() => { server.close(); }); it('should return the 2 patterns for the 2 subscribed projects', done => { + server.use(...successHandlers); + server.listen({ onUnhandledRequest: 'warn' }); + const source$: Observable = Source.create(options, { schedule }); source$.pipe(take(1)).subscribe({ next: result => { @@ -157,5 +184,40 @@ describe('GIVEN a Figma Source ', () => { complete: () => done() }); }); + + it('should support multiple files', done => { + server.use(...multiHandlers); + server.listen({ onUnhandledRequest: 'warn' }); + + const source$: Observable = Source.create(options, { schedule }); + source$.pipe(take(1)).subscribe({ + next: result => { + const meta0: Record = { + ...getProjectById(888).meta, + tags: ['some-tag1', 'some-tag2', ...getProjectById(888).meta.tags] + }; + meta0.data = { + ...meta0.data, + contentUrl: `/thumbnail/file111/2:0`, + fileId: 'file111', + projectId: '888' + }; + expect(result[0]).toEqual(createExpectedResult('jpmSaltPattern_111_pattern1', meta0)); + + const meta1: Record = { + ...getProjectById(888).meta, + tags: ['some-tag1', 'some-tag2', ...getProjectById(888).meta.tags] + }; + meta1.data = { + ...meta1.data, + fileId: 'file222', + contentUrl: `/thumbnail/file222/2:0`, + projectId: '888' + }; + expect(result[1]).toEqual(createExpectedResult('jpmSaltPattern_222_pattern1', meta1)); + }, + complete: () => done() + }); + }); }); }); diff --git a/packages/source-figma/src/index.ts b/packages/source-figma/src/index.ts index fae33a2c..30002e7c 100644 --- a/packages/source-figma/src/index.ts +++ b/packages/source-figma/src/index.ts @@ -72,13 +72,15 @@ const FigmaSource: Source = { requestHeaders: requestHeadersParam } = parsedOptions; - const projectEndpoints = projects.reduce>((result, project) => { + const projectEndpoints: Record = {}; + const projectById: Record = {}; + + projects.forEach(project => { const projectId = project.id.toString(); - return { - ...result, - [projectId]: endpoints.getProject.replace(':project_id', projectId) - }; - }, {}); + + projectEndpoints[projectId] = endpoints.getProject.replace(':project_id', projectId); + projectById[projectId] = project; + }); const projectsTransformer: HttpSourceResponseTransformerType< ProjectsResponse, @@ -109,6 +111,9 @@ const FigmaSource: Source = { }, []); }; + const getPatternPrefix = (metadata: Record) => + projectById[metadata?.data?.projectId].patternPrefix ?? null; + const projectFilesTransformer = ( response: ProjectFilesResponse, _prefixDir: string, @@ -118,7 +123,8 @@ const FigmaSource: Source = { const { document: { sharedPluginData } } = response; - const { patternPrefix } = projects[index]; + const sourceProvidedMetadata = transformerOptions[index].meta ?? {}; + const patternPrefix = getPatternPrefix(sourceProvidedMetadata); return Object.keys(sharedPluginData).reduce((figmaPagesResult, patternId) => { if (patternId.indexOf(patternPrefix) === 0) { /** Figma provided metadata */ @@ -131,7 +137,7 @@ const FigmaSource: Source = { ...patternData } }; - const sourceProvidedMetadata = transformerOptions[index].meta; + const figmaPageMeta = deepmerge>( figmaProvidedMetadata, sourceProvidedMetadata || {} @@ -216,7 +222,7 @@ const FigmaSource: Source = { ); const thumbnailRequestUrls = Object.keys(thumbnailNodes).map(fileId => { - let generateThumbnailUrl = endpoints.generateThumbnail.replace(':project_id', fileId); + const generateThumbnailUrl = endpoints.generateThumbnail.replace(':project_id', fileId); return generateThumbnailUrl.replace(':node_id', thumbnailNodes[fileId].join(',')); }); return createHttpSource({