Skip to content

Commit 98a79a2

Browse files
authored
feat: retry added by default (#198)
* feat: retry added by default
1 parent f69254b commit 98a79a2

7 files changed

+804
-572
lines changed

lib/__data__/index.ts

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { TestStatus, TestRunResponse } from "../types";
2+
3+
export const testRunUnresolvedResponse: TestRunResponse = {
4+
url: "url",
5+
status: TestStatus.unresolved,
6+
pixelMisMatchCount: 12,
7+
diffPercent: 0.12,
8+
diffTollerancePercent: 0,
9+
id: "some id",
10+
imageName: "imageName",
11+
merge: false,
12+
};
13+
14+
export const testRunOkResponse: TestRunResponse = {
15+
url: "url",
16+
status: TestStatus.ok,
17+
diffPercent: 0,
18+
diffTollerancePercent: 0,
19+
id: "some id",
20+
imageName: "imageName",
21+
merge: false,
22+
};
23+
24+
export const testRunNewResponse: TestRunResponse = {
25+
url: "url",
26+
status: TestStatus.new,
27+
pixelMisMatchCount: 0,
28+
diffPercent: 0,
29+
diffTollerancePercent: 0,
30+
id: "some id",
31+
imageName: "imageName",
32+
merge: false,
33+
};
34+
35+
export const testRunAutoApprovedResponse: TestRunResponse = {
36+
url: "url",
37+
status: TestStatus.autoApproved,
38+
pixelMisMatchCount: 0,
39+
diffPercent: 0,
40+
diffTollerancePercent: 0,
41+
id: "some id",
42+
imageName: "imageName",
43+
merge: false,
44+
};

lib/helpers/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from "./config.helper";
22
export * from "./type.helper";
33
export * from "./dto.helper";
4+
export * from "./track.helper";

lib/helpers/track.helper.spec.ts

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { TestRunResponse, TestStatus } from "../types";
2+
import { processTestRun, shouldStopRetry } from "./track.helper";
3+
import {
4+
testRunOkResponse,
5+
testRunUnresolvedResponse,
6+
testRunAutoApprovedResponse,
7+
testRunNewResponse,
8+
} from "../__data__";
9+
10+
describe.each<[TestStatus.new | TestStatus.unresolved, string]>([
11+
[TestStatus.new, "No baseline: "],
12+
[TestStatus.unresolved, "Difference found: "],
13+
])("processTestRun", (status, expectedMessage) => {
14+
beforeEach(() => {
15+
testRunUnresolvedResponse.status = status;
16+
});
17+
18+
it(`default soft assert should throw exception if status ${status}`, () => {
19+
expect(() => processTestRun(testRunUnresolvedResponse)).toThrowError(
20+
new Error(expectedMessage.concat(testRunUnresolvedResponse.url))
21+
);
22+
});
23+
24+
it(`disabled soft assert should throw exception if status ${status}`, () => {
25+
const enableSoftAssert = false;
26+
27+
expect(() =>
28+
processTestRun(testRunUnresolvedResponse, enableSoftAssert)
29+
).toThrowError(
30+
new Error(expectedMessage.concat(testRunUnresolvedResponse.url))
31+
);
32+
});
33+
34+
it(`enabled soft assert should log error if status ${status}`, () => {
35+
console.error = jest.fn();
36+
const enableSoftAssert = true;
37+
38+
processTestRun(testRunUnresolvedResponse, enableSoftAssert);
39+
40+
expect(console.error).toHaveBeenCalledWith(
41+
expectedMessage.concat(testRunUnresolvedResponse.url)
42+
);
43+
});
44+
});
45+
46+
it.each<[TestRunResponse, boolean]>([
47+
[testRunOkResponse, true],
48+
[testRunUnresolvedResponse, false],
49+
[testRunAutoApprovedResponse, true],
50+
[testRunNewResponse, true],
51+
])("shouldStopRetry", (response, expectedResult) => {
52+
expect(shouldStopRetry(response)).toBe(expectedResult);
53+
});

lib/helpers/track.helper.ts

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { TestRunResponse, TestStatus } from "../types";
2+
3+
const getErrorMessage = (
4+
testRunResponse: TestRunResponse
5+
): string | undefined => {
6+
switch (testRunResponse.status) {
7+
case TestStatus.new: {
8+
return `No baseline: ${testRunResponse.url}`;
9+
}
10+
case TestStatus.unresolved: {
11+
return `Difference found: ${testRunResponse.url}`;
12+
}
13+
}
14+
};
15+
16+
export const processTestRun = (
17+
testRunResponse: TestRunResponse,
18+
enableSoftAssert?: boolean
19+
) => {
20+
const errorMessage = getErrorMessage(testRunResponse);
21+
22+
if (errorMessage) {
23+
if (enableSoftAssert) {
24+
// eslint-disable-next-line no-console
25+
console.error(errorMessage);
26+
} else {
27+
throw new Error(errorMessage);
28+
}
29+
}
30+
};
31+
32+
export const shouldStopRetry = (result: TestRunResponse) =>
33+
result.status !== TestStatus.unresolved;
34+
35+
export const trackWithRetry = async (
36+
trackFn: () => Promise<TestRunResponse>,
37+
retryLimit: number,
38+
enableSoftAssert?: boolean
39+
): Promise<TestRunResponse> => {
40+
const result = await trackFn();
41+
if (retryLimit <= 0 || shouldStopRetry(result)) {
42+
processTestRun(result, enableSoftAssert);
43+
return result;
44+
}
45+
// eslint-disable-next-line no-console
46+
console.info(`Diff found... Remaining retry attempts **${retryLimit}**`);
47+
return trackWithRetry(trackFn, retryLimit - 1, enableSoftAssert);
48+
};

lib/visualRegressionTracker.spec.ts

+59-65
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import axios, { AxiosError, AxiosResponse } from "axios";
22
import { mocked } from "jest-mock";
33
import FormData from "form-data";
4-
4+
import { testRunOkResponse, testRunUnresolvedResponse } from "./__data__";
55
import { VisualRegressionTracker } from "./visualRegressionTracker";
66
import {
77
Config,
@@ -164,17 +164,6 @@ const testRunBuffer: TestRunBuffer = {
164164
comment: "comment",
165165
};
166166

167-
const testRunResponse: TestRunResponse = {
168-
url: "url",
169-
status: TestStatus.unresolved,
170-
pixelMisMatchCount: 12,
171-
diffPercent: 0.12,
172-
diffTollerancePercent: 0,
173-
id: "some id",
174-
imageName: "imageName",
175-
merge: false,
176-
};
177-
178167
describe("VisualRegressionTracker", () => {
179168
let vrt: VisualRegressionTracker;
180169

@@ -249,34 +238,42 @@ describe("VisualRegressionTracker", () => {
249238
);
250239
});
251240

252-
it("should track base64", async () => {
241+
it("should track base64 without retry", async () => {
242+
const responce = testRunOkResponse;
253243
vrt["isStarted"] = jest.fn().mockReturnValueOnce(true);
254-
vrt["submitTestRunBase64"] = jest
255-
.fn()
256-
.mockResolvedValueOnce(testRunResponse);
257-
vrt["processTestRun"] = jest.fn();
244+
vrt["submitTestRunBase64"] = jest.fn().mockResolvedValue(responce);
258245

259246
await vrt.track(testRunBase64);
260247

261248
expect(vrt["submitTestRunBase64"]).toHaveBeenCalledWith(testRunBase64);
262-
expect(vrt["processTestRun"]).toHaveBeenCalledWith(testRunResponse);
249+
expect(vrt["submitTestRunBase64"]).toHaveBeenCalledTimes(1);
263250
expect(mockedTestRunResult).toHaveBeenCalledWith(
264-
testRunResponse,
251+
responce,
265252
"http://localhost:4200"
266253
);
267254
});
268255

269-
it("should track multipart", async () => {
256+
it("should track base64 with retry", async () => {
257+
const responce = testRunUnresolvedResponse;
258+
vrt["isStarted"] = jest.fn().mockReturnValueOnce(true);
259+
vrt["submitTestRunBase64"] = jest.fn().mockResolvedValue(responce);
260+
261+
await expect(vrt.track(testRunBase64, 3)).rejects.toThrowError(
262+
"Difference found: url"
263+
);
264+
expect(vrt["submitTestRunBase64"]).toHaveBeenCalledTimes(4);
265+
expect(vrt["submitTestRunBase64"]).toHaveBeenCalledWith(testRunBase64);
266+
});
267+
268+
it("should track multipart without retry", async () => {
269+
const responce = testRunOkResponse;
270270
const data = new FormData();
271271
const buildId = "1312";
272272
const projectId = "asd";
273273
vrt["buildId"] = buildId;
274274
vrt["projectId"] = projectId;
275275
vrt["isStarted"] = jest.fn().mockReturnValueOnce(true);
276-
vrt["submitTestRunMultipart"] = jest
277-
.fn()
278-
.mockResolvedValueOnce(testRunResponse);
279-
vrt["processTestRun"] = jest.fn();
276+
vrt["submitTestRunMultipart"] = jest.fn().mockResolvedValueOnce(responce);
280277
mockedDtoHelper.multipartDtoToFormData.mockReturnValueOnce(data);
281278

282279
await vrt.track(testRunMultipart);
@@ -287,25 +284,47 @@ describe("VisualRegressionTracker", () => {
287284
branchName: config.branchName,
288285
...testRunMultipart,
289286
});
287+
expect(vrt["submitTestRunMultipart"]).toHaveBeenCalledTimes(1);
290288
expect(vrt["submitTestRunMultipart"]).toHaveBeenCalledWith(data);
291-
expect(vrt["processTestRun"]).toHaveBeenCalledWith(testRunResponse);
292289
expect(mockedTestRunResult).toHaveBeenCalledWith(
293-
testRunResponse,
290+
responce,
294291
"http://localhost:4200"
295292
);
296293
});
297294

295+
it("should track multipart with retry", async () => {
296+
const responce = testRunUnresolvedResponse;
297+
const data = new FormData();
298+
const buildId = "1312";
299+
const projectId = "asd";
300+
vrt["buildId"] = buildId;
301+
vrt["projectId"] = projectId;
302+
vrt["isStarted"] = jest.fn().mockReturnValueOnce(true);
303+
vrt["submitTestRunMultipart"] = jest.fn().mockResolvedValue(responce);
304+
mockedDtoHelper.multipartDtoToFormData.mockReturnValueOnce(data);
305+
306+
await expect(vrt.track(testRunMultipart, 3)).rejects.toThrowError(
307+
"Difference found: url"
308+
);
309+
expect(mockedDtoHelper.multipartDtoToFormData).toHaveBeenCalledWith({
310+
buildId,
311+
projectId,
312+
branchName: config.branchName,
313+
...testRunMultipart,
314+
});
315+
expect(vrt["submitTestRunMultipart"]).toHaveBeenCalledTimes(4);
316+
expect(vrt["submitTestRunMultipart"]).toHaveBeenCalledWith(data);
317+
});
318+
298319
it("should track buffer", async () => {
320+
const responce = testRunOkResponse;
299321
const data = new FormData();
300322
const buildId = "1312";
301323
const projectId = "asd";
302324
vrt["buildId"] = buildId;
303325
vrt["projectId"] = projectId;
304326
vrt["isStarted"] = jest.fn().mockReturnValueOnce(true);
305-
vrt["submitTestRunMultipart"] = jest
306-
.fn()
307-
.mockResolvedValueOnce(testRunResponse);
308-
vrt["processTestRun"] = jest.fn();
327+
vrt["submitTestRunMultipart"] = jest.fn().mockResolvedValueOnce(responce);
309328
mockedDtoHelper.bufferDtoToFormData.mockReturnValueOnce(data);
310329

311330
await vrt.track(testRunBuffer);
@@ -317,9 +336,8 @@ describe("VisualRegressionTracker", () => {
317336
...testRunBuffer,
318337
});
319338
expect(vrt["submitTestRunMultipart"]).toHaveBeenCalledWith(data);
320-
expect(vrt["processTestRun"]).toHaveBeenCalledWith(testRunResponse);
321339
expect(mockedTestRunResult).toHaveBeenCalledWith(
322-
testRunResponse,
340+
responce,
323341
"http://localhost:4200"
324342
);
325343
});
@@ -415,7 +433,7 @@ describe("VisualRegressionTracker", () => {
415433

416434
describe("submitTestRunBase64", () => {
417435
it("should submit test run", async () => {
418-
const testRunResponse: TestRunResponse = {
436+
const testRunUnresolvedResponse: TestRunResponse = {
419437
url: "url",
420438
status: TestStatus.unresolved,
421439
pixelMisMatchCount: 12,
@@ -429,11 +447,13 @@ describe("VisualRegressionTracker", () => {
429447
const projectId = "asd";
430448
vrt["buildId"] = buildId;
431449
vrt["projectId"] = projectId;
432-
mockedAxios.post.mockResolvedValueOnce({ data: testRunResponse });
450+
mockedAxios.post.mockResolvedValueOnce({
451+
data: testRunUnresolvedResponse,
452+
});
433453

434454
const result = await vrt["submitTestRunBase64"](testRunBase64);
435455

436-
expect(result).toBe(testRunResponse);
456+
expect(result).toBe(testRunUnresolvedResponse);
437457
expect(mockedAxios.post).toHaveBeenCalledWith(
438458
`${config.apiUrl}/test-runs`,
439459
{
@@ -478,11 +498,13 @@ describe("VisualRegressionTracker", () => {
478498
describe("submitTestRunMultipart", () => {
479499
it("should submit test run", async () => {
480500
const data = new FormData();
481-
mockedAxios.post.mockResolvedValueOnce({ data: testRunResponse });
501+
mockedAxios.post.mockResolvedValueOnce({
502+
data: testRunUnresolvedResponse,
503+
});
482504

483505
const result = await vrt["submitTestRunMultipart"](data);
484506

485-
expect(result).toBe(testRunResponse);
507+
expect(result).toBe(testRunUnresolvedResponse);
486508
expect(mockedAxios.post).toHaveBeenCalledWith(
487509
`${config.apiUrl}/test-runs/multipart`,
488510
data,
@@ -546,32 +568,4 @@ describe("VisualRegressionTracker", () => {
546568
);
547569
});
548570
});
549-
550-
describe.each<[TestStatus.new | TestStatus.unresolved, string]>([
551-
[TestStatus.new, "No baseline: "],
552-
[TestStatus.unresolved, "Difference found: "],
553-
])("processTestRun", (status, expectedMessage) => {
554-
beforeEach(() => {
555-
testRunResponse.status = status;
556-
});
557-
558-
it(`disabled soft assert should throw exception if status ${status}`, () => {
559-
vrt["config"].enableSoftAssert = false;
560-
561-
expect(() => vrt["processTestRun"](testRunResponse)).toThrowError(
562-
new Error(expectedMessage.concat(testRunResponse.url))
563-
);
564-
});
565-
566-
it(`enabled soft assert should log error if status ${status}`, () => {
567-
console.error = jest.fn();
568-
vrt["config"].enableSoftAssert = true;
569-
570-
vrt["processTestRun"](testRunResponse);
571-
572-
expect(console.error).toHaveBeenCalledWith(
573-
expectedMessage.concat(testRunResponse.url)
574-
);
575-
});
576-
});
577571
});

0 commit comments

Comments
 (0)