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
5 changes: 3 additions & 2 deletions docs/report-configuration-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ lists patterns to ignore when generating a report.
```

If `type` is omitted at the top level then every entry in `overrides` must
specify `type`. The same rule applies to `tool` and `experience`. If all three
are omitted at the top level then `overrides` is required.
specify `type`. The same rule applies to `tool` and `experience`. If `type`,
`tool` and `experience` are all omitted at the top level then `overrides` is
required.
127 changes: 127 additions & 0 deletions schemas/report-configuration/v2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"$id": "/test-reporting/schemas/report-configuration/v2.json",
"$ref": "#/$defs/taxonomyObject",
"type": "object",
"unevaluatedProperties": false,
"properties": {
"ignorePatterns": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"$ref": "#/$defs/nonEmptyUnpaddedString"
}
},
"overrides": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "object",
"unevaluatedProperties": false,
"minProperties": 2,
"$ref": "#/$defs/taxonomyObject",
"properties": {
"pattern": {
"$ref": "#/$defs/nonEmptyUnpaddedString"
}
},
"required": [
"pattern"
]
}
}
},
"allOf": [
{
"if": {
"properties": {
"type": {
"const": null
}
}
},
"then": {
"properties": {
"overrides": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"$ref": "#/$defs/taxonomyObject/properties/type"
}
},
"required": [
"type"
]
}
}
}
}
},
{
"if": {
"properties": {
"tool": {
"const": null
}
}
},
"then": {
"properties": {
"overrides": {
"type": "array",
"items": {
"type": "object",
"properties": {
"tool": {
"$ref": "#/$defs/taxonomyObject/properties/tool"
}
},
"required": [
"tool"
]
}
}
}
}
},
{
"if": {
"properties": {
"type": {
"const": null
},
"tool": {
"const": null
}
}
},
"then": {
"required": [
"overrides"
]
}
}
],
"$defs": {
"nonEmptyUnpaddedString": {
"type": "string",
"minLength": 1,
"pattern": "^(?!\\s).+(?<!\\s)$"
},
"taxonomyObject": {
"type": "object",
"properties": {
"type": {
"$ref": "#/$defs/nonEmptyUnpaddedString"
},
"tool": {
"$ref": "#/$defs/nonEmptyUnpaddedString"
}
}
}
}
}
20 changes: 15 additions & 5 deletions src/helpers/report-builder.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ class ReportDetailBuilder extends ReportBuilderBase {
constructor(reportConfiguration, codeowners, { reportVersionLatest = false } = {}) {
super();

this._reportConfiguration = reportConfiguration;
this._codeowners = codeowners;
this._reportConfiguration = reportConfiguration;
this._reportVersionLatest = reportVersionLatest;

this._setProperty('retries', 0);
Expand Down Expand Up @@ -320,13 +320,18 @@ class ReportBuilder extends ReportBuilderBase {
reportConfigurationPath,
reportWriter,
reportVersionLatest = false,
reportConfigurationVersionLatest = false,
verbose = false
} = options;

this._logger = logger;
this._verbose = verbose;
this._reportVersionLatest = reportVersionLatest;
this._reportConfiguration = new ReportConfiguration(reportConfigurationPath);
this._reportConfiguration = new ReportConfiguration(
reportConfigurationPath,
logger,
{ configurationVersionLatest: reportConfigurationVersionLatest }
);

if (reportWriter) {
if (reportPath) {
Expand Down Expand Up @@ -380,9 +385,14 @@ class ReportBuilder extends ReportBuilderBase {
const { details } = this._data;

if (!details.has(id)) {
details.set(id, new ReportDetailBuilder(this._reportConfiguration, this._codeowners, {
reportVersionLatest: this._reportVersionLatest
}));
details.set(
id,
new ReportDetailBuilder(
this._reportConfiguration,
this._codeowners,
{ reportVersionLatest: this._reportVersionLatest }
)
);
}

return details.get(id);
Expand Down
69 changes: 64 additions & 5 deletions src/helpers/report-configuration.cjs
Original file line number Diff line number Diff line change
@@ -1,16 +1,57 @@
const fs = require('node:fs');
const { resolve } = require('node:path');
const { formatErrorAjv, validateReportConfigurationV1Ajv } = require('./schema.cjs');
const {
formatErrorAjv,
validateReportConfigurationV1Ajv,
validateReportConfigurationV2Ajv
} = require('./schema.cjs');
const { minimatch } = require('minimatch');
const { makeRelativeFilePath } = require('./system.cjs');

const defaultConfigurationPath = './d2l-test-reporting.config.json';

const upgradeReportConfigurationV1ToV2 = (configuration, logger) => {
const { experience, overrides, ...rest } = configuration;
const upgraded = { ...rest };

if (experience != null) {
logger.warning('Report configuration field \'experience\' is no longer supported and will be ignored');
}

if (overrides) {
const upgradedOverrides = [];

for (const override of overrides) {
const { experience: overrideExperience, ...overrideRest } = override;

if (overrideExperience != null) {
logger.warning(`Report configuration override for pattern '${override.pattern}' has field 'experience' which is no longer supported and will be ignored`);
}

if (Object.keys(overrideRest).length < 2) {
logger.warning(`Report configuration override for pattern '${override.pattern}' has no remaining fields after upgrade and will be dropped`);

continue;
}

upgradedOverrides.push(overrideRest);
}

if (upgradedOverrides.length > 0) {
upgraded.overrides = upgradedOverrides;
}
}

return upgraded;
};

class ReportConfiguration {
constructor(path) {
constructor(path, logger, { configurationVersionLatest = false } = {}) {
let reportConfiguration;
let reportConfigurationPath;

this._configurationVersionLatest = configurationVersionLatest;

if (path) {
path = resolve(path);

Expand Down Expand Up @@ -45,7 +86,15 @@ class ReportConfiguration {
reportConfigurationPath = makeRelativeFilePath(path);
}

if (!validateReportConfigurationV1Ajv(reportConfiguration)) {
if (configurationVersionLatest) {
reportConfiguration = upgradeReportConfigurationV1ToV2(reportConfiguration, logger);

if (!validateReportConfigurationV2Ajv(reportConfiguration)) {
const { errors } = validateReportConfigurationV2Ajv;

throw new Error(formatErrorAjv(errors, { dataVar: 'report configuration' }));
}
} else if (!validateReportConfigurationV1Ajv(reportConfiguration)) {
const { errors } = validateReportConfigurationV1Ajv;

throw new Error(formatErrorAjv(errors, { dataVar: 'report configuration' }));
Expand Down Expand Up @@ -76,7 +125,10 @@ class ReportConfiguration {
if (minimatch(filePath, pattern)) {
metadata.type = overriddenType?.toLowerCase();
metadata.tool = overriddenTool;
metadata.experience = overriddenExperience;

if (!this._configurationVersionLatest) {
metadata.experience = overriddenExperience;
}

break;
}
Expand All @@ -90,14 +142,21 @@ class ReportConfiguration {

metadata.type = metadata.type ?? defaultType?.toLowerCase();
metadata.tool = metadata.tool ?? defaultTool;
metadata.experience = metadata.experience ?? defaultExperience;

if (!this._configurationVersionLatest) {
metadata.experience = metadata.experience ?? defaultExperience;
}

return metadata;
}

hasTaxonomy(filePath) {
const taxonomy = this.getTaxonomy(filePath);

if (this._configurationVersionLatest) {
return taxonomy.type != null && taxonomy.tool != null;
}

return taxonomy.type != null &&
taxonomy.tool != null &&
taxonomy.experience != null;
Expand Down
3 changes: 3 additions & 0 deletions src/helpers/schema.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ addErrors(ajv);
addFormats(ajv, ['date-time', 'uri', 'uuid']);

ajv.addSchema(require('../../schemas/report-configuration/v1.json'));
ajv.addSchema(require('../../schemas/report-configuration/v2.json'));
ajv.addSchema(require('../../schemas/report/v1.json'));
ajv.addSchema(require('../../schemas/report/v2.json'));
ajv.addSchema(latestReportSchema);
Expand All @@ -39,6 +40,7 @@ ajv.addSchema({
});

const validateReportConfigurationV1Ajv = ajv.getSchema('/test-reporting/schemas/report-configuration/v1.json');
const validateReportConfigurationV2Ajv = ajv.getSchema('/test-reporting/schemas/report-configuration/v2.json');
const validateReportV1ContextAjv = ajv.getSchema('/test-reporting/schemas/report/v1/context/loose.json');
const validateReportV2ContextAjv = ajv.getSchema('/test-reporting/schemas/report/v2/context/loose.json');
const validateReportV3ContextAjv = ajv.getSchema('/test-reporting/schemas/report/v3/context/loose.json');
Expand All @@ -53,6 +55,7 @@ const { details: { items: { properties: { browser: { enum: latestSupportedBrowse
module.exports = {
formatErrorAjv,
validateReportConfigurationV1Ajv,
validateReportConfigurationV2Ajv,
validateReportV1ContextAjv,
validateReportV2ContextAjv,
validateReportV3ContextAjv,
Expand Down
2 changes: 2 additions & 0 deletions src/reporters/webdriverio.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class WebdriverIO extends WDIOReporter {
this._baseReportPath = options.reportPath || './d2l-test-report.json';
this._reportConfigurationPath = options.reportConfigurationPath || './d2l-test-reporting.config.json';
this._reportVersionLatest = options.reportVersionLatest || false;
this._reportConfigurationVersionLatest = options.reportConfigurationVersionLatest || false;
this._verbose = options.verbose || false;
this._logger = logger;
this._report = null;
Expand Down Expand Up @@ -65,6 +66,7 @@ class WebdriverIO extends WDIOReporter {
reportPath: workerReportPath,
reportConfigurationPath: this._reportConfigurationPath,
reportVersionLatest: this._reportVersionLatest,
reportConfigurationVersionLatest: this._reportConfigurationVersionLatest,
verbose: this._verbose
});
console.log('[D2L Reporter] Initialized successfully');
Expand Down
1 change: 1 addition & 0 deletions test/integration/data/configs/mocha.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = {
reporterOptions: [
'reportPath=./d2l-test-report-mocha.json',
'reportVersionLatest=true',
'reportConfigurationVersionLatest=true',
'verbose=true'
]
};
1 change: 1 addition & 0 deletions test/integration/data/configs/playwright.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { defineConfig, devices } from '@playwright/test';
const playwrightReporterOptions = {
reportPath: './d2l-test-report-playwright.json',
reportVersionLatest: true,
reportConfigurationVersionLatest: true,
verbose: true
};

Expand Down
1 change: 1 addition & 0 deletions test/integration/data/configs/web-test-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default {
reporter({
reportPath: './d2l-test-report-web-test-runner.json',
reportVersionLatest: true,
reportConfigurationVersionLatest: true,
verbose: true
})
],
Expand Down
1 change: 1 addition & 0 deletions test/integration/data/configs/webdriverio.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ exports.config = {
reportPath: './d2l-test-report-webdriverio.json',
reportConfigurationPath: './d2l-test-reporting.config.json',
reportVersionLatest: true,
reportConfigurationVersionLatest: true,
verbose: true
}]
],
Expand Down