Skip to content

Commit 6e93dae

Browse files
committed
update tests
1 parent a857398 commit 6e93dae

3 files changed

Lines changed: 305 additions & 65 deletions

File tree

src/usecases/handle-figma-file-update-event-use-case.test.ts

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { v4 as uuidv4 } from 'uuid';
22

33
import { handleFigmaFileUpdateEventUseCase } from './handle-figma-file-update-event-use-case';
44

5+
import * as launchDarkly from '../config/launch_darkly';
56
import { FigmaTeamAuthStatus } from '../domain/entities';
67
import {
78
generateAssociatedFigmaDesign,
89
generateAtlassianDesign,
910
generateConnectInstallation,
1011
generateFigmaDesignIdentifier,
12+
generateFigmaFileWebhook,
1113
generateFigmaTeam,
1214
} from '../domain/entities/testing';
1315
import {
@@ -20,8 +22,62 @@ import {
2022
connectInstallationRepository,
2123
figmaTeamRepository,
2224
} from '../infrastructure/repositories';
25+
import type { FigmaWebhookInfo } from '../web/routes/figma';
2326

2427
describe('handleFigmaFileUpdateEventUseCase', () => {
28+
describe('file webhook', () => {
29+
beforeEach(() => {
30+
jest.spyOn(launchDarkly, 'getLDClient').mockResolvedValue(null);
31+
jest.spyOn(launchDarkly, 'getFeatureFlag').mockResolvedValue(true);
32+
});
33+
it('should handle file webhook events', async () => {
34+
const connectInstallation = generateConnectInstallation();
35+
jest
36+
.spyOn(connectInstallationRepository, 'get')
37+
.mockResolvedValue(connectInstallation);
38+
39+
const figmaFileWebhook = generateFigmaFileWebhook({
40+
connectInstallationId: connectInstallation.id,
41+
});
42+
const fileKey = uuidv4();
43+
const associatedFigmaDesigns = [1, 2, 3].map((i) =>
44+
generateAssociatedFigmaDesign({
45+
designId: generateFigmaDesignIdentifier({
46+
fileKey,
47+
nodeId: `${i}:${i}`,
48+
}),
49+
connectInstallationId: connectInstallation.id,
50+
}),
51+
);
52+
jest
53+
.spyOn(
54+
associatedFigmaDesignRepository,
55+
'findManyByFileKeyAndConnectInstallationId',
56+
)
57+
.mockResolvedValue(associatedFigmaDesigns);
58+
const associatedAtlassianDesigns = associatedFigmaDesigns.map(
59+
(figmaDesign) =>
60+
generateAtlassianDesign({
61+
id: figmaDesign.designId.toAtlassianDesignId(),
62+
}),
63+
);
64+
jest
65+
.spyOn(figmaService, 'getAvailableDesignsFromSameFile')
66+
.mockResolvedValue(associatedAtlassianDesigns);
67+
68+
jest.spyOn(jiraService, 'submitDesigns').mockResolvedValue();
69+
70+
const webhookInfo: FigmaWebhookInfo = {
71+
figmaFileWebhook,
72+
webhookType: 'file',
73+
};
74+
await handleFigmaFileUpdateEventUseCase.execute(webhookInfo, fileKey);
75+
expect(jiraService.submitDesigns).toHaveBeenCalledWith(
76+
associatedAtlassianDesigns,
77+
connectInstallation,
78+
);
79+
});
80+
});
2581
describe('error handling', () => {
2682
const connectInstallation = generateConnectInstallation();
2783
const figmaTeam = generateFigmaTeam({
@@ -44,7 +100,11 @@ describe('handleFigmaFileUpdateEventUseCase', () => {
44100
.mockRejectedValue(new UnauthorizedFigmaServiceError());
45101
jest.spyOn(figmaTeamRepository, 'updateAuthStatus').mockResolvedValue();
46102

47-
await handleFigmaFileUpdateEventUseCase.execute(figmaTeam, fileKey);
103+
const webhookInfo: FigmaWebhookInfo = {
104+
figmaTeam,
105+
webhookType: 'team',
106+
};
107+
await handleFigmaFileUpdateEventUseCase.execute(webhookInfo, fileKey);
48108

49109
expect(figmaTeamRepository.updateAuthStatus).toHaveBeenCalledWith(
50110
figmaTeam.id,
@@ -75,7 +135,11 @@ describe('handleFigmaFileUpdateEventUseCase', () => {
75135
.mockResolvedValue(associatedAtlassianDesigns);
76136
jest.spyOn(jiraService, 'submitDesigns').mockResolvedValue();
77137

78-
await handleFigmaFileUpdateEventUseCase.execute(figmaTeam, fileKey);
138+
const webhookInfo: FigmaWebhookInfo = {
139+
figmaTeam,
140+
webhookType: 'team',
141+
};
142+
await handleFigmaFileUpdateEventUseCase.execute(webhookInfo, fileKey);
79143

80144
expect(figmaTeamRepository.updateAuthStatus).not.toHaveBeenCalled();
81145
expect(jiraService.submitDesigns).toHaveBeenCalledWith(
@@ -111,7 +175,11 @@ describe('handleFigmaFileUpdateEventUseCase', () => {
111175
.mockResolvedValue(associatedAtlassianDesigns);
112176
jest.spyOn(jiraService, 'submitDesigns').mockResolvedValue();
113177

114-
await handleFigmaFileUpdateEventUseCase.execute(figmaTeam, fileKey);
178+
const webhookInfo: FigmaWebhookInfo = {
179+
figmaTeam,
180+
webhookType: 'team',
181+
};
182+
await handleFigmaFileUpdateEventUseCase.execute(webhookInfo, fileKey);
115183

116184
expect(jiraService.submitDesigns).toHaveBeenCalledWith(
117185
associatedAtlassianDesigns,
@@ -138,7 +206,11 @@ describe('handleFigmaFileUpdateEventUseCase', () => {
138206
.mockRejectedValue(new UnauthorizedFigmaServiceError());
139207
jest.spyOn(figmaTeamRepository, 'updateAuthStatus').mockResolvedValue();
140208

141-
await handleFigmaFileUpdateEventUseCase.execute(figmaTeam, fileKey);
209+
const webhookInfo: FigmaWebhookInfo = {
210+
figmaTeam,
211+
webhookType: 'team',
212+
};
213+
await handleFigmaFileUpdateEventUseCase.execute(webhookInfo, fileKey);
142214

143215
expect(figmaTeamRepository.updateAuthStatus).toHaveBeenCalledWith(
144216
figmaTeam.id,
@@ -166,8 +238,12 @@ describe('handleFigmaFileUpdateEventUseCase', () => {
166238
.mockRejectedValue(error);
167239
jest.spyOn(jiraService, 'submitDesigns');
168240

241+
const webhookInfo: FigmaWebhookInfo = {
242+
figmaTeam,
243+
webhookType: 'team',
244+
};
169245
await expect(
170-
handleFigmaFileUpdateEventUseCase.execute(figmaTeam, fileKey),
246+
handleFigmaFileUpdateEventUseCase.execute(webhookInfo, fileKey),
171247
).rejects.toStrictEqual(error);
172248
expect(jiraService.submitDesigns).not.toHaveBeenCalled();
173249
});

src/web/middleware/figma/figma-webhook-auth-middleware.test.ts

Lines changed: 179 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,53 +4,192 @@ import { v4 as uuidv4 } from 'uuid';
44
import { figmaWebhookAuthMiddleware } from './figma-webhook-auth-middleware';
55

66
import { flushMacrotaskQueue } from '../../../common/testing/utils';
7-
import { generateFigmaTeam } from '../../../domain/entities/testing';
8-
import { figmaTeamRepository } from '../../../infrastructure/repositories';
7+
import {
8+
generateFigmaFileWebhook,
9+
generateFigmaTeam,
10+
} from '../../../domain/entities/testing';
11+
import {
12+
figmaFileWebhookRepository,
13+
figmaTeamRepository,
14+
} from '../../../infrastructure/repositories';
915
import { BadRequestResponseStatusError } from '../../errors';
10-
import { generatePingWebhookEventRequestBody } from '../../routes/figma/testing';
16+
import {
17+
generateDevModeStatusUpdateWebhookEventRequestBody,
18+
generateFileUpdateWebhookEventRequestBody,
19+
generatePingWebhookEventRequestBody,
20+
} from '../../routes/figma/testing';
1121

1222
describe('figmaWebhookAuthMiddleware', () => {
13-
it('should authenticate request and set figmaTeam in locals if request is authentic', async () => {
14-
const webhookId = uuidv4();
15-
const webhookPasscode = uuidv4();
16-
const figmaTeam = generateFigmaTeam({ webhookId, webhookPasscode });
17-
jest
18-
.spyOn(figmaTeamRepository, 'findByWebhookId')
19-
.mockResolvedValue(figmaTeam);
20-
21-
const request = {
22-
body: generatePingWebhookEventRequestBody({
23-
webhook_id: webhookId,
24-
passcode: webhookPasscode,
25-
}),
26-
} as Request;
27-
const response = {
28-
locals: {},
29-
} as Response;
30-
const next = jest.fn();
31-
32-
figmaWebhookAuthMiddleware(request, response, next);
33-
await flushMacrotaskQueue();
34-
35-
expect(next).toHaveBeenCalledWith();
36-
expect(response.locals.figmaTeam).toBe(figmaTeam);
37-
expect(figmaTeamRepository.findByWebhookId).toHaveBeenCalledWith(webhookId);
23+
describe('file webhook', () => {
24+
beforeEach(() => {
25+
jest
26+
.spyOn(figmaTeamRepository, 'findByWebhookId')
27+
.mockResolvedValue(null);
28+
});
29+
30+
it('should authenticate request and set figmaFileWebhook in locals if request is authentic', async () => {
31+
const webhookId = uuidv4();
32+
const webhookPasscode = uuidv4();
33+
const figmaFileWebhook = generateFigmaFileWebhook({
34+
webhookId,
35+
webhookPasscode,
36+
});
37+
jest
38+
.spyOn(figmaFileWebhookRepository, 'findByWebhookId')
39+
.mockResolvedValue(figmaFileWebhook);
40+
41+
const request = {
42+
body: generateFileUpdateWebhookEventRequestBody({
43+
webhook_id: webhookId,
44+
passcode: webhookPasscode,
45+
}),
46+
} as Request;
47+
const response = {
48+
locals: {},
49+
} as Response;
50+
const next = jest.fn();
51+
52+
figmaWebhookAuthMiddleware(request, response, next);
53+
await flushMacrotaskQueue();
54+
55+
expect(next).toHaveBeenCalledWith();
56+
expect(response.locals.webhookInfo).toEqual({
57+
figmaFileWebhook,
58+
webhookType: 'file',
59+
});
60+
expect(figmaTeamRepository.findByWebhookId).toHaveBeenCalledWith(
61+
webhookId,
62+
);
63+
});
64+
65+
it('can handle dev mode status update webhook events', async () => {
66+
const webhookId = uuidv4();
67+
const webhookPasscode = uuidv4();
68+
const figmaFileWebhook = generateFigmaFileWebhook({
69+
webhookId,
70+
webhookPasscode,
71+
});
72+
jest
73+
.spyOn(figmaFileWebhookRepository, 'findByWebhookId')
74+
.mockResolvedValue(figmaFileWebhook);
75+
76+
const request = {
77+
body: generateDevModeStatusUpdateWebhookEventRequestBody({
78+
webhook_id: webhookId,
79+
passcode: webhookPasscode,
80+
}),
81+
} as Request;
82+
83+
const response = {
84+
locals: {},
85+
} as Response;
86+
const next = jest.fn();
87+
88+
figmaWebhookAuthMiddleware(request, response, next);
89+
await flushMacrotaskQueue();
90+
91+
expect(next).toHaveBeenCalledWith();
92+
expect(response.locals.webhookInfo).toEqual({
93+
figmaFileWebhook,
94+
webhookType: 'file',
95+
});
96+
expect(figmaFileWebhookRepository.findByWebhookId).toHaveBeenCalledWith(
97+
webhookId,
98+
);
99+
});
100+
101+
it('should not authenticate request if request contains invalid passcode', async () => {
102+
const webhookId = uuidv4();
103+
const figmaFileWebhook = generateFigmaFileWebhook({ webhookId });
104+
jest
105+
.spyOn(figmaFileWebhookRepository, 'findByWebhookId')
106+
.mockResolvedValue(figmaFileWebhook);
107+
108+
const request = {
109+
body: generatePingWebhookEventRequestBody({
110+
webhook_id: webhookId,
111+
passcode: 'invalid',
112+
}),
113+
} as Request;
114+
const next = jest.fn();
115+
116+
figmaWebhookAuthMiddleware(request, {} as Response, next);
117+
await flushMacrotaskQueue();
118+
119+
expect(next).toHaveBeenCalledWith(
120+
expect.any(BadRequestResponseStatusError),
121+
);
122+
});
38123
});
39124

40-
it('should not authenticate request if request does not contain webhook credentials', async () => {
41-
const request = {} as Request;
42-
const next = jest.fn();
43-
44-
figmaWebhookAuthMiddleware(request, {} as Response, next);
45-
await flushMacrotaskQueue();
46-
47-
expect(next).toHaveBeenCalledWith(
48-
expect.any(BadRequestResponseStatusError),
49-
);
125+
describe('team webhook', () => {
126+
beforeEach(() => {
127+
jest
128+
.spyOn(figmaFileWebhookRepository, 'findByWebhookId')
129+
.mockResolvedValue(null);
130+
});
131+
132+
it('should authenticate request and set figmaTeam in locals if request is authentic', async () => {
133+
const webhookId = uuidv4();
134+
const webhookPasscode = uuidv4();
135+
const figmaTeam = generateFigmaTeam({ webhookId, webhookPasscode });
136+
jest
137+
.spyOn(figmaTeamRepository, 'findByWebhookId')
138+
.mockResolvedValue(figmaTeam);
139+
140+
const request = {
141+
body: generatePingWebhookEventRequestBody({
142+
webhook_id: webhookId,
143+
passcode: webhookPasscode,
144+
}),
145+
} as Request;
146+
const response = {
147+
locals: {},
148+
} as Response;
149+
const next = jest.fn();
150+
151+
figmaWebhookAuthMiddleware(request, response, next);
152+
await flushMacrotaskQueue();
153+
154+
expect(next).toHaveBeenCalledWith();
155+
expect(response.locals.webhookInfo).toEqual({
156+
figmaTeam,
157+
webhookType: 'team',
158+
});
159+
expect(figmaTeamRepository.findByWebhookId).toHaveBeenCalledWith(
160+
webhookId,
161+
);
162+
});
163+
164+
it('should not authenticate request if request contains invalid passcode', async () => {
165+
const webhookId = uuidv4();
166+
const figmaTeam = generateFigmaTeam({ webhookId });
167+
jest
168+
.spyOn(figmaTeamRepository, 'findByWebhookId')
169+
.mockResolvedValue(figmaTeam);
170+
171+
const request = {
172+
body: generatePingWebhookEventRequestBody({
173+
webhook_id: figmaTeam.webhookId,
174+
passcode: 'invalid',
175+
}),
176+
} as Request;
177+
const next = jest.fn();
178+
179+
figmaWebhookAuthMiddleware(request, {} as Response, next);
180+
await flushMacrotaskQueue();
181+
182+
expect(next).toHaveBeenCalledWith(
183+
expect.any(BadRequestResponseStatusError),
184+
);
185+
});
50186
});
51187

52188
it('should not authenticate request if webhook is unknown', async () => {
53189
jest.spyOn(figmaTeamRepository, 'findByWebhookId').mockResolvedValue(null);
190+
jest
191+
.spyOn(figmaFileWebhookRepository, 'findByWebhookId')
192+
.mockResolvedValue(null);
54193

55194
const request = {
56195
body: generatePingWebhookEventRequestBody({
@@ -68,19 +207,8 @@ describe('figmaWebhookAuthMiddleware', () => {
68207
);
69208
});
70209

71-
it('should not authenticate request if request contains invalid passcode', async () => {
72-
const webhookId = uuidv4();
73-
const figmaTeam = generateFigmaTeam({ webhookId });
74-
jest
75-
.spyOn(figmaTeamRepository, 'findByWebhookId')
76-
.mockResolvedValue(figmaTeam);
77-
78-
const request = {
79-
body: generatePingWebhookEventRequestBody({
80-
webhook_id: figmaTeam.webhookId,
81-
passcode: 'invalid',
82-
}),
83-
} as Request;
210+
it('should not authenticate request if request does not contain webhook credentials', async () => {
211+
const request = {} as Request;
84212
const next = jest.fn();
85213

86214
figmaWebhookAuthMiddleware(request, {} as Response, next);

0 commit comments

Comments
 (0)