Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion src/_data_/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Build, ImageComparison, Project } from '@prisma/client';
import { Baseline, Build, ImageComparison, Project, TestRun, TestVariation } from '@prisma/client';

export const TEST_PROJECT: Project = {
id: '1',
Expand Down Expand Up @@ -26,3 +26,67 @@ export const TEST_BUILD: Build = {
userId: '2341235',
isRunning: true,
};

export const generateBaseline = (baseline?: Partial<Baseline>): Baseline => {
return {
id: 'baselineId',
baselineName: 'baselineName',
testVariationId: 'testVariationId',
testRunId: 'testRunId',
updatedAt: new Date(),
createdAt: new Date(),
...baseline,
};
};

export const generateTestVariation = (
testVariation?: Partial<TestVariation>,
baselines?: Baseline[]
): TestVariation & { baselines: Baseline[] } => {
return {
id: '123',
projectId: 'project Id',
name: 'Test name',
baselineName: 'baselineName',
os: 'OS',
browser: 'browser',
viewport: 'viewport',
device: 'device',
ignoreAreas: '[]',
comment: 'some comment',
createdAt: new Date(),
updatedAt: new Date(),
branchName: 'master',
...testVariation,
baselines: baselines ?? [generateBaseline()],
};
};

export const generateTestRun = (testRun?: Partial<TestRun>): TestRun => {
return {
id: '10fb5e02-64e0-4cf5-9f17-c00ab3c96658',
imageName: '1592423768112.screenshot.png',
diffName: 'diffName',
diffPercent: 12,
diffTollerancePercent: 1,
pixelMisMatchCount: 123,
status: 'new',
buildId: '146e7a8d-89f0-4565-aa2c-e61efabb0afd',
testVariationId: '3bc4a5bc-006e-4d43-8e4e-eaa132627fca',
updatedAt: new Date(),
createdAt: new Date(),
name: 'ss2f77',
browser: 'chromium',
device: null,
os: null,
viewport: '1800x1600',
baselineName: null,
ignoreAreas: '[]',
tempIgnoreAreas: '[]',
comment: 'some comment',
baselineBranchName: 'master',
branchName: 'develop',
merge: false,
...testRun,
};
};
151 changes: 125 additions & 26 deletions src/test-runs/test-runs.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { CommentDto } from '../shared/dto/comment.dto';
import { TestVariationsService } from '../test-variations/test-variations.service';
import { TestRunDto } from '../test-runs/dto/testRun.dto';
import { BuildsService } from '../builds/builds.service';
import { TEST_PROJECT } from '../_data_';
import { generateBaseline, generateTestRun, generateTestVariation, TEST_PROJECT } from '../_data_';
import { getTestVariationUniqueData } from '../utils';
import { BaselineDataDto } from '../shared/dto/baseline-data.dto';
import { CompareService } from '../compare/compare.service';
Expand All @@ -39,6 +39,7 @@ const initService = async ({
testVariationFindManyMock = jest.fn(),
baselineCreateMock = jest.fn(),
testVariationFindOrCreateMock = jest.fn(),
testVariationGetDetailsMock = jest.fn(),
testVariationFindUniqueMock = jest.fn(),
projectFindUniqueMock = jest.fn(),
compareGetDiffMock = jest.fn(),
Expand Down Expand Up @@ -92,6 +93,7 @@ const initService = async ({
provide: TestVariationsService,
useValue: {
findOrCreate: testVariationFindOrCreateMock,
getDetails: testVariationGetDetailsMock,
},
},
{
Expand All @@ -114,31 +116,6 @@ describe('TestRunsService', () => {
const imageBuffer = Buffer.from('Image');
const ignoreAreas = [{ x: 1, y: 2, width: 10, height: 20 }];
const tempIgnoreAreas = [{ x: 3, y: 4, width: 30, height: 40 }];
const baseTestRun: TestRun = {
id: 'id',
imageName: 'imageName',
diffName: 'diffName',
baselineName: 'baselineName',
diffPercent: 1,
pixelMisMatchCount: 10,
diffTollerancePercent: 12,
status: TestStatus.new,
buildId: 'buildId',
testVariationId: 'testVariationId',
updatedAt: new Date(),
createdAt: new Date(),
name: 'test run name',
ignoreAreas: '[]',
tempIgnoreAreas: '[]',
browser: 'browser',
device: 'device',
os: 'os',
viewport: 'viewport',
branchName: 'develop',
baselineBranchName: 'master',
comment: 'some comment',
merge: false,
};

it('findOne', async () => {
const id = 'some id';
Expand Down Expand Up @@ -657,4 +634,126 @@ describe('TestRunsService', () => {
expect(service['tryAutoApproveByNewBaselines']).toHaveBeenCalledWith({ testVariation, testRun });
expect(mocked(TestRunResultDto)).toHaveBeenCalledWith(testRun, testVariation);
});

describe('tryAutoApproveByNewBaselines', () => {
it('skip if ok', async () => {
const testRun = generateTestRun({ status: TestStatus.ok });
service = await initService({});

const result = await service['tryAutoApproveByNewBaselines']({
testVariation: generateTestVariation(),
testRun,
});

expect(result).toBe(testRun);
});

it('should not auto approve', async () => {
const testRun = generateTestRun({ status: TestStatus.unresolved });
const baseline = generateBaseline();
const testRunFindManyMock = jest.fn().mockResolvedValueOnce([generateTestRun({ status: TestStatus.approved })]);
const testVariationGetDetailsMock = jest.fn().mockResolvedValueOnce(generateTestVariation({}, [baseline]));
service = await initService({ testRunFindManyMock, testVariationGetDetailsMock });
service['shouldAutoApprove'] = jest.fn().mockResolvedValueOnce(false);

const result = await service['tryAutoApproveByNewBaselines']({
testVariation: generateTestVariation(),
testRun,
});

expect(service['shouldAutoApprove']).toHaveBeenCalled();
expect(result).toBe(testRun);
});

it('should auto approve', async () => {
const testRun = generateTestRun({ status: TestStatus.unresolved });
const baseline = generateBaseline();
const testRunFindManyMock = jest.fn().mockResolvedValueOnce([generateTestRun({ status: TestStatus.approved })]);
const testVariationGetDetailsMock = jest.fn().mockResolvedValueOnce(generateTestVariation({}, [baseline]));
service = await initService({ testRunFindManyMock, testVariationGetDetailsMock });
service['shouldAutoApprove'] = jest.fn().mockResolvedValueOnce(true);
service.approve = jest.fn().mockResolvedValueOnce({
...testRun,
status: TestStatus.autoApproved,
});

const result = await service['tryAutoApproveByNewBaselines']({
testVariation: generateTestVariation(),
testRun,
});

expect(result).toStrictEqual({
...testRun,
status: TestStatus.autoApproved,
});
});
});

describe('tryAutoApproveByPastBaselines', () => {
it('skip if ok', async () => {
const testRun = generateTestRun({ status: TestStatus.ok });
service = await initService({});

const result = await service['tryAutoApproveByPastBaselines']({
testVariation: generateTestVariation(),
testRun,
});

expect(result).toBe(testRun);
});

it('skip if the branch the same as baseline', async () => {
const testRun = generateTestRun({ status: TestStatus.unresolved, branchName: 'a', baselineBranchName: 'a' });
service = await initService({});

const result = await service['tryAutoApproveByPastBaselines']({
testVariation: generateTestVariation(),
testRun,
});

expect(result).toBe(testRun);
});

it('should not auto approve', async () => {
const testRun = generateTestRun({ status: TestStatus.unresolved });
const baseline = generateBaseline();
const testVariationGetDetailsMock = jest
.fn()
.mockResolvedValueOnce(generateTestVariation({}, [baseline, baseline]));
service = await initService({ testVariationGetDetailsMock });
service['shouldAutoApprove'] = jest.fn().mockResolvedValueOnce(false);

const result = await service['tryAutoApproveByPastBaselines']({
testVariation: generateTestVariation(),
testRun,
});

expect(service['shouldAutoApprove']).toHaveBeenCalled();
expect(result).toBe(testRun);
});

it('should auto approve', async () => {
const testRun = generateTestRun({ status: TestStatus.unresolved });
const baseline = generateBaseline();
const testVariationGetDetailsMock = jest
.fn()
.mockResolvedValueOnce(generateTestVariation({}, [baseline, baseline]));
service = await initService({ testVariationGetDetailsMock });
service['shouldAutoApprove'] = jest.fn().mockResolvedValueOnce(true);
service.approve = jest.fn().mockResolvedValueOnce({
...testRun,
status: TestStatus.autoApproved,
});

const result = await service['tryAutoApproveByPastBaselines']({
testVariation: generateTestVariation(),
testRun,
});

expect(result).toStrictEqual({
...testRun,
status: TestStatus.autoApproved,
});
});
});
});
4 changes: 2 additions & 2 deletions src/test-runs/test-runs.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ export class TestRunsService {
const testVariationHistory = await this.testVariationService.getDetails(testVariation.id);
// skip first baseline as it was used by default in general flow
for (const baseline of testVariationHistory.baselines.slice(1)) {
if (this.shouldAutoApprove({ projectId: testVariation.projectId, baseline, testRun })) {
if (await this.shouldAutoApprove({ projectId: testVariation.projectId, baseline, testRun })) {
return this.approve(testRun.id, false, true);
}
}
Expand Down Expand Up @@ -321,7 +321,7 @@ export class TestRunsService {
const approvedTestVariation = await this.testVariationService.getDetails(approvedTestRun.testVariationId);
const baseline = approvedTestVariation.baselines.shift();

if (this.shouldAutoApprove({ projectId: testVariation.projectId, baseline, testRun })) {
if (await this.shouldAutoApprove({ projectId: testVariation.projectId, baseline, testRun })) {
return this.approve(testRun.id, false, true);
}
}
Expand Down
Binary file added test/image_edited_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 18 additions & 1 deletion test/test-runs.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe('TestRuns (e2e)', () => {

const image_v1 = './test/image.png';
const image_v2 = './test/image_edited.png';
const image_v3 = './test/image_edited_2.png';

beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
Expand Down Expand Up @@ -75,8 +76,24 @@ describe('TestRuns (e2e)', () => {
image_v1
);
await testRunsService.approve(testRun1.id);
const { testRun: testRun2 } = await haveTestRunCreated(
buildsService,
testRunsService,
project.id,
project.mainBranchName,
image_v2
);
await testRunsService.approve(testRun2.id);
const { testRun: testRun3 } = await haveTestRunCreated(
buildsService,
testRunsService,
project.id,
"feature",
image_v2
);
await testRunsService.approve(testRun3.id);

const { testRun } = await haveTestRunCreated(buildsService, testRunsService, project.id, 'develop', image_v2);
const { testRun } = await haveTestRunCreated(buildsService, testRunsService, project.id, 'develop', image_v3);

expect(testRun.status).toBe(TestStatus.unresolved);
});
Expand Down