Closed edumserrano closed 1 month ago
I understand this is just a quality of life improvement, there's almost nothing that this feature allows doing that you can't already do. However, let me give you an example of how my Azure DevOps CI pipeline looks like to help justify the use case for my feature request:
[!NOTE]
The below are fragments of my pipeline for Azure DevOps that uses the blob reporter and the merge cli to produce the merged Playwright html reporter.
First, each job will run its sharded Playwright test run and upload the raw data from the blob reporter. The $(shardValue)
and $(totalShards)
are variables set for each shard run. After each sharded Playwright test execution, the pipeline will contain several artifacts named playwright-blob-reporter-shard-<shard-number>
, each containing a zip of the raw data from the test execution.
- task: PowerShell@2
displayName: Run Playwright tests
inputs:
targetType: inline
script: |
npx playwright test --shard=$(shardValue)/$(totalShards)
- task: PublishPipelineArtifact@1
displayName: Publish Playwright blob reporter
inputs:
targetPath: $(Build.SourcesDirectory)/test-reporters/playwright
artifactName: playwright-blob-reporter-shard-$(shardValue)
parallel: true
After all the sharded runs have executed, we download each of the artifacts and flatten them into the ./blob-reporter
directory. At this point, the ./blob-reporter
directory contains all the zip files from each sharded run and all we have to do is use the Playwright merge CLI and give it a Playwright merge config to produce the merged test reporters.
- task: DownloadPipelineArtifact@2
inputs:
buildType: current
itemPattern: '**/*.zip'
targetPath: $(Build.ArtifactStagingDirectory)/temp
- task: PowerShell@2
displayName: Merge playwright blob reports
inputs:
targetType: inline
script: |
mkdir $(Build.SourcesDirectory)/blob-reporter
Get-ChildItem -File -Recurse -LiteralPath $(Build.ArtifactStagingDirectory)/temp `
| where {$_.FullName -like '*blob-reporter*'} `
| Move-Item -Destination $(Build.SourcesDirectory)/blob-reporter
npx playwright merge-reports --config=playwright.merge.ts ./blob-reporter
Trying to do the same with monocart reporter is definitily possible but involves more steps as well as it involves keeping the merge.ts file in sync with how many shards we want to use. This is not an issue with the Playwright merge CLI example I just gave because we can provide it with a directory of zip files and it will read all of them to generate the merged test reports.
Another reason I believe this feature is useful is that it lowers the barrier for people wanting to merge monocart-reporter test results. The first problem I encountered when following your documentation was that I wanted to use a typescript file for the merge but didn't know how to then execute it. Had to research that.
I also remember having a problem trying to use the example merge.js file because my project's package.json
wasn't of type:module
so I couldn't use the import
statments, had to change those.
These are all small things I understand but for inexperienced people they are barriers to overcome to be able to simply merge reports.
Lastly I would say that having a behaviour aligned with the official Playwright tools, even though monocart-reporter supported merging before Playwright did, is a positive as it means users can easily move between tools or even use both.
Please try monocart-reporter@2.8.0
npx monocart merge <glob-patterns>
# -o --outputFile
npx monocart merge path-to/shard*/index.json -o merged-reports/index.html
# -c --config
npx monocart merge path-to/shard*/index.json -c mr.config.js
Hi @cenfun , sorry for my delayed response.
I can run the merge cli and provide a path to the sharded reports as well as define an output path for the report. That seems to work fine. However I need to be able to pass a custom config to be used by the merge CLI and I'm struggling to do that.
1) Can you give me a sample of what the (EDIT: See the post below, I was able to get it working)
2) Is it at all possible to use a mr.config.js
should look like?.ts
file for the config? Probably not right? I'm asking because in my case I'm using a typescript for the Playwright config file playwright.config.ts
and in that config file I have some functions to get the monocart options to use when configuring the monocart-reporter and I'd like to export and reuse those functions in the merge CLI config file.
I was able to get the merge CLI using a config file working. All I needed to do was to export an object of type MonocartReporterOptions.
Here's how my config file looks like:
const path = require('node:path');
function getCodeCoverageOptions(monocartReporterOutputDir) {
const codeCoverageDir = path.resolve(monocartReporterOutputDir, "code-coverage");
const v8RelativeFilePath = "v8/index.html";
// The paths in the codeCoverageReports variable are all relative to monocart-reporter coverage.outputDir.
const codeCoverageReports = [
[
"v8",
{
outputFile: v8RelativeFilePath, // v8 sub dir and html file name, relative to coverage.outputDir.
inline: true, // inline all scripts required for the V8 html report into a single HTML file.
metrics: ["lines"], // metrics is an Array<"bytes" | "functions" | "branches" | "lines">
},
],
[
"console-summary",
{
metrics: ["lines"],
},
],
[
"cobertura",
{
file: "cobertura/code-coverage.cobertura.xml",
},
],
[
"lcovonly",
{
file: "lcov/code-coverage.lcov.info",
},
],
];
// for documentation on the monocart code coverage options see:
// - https://github.com/cenfun/monocart-reporter#code-coverage-report
// - https://github.com/cenfun/monocart-coverage-reports
// - https://github.com/cenfun/monocart-coverage-reports/blob/main/lib/index.d.ts
const coverageOptions = {
outputDir: codeCoverageDir, // all code coverage reports will be created in this dir.
reportPath: path.resolve(codeCoverageDir, v8RelativeFilePath), // code coverage html report filepath which shows up in the monocart report under global attachments.
reports: codeCoverageReports,
sourceFilter: (sourcePath) => {
// Only include files that are under the src folder.
// Configure this filter accordingly to your app.
return (
sourcePath.startsWith("projects/playground/src") ||
sourcePath.startsWith("projects/ngx-module-federation-tools/")
);
},
entryFilter: (entry) => {
// Exclude files that aren't excluded by sourceFilter because they
// are not included in the sourcemap.See:
// - https://github.com/cenfun/monocart-reporter/issues/60
//
// Configure this filter accordingly to your app, you might not
// even need it if sourceFilter is enough.
const url = entry.url;
return !url.includes("fonts.googleapis.com");
},
};
return coverageOptions;
}
function getMonocartOptions() {
const reportersOutputDir = path.resolve("./test-reporters/playwright");
const monocartReporterOutputDir = path.resolve(reportersOutputDir, "monocart-reporter");
const monocartOptions = {
name: "Playground app for @ln/ngx-module-federation-tools",
outputFile: path.resolve(monocartReporterOutputDir, "monocart-report.html"),
coverage: getCodeCoverageOptions(monocartReporterOutputDir, false),
tags: {
// See https://github.com/cenfun/monocart-reporter#style-tags
console: {
background: "#0066cc",
},
"remote-module-stores": {
background: " #cc66ff",
},
"remote-module": {
background: "#6600cc",
},
"micro-frontend-hosts": {
background: "#009933",
},
"dynamic-angular-components": {
background: "#00d1ca",
},
"custom-elements": {
background: "#c77700",
},
},
customFieldsInComments: true,
columns: (defaultColumns) => {
// See https://github.com/cenfun/monocart-reporter#custom-columns
//
// Need to define a custom column that will be used to map the data collected from the
// `customFieldsInComments: true` option defined above.
// Because the test comments are only using the @description comment item, I only need to
// define a single column with id 'description'.
//
// If the tests used multiple comment items, such as @description and @owner, then I would have
// to also define a custom column with id of 'owner' to map its values to the report.
const descriptionColumn = defaultColumns.find(
(column) => column.id === "description",
);
// if there's no description column then add one and place it before the duration column
if (!descriptionColumn) {
const index = defaultColumns.findIndex(
(column) => column.id === "duration",
);
defaultColumns.splice(index, 0, {
id: "description",
name: "Description",
align: "left",
searchable: true,
detailed: true,
markdown: true,
styleMap: {
"font-weight": "normal",
},
});
}
},
};
return monocartOptions;
}
const options = getMonocartOptions();
module.exports = options;
Any thoughts on:
Is it at all possible to use a .ts file for the config? Probably not right? I'm asking because in my case I'm using a typescript for the Playwright config file playwright.config.ts and in that config file I have some functions to get the monocart options to use when configuring the monocart-reporter and I'd like to export and reuse those functions in the merge CLI config file. [^1]
I guess the only way would be for you to support .ts
files as input to the merge CLI right? You would have to do something like:
ts-node can register the typescript file to be transpiled on runtime and there by allowing us to use the typescript file in JS file
As described in How to use Typescript files inside Javascript file?.
I'm out of my depth here so perhaps I'm just saying nonsense
If it helps understand why I'm asking this:
It's because the big monocart options that you see in this comment is in a .ts
file that I use as part of my playwright.config.ts
. And I would like to avoid having to duplicate this code into a JS file for the merge CLI. I'd like to use the same code by exporting a function that provides the monocart report options from the ts
file so I can re-use it on the merge CLI config file.
[^1]: source comment
So I guess the obvious solution if I want to share code is to write the common code in a JS file and import that into my TS file. That works.
I'll close this as it seems to be working all well 👏
I also wanted to leave here some feedback on how my Azure DevOps CI pipeline looks like doing a sharded test run and then merging monocart reports using monocart-reporter's merge CLI so it can be contrasted with this comment which shows sharded test runs using the built-in html reporter and Playwright's merge-reports
option.
First, each job will run its sharded Playwright test run, archive the contents of the monocart reporter output into a tar.gz
file and upload it. The $(shardValue)
and $(totalShards)
are variables set for each shard run. After each sharded Playwright test execution, the pipeline will contain several artifacts named playwright-monocart-reporters-shard-<shard-number>
, each containing a tar.gz
of the output from the monocart reporter for that shard.
- task: PowerShell@2
displayName: Run Playwright tests
inputs:
targetType: inline
script: |
npx playwright test --shard=$(shardValue)/$(totalShards)
- task: ArchiveFiles@2
displayName: Zip monocart reports
inputs:
rootFolderOrFile: '$(Build.SourcesDirectory)/test-reporters/playwright/monocart-reporter'
includeRootFolder: false
archiveType: 'tar'
archiveFile: '$(Build.SourcesDirectory)/test-reporters/playwright/monocart-reporter-zip/monocart-reporter-$(shardValue).tar.gz'
verbose: true
- task: PublishPipelineArtifact@1
displayName: Publish Playwright monocart reports
inputs:
targetPath: $(Build.SourcesDirectory)/test-reporters/playwright
artifactName: playwright-monocart-reporters-shard-$(shardValue)
parallel: true
After all the sharded runs have executed, we download each of the artifacts and flatten them into the ./test-reporters/shards/monocart-reporter
directory. At this point, the ./test-reporters/shards/monocart-reporter
directory contains all the tar.gz
monocart reports from each sharded run. Then we extract each of the tar.gz
files into their own directory and execute the monocart-reporter merge CLI with a merge config file, which is this example is named playwright.monocart-reporter-merge.js
to produce the merged monocart report.
- task: DownloadPipelineArtifact@2
displayName: Download Playwright monocart reports
inputs:
buildType: current
itemPattern: '*/monocart-reporter-zip/*.tar.gz'
targetPath: $(Build.ArtifactStagingDirectory)/temp
- task: PowerShell@2
displayName: Merge playwright monocart reports
inputs:
targetType: inline
script: |
mkdir -p $(Build.SourcesDirectory)/test-reporters/shards/monocart-reporter
Get-ChildItem -File -Recurse -LiteralPath $(Build.ArtifactStagingDirectory)/temp `
| Move-Item -Destination $(Build.SourcesDirectory)/test-reporters/shards/monocart-reporter
$zippedMonocartReports = Get-ChildItem -File -LiteralPath $(Build.SourcesDirectory)/test-reporters/shards/monocart-reporter
foreach ($zip in $zippedMonocartReports)
{
$folderName = $zip.Name.Split('.')[0] # remove the .tar.gz extension
$extractToFolder = "$(Build.SourcesDirectory)/test-reporters/shards/monocart-reporter/$folderName"
mkdir -p $extractToFolder
tar -xvzf $zip -C $extractToFolder
}
npx monocart merge ./test-reporters/shards/**/monocart-report.json -c ./playwright.monocart-reporter-merge.js
Description
After #139, with version
2.7.1
of monocart-reporter it became much easier to merge reports from sharded Playwright test runs.I can easily create a merged monocart report with the following merge file:
And by running:
npx tsx .\playwright.monocart-reporter-merge.ts
.In a CI environment, to get the above to work, I have to: 1) upload the monocart reporter output generated from each sharded run to the pipeline artifacts. 2) once all shards have executed, download the artifact from each sharded run into a folder structure that matches the one expected by the merge file above. 3) run the merge command:
npx tsx .\playwright.monocart-reporter-merge.ts
.Whilst it is possible to do all of the above it is a bit cumbersome in two aspects:
1) If you want to change the number of shards or the directory where the data from the shards is you have to update the merge file logic as well. 2) You have to code some logic on the pipeline so that the download from the pipeline artifacts matches the folder structure expected by the merge file.
I believe that both of these issues can be alleviated by following the approach used by Playwright with the blob reporter and the merge cli.
Suggestion
1) Consider adding a way to tell monocart reporter that it should only produce raw data and that at the end that raw data should be zipped. For instance, the
MonocartReporterOptions
could have araw
boolean property which defaults tofalse
. 2) Create a CLI tool, whether as part of the existingmonocart-reporter
or as a separate package, that can be invoked to merge monocart reports. This CLI tool would take in a path to a folder that contains one or more zipped raw report data and invoke themerge
function from themonocart-reporter
. In essence, this CLI tool is nothing more than a wrapper around themerge
function from themonocart-reporter
package. 3) The merge CLI tool should also take in an input parameter that would let us specify the path to a merge file. This merge file should export theMonocartReporterOptions
object which would be used to do the merge.