Skip to content

Commit b717b6c

Browse files
Weekly (#107)
* added weekly summary feature * added readme updates * added notes for install and report generation
1 parent 5a68d89 commit b717b6c

31 files changed

+1502
-320
lines changed

README.md

Lines changed: 156 additions & 146 deletions
Large diffs are not rendered by default.

cli.js

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import chalk from 'chalk';
33
import { isProjectConfigured } from './scripts/configuredStatus.js';
44
import { main } from './src/index.js';
55
import { handleDailyReport } from './src/sharedMethods/dailyReportHandler.js';
6-
import { handleSummary } from './src/sharedMethods/summaryHandler.js';
6+
import {
7+
handleSummary,
8+
handleWeeklySummary,
9+
} from './src/sharedMethods/summaryHandler.js';
710
import { spawn } from 'child_process';
811
import { GOOGLE_KEYFILE_PATH, GOOGLE_SHEET_ID } from './constants.js';
912
import path from 'path';
@@ -34,7 +37,7 @@ const resolvePostInstallScript = () => {
3437
async function run() {
3538
const args = process.argv.slice(2);
3639
const commands = args.filter((arg) =>
37-
['todays-report', 'monthly-summary'].includes(arg)
40+
['todays-report', 'monthly-summary', 'weekly-summary'].includes(arg)
3841
);
3942

4043
const command = commands[0] || ''; // Select the first command if multiple, though typically there should only be one
@@ -47,9 +50,13 @@ async function run() {
4750
const framework = frameworkArg || ''; // Ensure the framework is correctly specified
4851
const isCypress = framework === 'cypress' || framework === 'cy';
4952
const isPlaywright = framework === 'playwright' || framework === 'pw';
50-
const unsupportedCsvForMonthly = isCSV && command.includes('monthly-summary');
51-
const unsupportedDuplicateCsvForMonthly =
52-
isCSV && isDuplicate && command.includes('monthly-summary');
53+
const unsupportedCsvForSummary =
54+
isCSV &&
55+
(command.includes('monthly-summary') || command.includes('weekly-summary'));
56+
const unsupportedDuplicateCsvForSummary =
57+
isCSV &&
58+
isDuplicate &&
59+
(command.includes('monthly-summary') || command.includes('weekly-summary'));
5360
const optionsPayload = {
5461
csv: isCSV,
5562
duplicate: isDuplicate,
@@ -68,6 +75,7 @@ async function run() {
6875
Commands (Optional):
6976
todays-report Only generate today's report.
7077
monthly-summary Only generate previous months summary.
78+
weekly-summary Only generate previous weeks summary.
7179
7280
Options (Optional):
7381
--csv Output the report in CSV format.
@@ -80,7 +88,7 @@ async function run() {
8088
Generate today's report for Playwright in CSV format:
8189
qa-shadow-report playwright todays-report --csv
8290
83-
Generate a daily report and monthly summary when necessary, in google sheets, for cypress:
91+
Generate a daily report, and/or summaries as configured, in google sheets, for cypress:
8492
qa-shadow-report cypress
8593
8694
Shortcuts:
@@ -136,10 +144,10 @@ async function run() {
136144
chalk.green('playwright')
137145
);
138146
process.exit(1);
139-
} else if (unsupportedCsvForMonthly || unsupportedDuplicateCsvForMonthly) {
147+
} else if (unsupportedCsvForSummary || unsupportedDuplicateCsvForSummary) {
140148
console.info(
141149
chalk.yellow(
142-
'Error: CSV output for "monthly-summary" with or without duplication is not supported.'
150+
'Error: CSV output for summaries with or without duplication is not supported.'
143151
)
144152
);
145153
process.exit(1);
@@ -152,6 +160,9 @@ async function run() {
152160
case 'monthly-summary':
153161
await handleSummary({ ...optionsPayload });
154162
break;
163+
case 'weekly-summary':
164+
await handleWeeklySummary({ ...optionsPayload });
165+
break;
155166
default:
156167
await main({ ...optionsPayload });
157168
break;

constants.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,24 @@ export const TEST_CATEGORIES_AVAILABLE = () => {
365365
});
366366
};
367367

368+
export const WEEK_START = () => {
369+
return getCachedOrCompute('startDay', () => {
370+
return shadowConfigDetails.weeklySummaryStartDay;
371+
});
372+
};
373+
374+
export const WEEKLY_SUMMARY_ENABLED = () => {
375+
return getCachedOrCompute('active', () => {
376+
const weeklySummaryActive =
377+
shadowConfigDetails && shadowConfigDetails.weeklySummaryStartDay;
378+
if (weeklySummaryActive) {
379+
return true;
380+
} else {
381+
return false;
382+
}
383+
});
384+
};
385+
368386
export const DEFAULT_HEADER_METRICS = [
369387
'# passed tests',
370388
'# failed tests',
@@ -404,3 +422,38 @@ export const ALL_TEAM_NAMES = () => {
404422
}
405423
});
406424
};
425+
426+
export const DAYS = {
427+
Sunday: 0,
428+
Monday: 1,
429+
Tuesday: 2,
430+
Wednesday: 3,
431+
Thursday: 4,
432+
Friday: 5,
433+
Saturday: 6,
434+
};
435+
436+
export const SHORT_DAYS = {
437+
Monday: 'Mon',
438+
Tuesday: 'Tue',
439+
Wednesday: 'Wed',
440+
Thursday: 'Thu',
441+
Friday: 'Fri',
442+
Saturday: 'Sat',
443+
Sunday: 'Sun',
444+
};
445+
446+
export const MONTHS = [
447+
'Jan',
448+
'Feb',
449+
'Mar',
450+
'Apr',
451+
'May',
452+
'Jun',
453+
'Jul',
454+
'Aug',
455+
'Sep',
456+
'Oct',
457+
'Nov',
458+
'Dec',
459+
];

images/dailyReport.png

-984 KB
Loading

images/weeklySummary.png

519 KB
Loading

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "qa-shadow-report",
3-
"version": "2.0.1",
3+
"version": "2.1.1",
44
"bin": {
55
"qa-shadow-report": "./cli.js",
66
"qasr": "./cli.js",

scripts/postInstall.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,17 @@ const createConfigFile = () => {
146146
// googleSpreadsheetUrl: 'your-google-spreadsheet-url' OR googleSpreadsheetUrl: process.env.GOOGLE_SHEET_URL,
147147
148148
// Path to Google credentials file (service account JSON file): Replace with the file path or use an environment variable.
149-
// googleKeyFilePath: 'googleCredentials.json' OR googleKeyFilePath: process.env.GOOGLE_KEY_FILE_PATH,
149+
// googleKeyFilePath: './googleCredentials.json' OR googleKeyFilePath: process.env.GOOGLE_KEY_FILE_PATH,
150150
151151
// Path to test data results file in the format generated by your test runner. Replace with the path or use an environment variable.
152152
// testData: './path-to-test-results/output.json' OR testData: process.env.TEST_DATA,
153153
154154
// Directory for saving CSV downloads (optional). Uncomment and replace with your preferred path or use an environment variable.
155-
// csvDownloadsPath: 'downloads' OR csvDownloadsPath: process.env.CSV_DOWNLOADS_PATH,
155+
// csvDownloadsPath: './downloads' OR csvDownloadsPath: process.env.CSV_DOWNLOADS_PATH,
156+
157+
// Weekly summary settings (optional). To activate, set weekly summary sart date, summary will includes the start date and the following 7 days.
158+
// weeklySummaryStartDay: 'Monday' OR process.env.WEEKLY_SUMMARY_START_DAY
159+
},
156160
};
157161
`;
158162
fs.writeFileSync(configFilePath, defaultConfigContent, {

src/dailyReportMethods/buildReport.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
1-
// Utility functions imports
21
import { formatDuration } from '../sharedMethods/dateFormatting.js';
3-
4-
// Data extraction and reporting imports
52
import * as dataExtraction from './extraction/dataExtractionUtilities.js';
6-
7-
// Shared methods imports
83
import { enforceMaxLength } from './utilities/cellMaxLength.js';
9-
10-
// Configuration and constants imports
114
import * as constants from '../../constants.js';
125

136
/**

src/dailyReportMethods/extraction/dataExtractionUtilities.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export const extractAreaFromFullFile = async (fullFile, testTypesAvailable) => {
2727
.filter((segment) => !testTypesAvailable.includes(segment))
2828
.join('/');
2929

30-
return area; // The function only returns the area
30+
return area;
3131
};
3232

3333
/**

src/dailyReportMethods/reportGeneration/buildDailyPayload.js

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,37 +30,24 @@ export const buildDailyPayload = async (dataSet, playwright) => {
3030
throw new Error('Invalid columnsAvailable: Expected an array.');
3131
}
3232

33-
// Initialize the structure for daily payload
3433
let fullDailyPayload = initializeDailyPayload();
35-
36-
// Process test suites to construct payload entries
3734
const payloadEntries = await processTestSuites(dataSet, playwright);
3835
fullDailyPayload.bodyPayload = payloadEntries;
3936

40-
// Sort the structured data
4137
sortPayload(fullDailyPayload);
42-
43-
// Map object values to body payload
4438
fullDailyPayload.bodyPayload = fullDailyPayload.bodyPayload.map(
4539
Object.values
4640
);
47-
48-
// Construct and assign report headers
4941
fullDailyPayload.headerPayload = await constructHeaderReport(
5042
fullDailyPayload.bodyPayload
5143
);
52-
53-
// Append state reports to the header payload
5444
appendStateReportsToHeader(
5545
fullDailyPayload.headerPayload,
5646
DEFAULT_HEADER_METRICS,
5747
playwright
5848
);
59-
60-
// Append available columns and save to configuration
6149
fullDailyPayload.headerPayload.push(columnsAvailable);
6250

63-
// Append the end row to the footer payload
6451
const headerRowIndex = findHeaderRowIndex(fullDailyPayload.headerPayload);
6552
const headerRow = fullDailyPayload.headerPayload[headerRowIndex - 1];
6653
const statusTargetIndex = headerRow.indexOf('state');
@@ -71,6 +58,6 @@ export const buildDailyPayload = async (dataSet, playwright) => {
7158
return fullDailyPayload;
7259
} catch (error) {
7360
console.error('Error building daily payload:', error);
74-
throw error; // Rethrow to allow further error handling from the caller
61+
throw error;
7562
}
7663
};

src/dailyReportMethods/reportGeneration/combineReports.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export const combineReports = (allReportEntries, placeholders) => {
2525
let combinedReports = [];
2626

2727
try {
28-
// Determine the maximum count of type entries across all reports
2928
const maxTypeCount = Math.max(
3029
...allReportEntries.map((report) => {
3130
if (!Array.isArray(report)) {
@@ -35,7 +34,6 @@ export const combineReports = (allReportEntries, placeholders) => {
3534
})
3635
);
3736

38-
// Iterate over each type count index
3937
for (let i = 0; i < maxTypeCount; i++) {
4038
let combinedRowTests = [];
4139
let combinedRowPassed = [];
@@ -46,7 +44,6 @@ export const combineReports = (allReportEntries, placeholders) => {
4644
combinedRowPassed.push(...(report[2 * i + 1] || placeholders[1]));
4745
});
4846

49-
// Add the combined rows to the main array
5047
combinedReports.push(combinedRowTests, combinedRowPassed);
5148
}
5249

src/dailyReportMethods/reportGeneration/constructHeaderReport.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,8 @@ export const constructHeaderReport = async (payload) => {
3232
{ types: teamNames, index: 5 },
3333
];
3434

35-
// Initialize an array to store all report entries
3635
const allReportEntries = [];
3736

38-
// Loop through each type structure to generate report entries
3937
for (const typeData of typeArrays) {
4038
if (!Array.isArray(typeData.types)) {
4139
throw new Error(
@@ -51,13 +49,9 @@ export const constructHeaderReport = async (payload) => {
5149
allReportEntries.push(reportEntry);
5250
}
5351

54-
// Calculate the maximum number of types across all categories
5552
const maxTypes = Math.max(...typeArrays.map((t) => t.types.length));
56-
57-
// Generate placeholders for the report
5853
const placeholders = generatePlaceholders(maxTypes);
5954

60-
// Combine all report entries and placeholders into one report
6155
return combineReports(allReportEntries, placeholders);
6256
} catch (error) {
6357
console.error('Error constructing header report:', error);

src/dailyReportMethods/reportGeneration/reportGenerationHelpers.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,6 @@ export const buildFormulas = (
275275
const templates = constants.FORMULA_TEMPLATES;
276276
const keys = constants.FORMULA_KEYS;
277277

278-
// Generate actual formula strings by filling in the templates
279278
const filledFormulas = templates.map(fillTemplate);
280279

281280
const combinedObject = keys.reduce((obj, key, index) => {
@@ -405,7 +404,6 @@ export const createMergeQueries = (data, headerRowIndex, sheetId) => {
405404
throw new Error('Sheet ID must be a non-negative integer.');
406405
}
407406

408-
// Helper function to create a single merge query object
409407
const createMergeQuery = (start, end, startColumn, endColumn) => ({
410408
sheetId,
411409
startRowIndex: start,
@@ -414,7 +412,6 @@ export const createMergeQueries = (data, headerRowIndex, sheetId) => {
414412
endColumnIndex: endColumn,
415413
});
416414

417-
// Processes merges for a single column
418415
const processColumn = (columnIndex) => {
419416
const merges = [];
420417
let startMergeIndex = headerRowIndex;
@@ -439,10 +436,7 @@ export const createMergeQueries = (data, headerRowIndex, sheetId) => {
439436
return merges;
440437
};
441438

442-
// Combine merge queries for both columns
443439
const merges = [...processColumn(0), ...processColumn(1)];
444-
445-
// Construct the requestBody for the batch update
446440
const requestBody = {
447441
requests: merges.map((merge) => ({
448442
mergeCells: {

src/dailyReportMethods/utilities/cellMaxLength.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@ export const enforceMaxLength = (str, maxLength) => {
1515
}
1616

1717
try {
18-
// Convert the input to a string if it's a number
1918
const result =
2019
typeof str === 'number' || typeof str === 'string' ? String(str) : '';
21-
// Return the truncated string
2220
return result.substring(0, maxLength);
2321
} catch (error) {
2422
console.error('Error in enforceMaxLength:', error);

src/google/googleSheetIntegration/createNewtab.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { dataObjects } from '../../index.js';
22
import { sheets, auth, spreadsheetId } from '../auth.js';
33
import { createSummaryTitle } from '../sheetDataMethods/createTabNames.js';
4+
import { createWeeklySummaryTitle } from '../../sharedMethods/summaryHandler.js';
45

56
export const createNewTab = async (
67
sheetName,
@@ -36,3 +37,38 @@ export const createNewTab = async (
3637
throw error;
3738
}
3839
};
40+
41+
export const createNewWeeklyTab = async (
42+
sheetName,
43+
// mockBatchUpdate, // Mock function for testing
44+
createSummaryTitleFn = createWeeklySummaryTitle, // Default to actual function
45+
dataObjectsRef = dataObjects, // Default to actual dataObjects
46+
sheetsInstance // Injected dependency for testing
47+
) => {
48+
// Use the injected sheetsInstance or fall back to the actual sheets object
49+
const sheetsAPI = sheetsInstance || sheets;
50+
const authToUse = (sheetsInstance && sheetsInstance.auth) || auth;
51+
const spreadsheetIdToUse =
52+
(sheetsInstance && sheetsInstance.spreadsheetId) || spreadsheetId;
53+
54+
try {
55+
const response = await sheetsAPI.spreadsheets.batchUpdate({
56+
auth: authToUse,
57+
spreadsheetId: spreadsheetIdToUse,
58+
requestBody: {
59+
requests: [{ addSheet: { properties: { title: sheetName } } }],
60+
},
61+
});
62+
63+
const summaryTitle = createSummaryTitleFn();
64+
if (sheetName.includes(summaryTitle)) {
65+
dataObjectsRef.weeklySummaryTabData = response;
66+
} else {
67+
dataObjectsRef.todaysReportData = response;
68+
}
69+
return response;
70+
} catch (error) {
71+
console.error('"createNewTab": Error creating new sheet:', error);
72+
throw error;
73+
}
74+
};

src/google/googleSheetIntegration/writeToSheet.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const writeToSheet = async (sheetTitle, values, sheetsInstance) => {
2323
});
2424
} catch (error) {
2525
console.error(`Error writing to sheet "${sheetTitle}":`, error);
26-
throw error; // Ensure errors are thrown for test catching
26+
throw error;
2727
}
2828
};
2929

@@ -49,6 +49,6 @@ export const batchUpdateMasterSheet = async (payload, sheetsInstance) => {
4949
});
5050
} catch (error) {
5151
console.error('Error applying batch update:', error);
52-
throw error; // Ensure errors are thrown for test catching
52+
throw error;
5353
}
5454
};

0 commit comments

Comments
 (0)