qa-shadow-report
Version:
npm package that prints formatted test reports into a google sheet or csv file
400 lines (355 loc) • 12.6 kB
JavaScript
import { jest } from '@jest/globals';
// Mock constants before importing modules
jest.unstable_mockModule('../../constants.js', () => ({
TEST_TYPES_AVAILABLE: () => ['e2e', 'integration', 'unit'],
TEST_CATEGORIES_AVAILABLE: () => ['smoke', 'regression', 'sanity'],
ALL_TEAM_NAMES: () => ['Team1', 'Team2', 'team-3', 'team1'],
}));
// Mock helper functions
jest.unstable_mockModule('./extraction/dataExtractionUtilities.js', () => ({
extractAreaFromFullFile: jest.fn(async (fullFile) => 'TestArea'),
extractSpecFromFullFile: jest.fn(async (fullFile) => 'TestSpec'),
extractTypeFromFullFile: jest.fn(async (fullFile, types) => 'e2e'),
extractManualTestCaseIdFromTest: jest.fn(async (test) => 'TC123'),
extractTeamNameFromTest: jest.fn((test, teams) => {
if (!test || !test.fullTitle) {
throw new TypeError(
'The "test" object must have a "fullTitle" property of type string.'
);
}
if (typeof test.fullTitle !== 'string') {
throw new TypeError(
'The "test" object must have a "fullTitle" property of type string.'
);
}
if (!Array.isArray(teams) || teams.length === 0) {
return '';
}
const match = test.fullTitle.match(/\[(.*?)\]/);
return match ? match[1] : '';
}),
extractCategoryFromTest: jest.fn(async (test, categories) => 'smoke'),
extractTestNameFromFullTitle: jest.fn(async (fullTitle) => 'Test Case'),
}));
jest.unstable_mockModule('../sharedMethods/dateFormatting.js', () => ({
formatDuration: jest.fn(async (duration) => '1s'),
}));
jest.unstable_mockModule('./utilities/cellMaxLength.js', () => ({
enforceMaxLength: jest.fn(
(str, maxLength) => str?.substring(0, maxLength) || ''
),
}));
// Import modules after mocking
const { constructReportPayloadEntry } = await import('./buildReport.js');
const { extractTeamNameFromTest } = await import(
'./extraction/dataExtractionUtilities.js'
);
describe('Daily Report Methods', () => {
// Test Data Setup
const createTestParams = (result, test, playwright) => ({
result,
test,
playwright,
});
// constructReportPayloadEntry Tests
describe('constructReportPayloadEntry', () => {
const isPlaywrightOptions = [true, false];
isPlaywrightOptions.forEach((isPlaywright) => {
const testFramework = isPlaywright ? 'Playwright' : 'Cypress';
describe(`when using ${testFramework}`, () => {
it('should construct a payload entry with valid inputs', async () => {
const params = createTestParams(
{
fullFile: 'path/to/test.spec.js',
state: 'passed',
},
{
fullTitle: 'Test Suite [Team1] Test Case',
duration: 1000,
projectName: 'Project A',
err: null,
state: 'passed',
},
isPlaywright
);
const result = await constructReportPayloadEntry(
params.result,
params.test,
params.playwright
);
expect(result).toBeDefined();
expect(result).toHaveProperty('area');
expect(result).toHaveProperty('spec');
expect(result).toHaveProperty('testName');
expect(result).toHaveProperty('type');
expect(result).toHaveProperty('category');
expect(result).toHaveProperty('team');
expect(result).toHaveProperty('priority');
expect(result).toHaveProperty('status');
expect(result).toHaveProperty('state');
expect(result).toHaveProperty('manualTestId');
expect(result).toHaveProperty('error');
expect(result).toHaveProperty('speed');
});
it('should handle test failures', async () => {
const errorMessage = 'Test failed due to assertion error';
const params = createTestParams(
{
fullFile: 'path/to/test.spec.js',
state: 'failed',
},
{
fullTitle: 'Test Suite [Team1] Test Case',
duration: 1000,
projectName: 'Project A',
err: isPlaywright ? errorMessage : { message: errorMessage },
state: 'failed',
},
isPlaywright
);
const result = await constructReportPayloadEntry(
params.result,
params.test,
params.playwright
);
expect(result.state).toBe('failed');
expect(result.error).toBe(errorMessage);
});
it('should handle test timeouts', async () => {
const params = createTestParams(
{
fullFile: 'path/to/test.spec.js',
state: 'timeout',
},
{
fullTitle: 'Test Suite [Team1] Test Case',
duration: 30000,
projectName: 'Project A',
err: isPlaywright ? 'Test timeout' : { message: 'Test timeout' },
state: 'timeout',
},
isPlaywright
);
const result = await constructReportPayloadEntry(
params.result,
params.test,
params.playwright
);
expect(result.state).toBe('timeout');
expect(result.error).toBe('Test timeout');
});
it('should handle missing optional fields', async () => {
const params = createTestParams(
{
fullFile: 'path/to/test.spec.js',
state: 'passed',
},
{
fullTitle: 'Test Suite Test Case',
duration: 1000,
projectName: 'Project A',
err: null,
state: 'passed',
},
isPlaywright
);
const result = await constructReportPayloadEntry(
params.result,
params.test,
params.playwright
);
expect(result.team).toBe('');
expect(result.manualTestId).toBe('TC123');
expect(result.category).toBe('smoke');
});
it('should enforce maximum length for all fields', async () => {
const longString = 'A'.repeat(1000);
const params = createTestParams(
{
fullFile: 'path/to/test.spec.js',
state: 'passed',
},
{
fullTitle: `Test Suite [Team1] ${longString}`,
duration: 1000,
projectName: longString,
err: null,
state: 'passed',
},
isPlaywright
);
const result = await constructReportPayloadEntry(
params.result,
params.test,
params.playwright
);
Object.values(result).forEach((value) => {
if (typeof value === 'string') {
expect(value.length).toBeLessThanOrEqual(500);
}
});
});
it('should handle invalid file paths', async () => {
const params = createTestParams(
{
fullFile: 'invalid/path',
state: 'passed',
},
{
fullTitle: 'Test Suite [Team1] Test Case',
duration: 1000,
projectName: 'Project A',
err: null,
state: 'passed',
},
isPlaywright
);
const result = await constructReportPayloadEntry(
params.result,
params.test,
params.playwright
);
expect(result.spec).toBe('TestSpec');
expect(result.type).toBe('e2e');
});
});
});
it('should throw an error for invalid inputs', async () => {
const invalidInputs = [
{ result: null, test: {}, playwright: true },
{ result: {}, test: null, playwright: true },
{ result: {}, test: {}, playwright: 'not a boolean' },
];
for (const input of invalidInputs) {
await expect(
constructReportPayloadEntry(
input.result,
input.test,
input.playwright
)
).rejects.toThrow();
}
});
});
// extractTeamNameFromTest Tests
describe('extractTeamNameFromTest', () => {
it('should extract the team name from the test fullTitle', () => {
const test = { fullTitle: 'Some test [Team2]' };
const result = extractTeamNameFromTest(test, [
'Team1',
'Team2',
'team-3',
'team1',
]);
expect(result).toBe('Team2');
});
it('should return empty string if no team name is found', () => {
const test = { fullTitle: 'Some test without team name' };
const result = extractTeamNameFromTest(test, [
'Team1',
'Team2',
'team-3',
'team1',
]);
expect(result).toBe('');
});
it('should handle multiple team names and extract the correct one', () => {
const test = { fullTitle: 'Some test [team-3] [Team2]' };
const result = extractTeamNameFromTest(test, [
'Team1',
'Team2',
'team-3',
'team1',
]);
expect(result).toBe('team-3');
});
it('should be case insensitive', () => {
const test = { fullTitle: 'Some test [team1]' };
const result = extractTeamNameFromTest(test, [
'Team1',
'Team2',
'team-3',
'team1',
]);
expect(result).toBe('team1');
});
it('should throw TypeError if test object does not have fullTitle property', () => {
const test = { title: 'Some test' };
expect(() =>
extractTeamNameFromTest(test, ['Team1', 'Team2', 'team-3', 'team1'])
).toThrow(
'The "test" object must have a "fullTitle" property of type string.'
);
});
it('should throw TypeError if fullTitle is not a string', () => {
const test = { fullTitle: 12345 };
expect(() =>
extractTeamNameFromTest(test, ['Team1', 'Team2', 'team-3', 'team1'])
).toThrow(
'The "test" object must have a "fullTitle" property of type string.'
);
});
it('should return empty string if allTeamNames is empty', () => {
const test = { fullTitle: 'Some test [Team2]' };
const result = extractTeamNameFromTest(test, []);
expect(result).toBe('');
});
it('should handle special characters in team names', () => {
const specialTeamNames = ['team$pecial', 'team^'];
const test = { fullTitle: 'Some test [team$pecial]' };
const result = extractTeamNameFromTest(test, specialTeamNames);
expect(result).toBe('team$pecial');
});
it('should handle team names with spaces', () => {
const teamNames = ['Team Alpha', 'Team Beta'];
const test = { fullTitle: 'Some test [Team Alpha]' };
const result = extractTeamNameFromTest(test, teamNames);
expect(result).toBe('Team Alpha');
});
it('should handle team names with numbers', () => {
const teamNames = ['Team1', 'Team2', 'Team3'];
const test = { fullTitle: 'Some test [Team2]' };
const result = extractTeamNameFromTest(test, teamNames);
expect(result).toBe('Team2');
});
});
// Performance Tests
describe('Performance', () => {
it('should construct payload entries efficiently', async () => {
const params = createTestParams(
{
fullFile: 'path/to/test.spec.js',
state: 'passed',
},
{
fullTitle: 'Test Suite [Team1] Test Case',
duration: 1000,
projectName: 'Project A',
err: null,
},
true
);
const startTime = performance.now();
const iterations = 100;
for (let i = 0; i < iterations; i++) {
await constructReportPayloadEntry(
params.result,
params.test,
params.playwright
);
}
const endTime = performance.now();
expect(endTime - startTime).toBeLessThan(1000); // Should complete within 1 second
});
it('should extract team names efficiently', () => {
const test = { fullTitle: 'Test Suite [Team1] Test Case' };
const startTime = performance.now();
const iterations = 1000;
for (let i = 0; i < iterations; i++) {
extractTeamNameFromTest(test, ['Team1', 'Team2', 'team-3', 'team1']);
}
const endTime = performance.now();
expect(endTime - startTime).toBeLessThan(100); // Should complete within 100ms
});
});
});