@smoothdeploy/playwright 1.57.1 → 1.58.1-beta-1770383926000
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @smoothdeploy/playwright might be problematic. Click here for more details.
- package/ThirdPartyNotices.txt +1188 -65
- package/lib/agents/agentParser.js +89 -0
- package/lib/agents/generateAgents.js +27 -74
- package/lib/agents/generateAgents.js.map +7 -0
- package/lib/agents/playwright-test-planner.agent.md +1 -0
- package/lib/common/config.js +6 -4
- package/lib/common/config.js.map +7 -0
- package/lib/common/configLoader.js.map +7 -0
- package/lib/common/esmLoaderHost.js +2 -0
- package/lib/common/esmLoaderHost.js.map +7 -0
- package/lib/common/expectBundle.js +2 -17
- package/lib/common/expectBundle.js.map +7 -0
- package/lib/common/expectBundleImpl.js +132 -132
- package/lib/common/expectBundleImpl.js.map +7 -0
- package/lib/common/fixtures.js.map +7 -0
- package/lib/common/globals.js.map +7 -0
- package/lib/common/ipc.js.map +7 -0
- package/lib/common/poolBuilder.js.map +7 -0
- package/lib/common/process.js +28 -0
- package/lib/common/process.js.map +7 -0
- package/lib/common/suiteUtils.js.map +7 -0
- package/lib/common/test.js.map +7 -0
- package/lib/common/testLoader.js.map +7 -0
- package/lib/common/testType.js.map +7 -0
- package/lib/common/validators.js +10 -10
- package/lib/common/validators.js.map +7 -0
- package/lib/fsWatcher.js.map +7 -0
- package/lib/index.js +205 -12
- package/lib/index.js.map +7 -0
- package/lib/internalsForTest.js.map +7 -0
- package/lib/isomorphic/events.js.map +7 -0
- package/lib/isomorphic/folders.js.map +7 -0
- package/lib/isomorphic/stringInternPool.js.map +7 -0
- package/lib/isomorphic/teleReceiver.js +15 -2
- package/lib/isomorphic/teleReceiver.js.map +7 -0
- package/lib/isomorphic/teleSuiteUpdater.js +24 -4
- package/lib/isomorphic/teleSuiteUpdater.js.map +7 -0
- package/lib/isomorphic/testServerConnection.js.map +7 -0
- package/lib/isomorphic/testServerInterface.js.map +7 -0
- package/lib/isomorphic/testTree.js +13 -18
- package/lib/isomorphic/testTree.js.map +7 -0
- package/lib/isomorphic/types.d.js.map +7 -0
- package/lib/loader/loaderMain.js.map +7 -0
- package/lib/matchers/expect.js +2 -15
- package/lib/matchers/expect.js.map +7 -0
- package/lib/matchers/matcherHint.js +1 -44
- package/lib/matchers/matcherHint.js.map +7 -0
- package/lib/matchers/matchers.js +3 -2
- package/lib/matchers/matchers.js.map +7 -0
- package/lib/matchers/toBeTruthy.js +5 -3
- package/lib/matchers/toBeTruthy.js.map +7 -0
- package/lib/matchers/toEqual.js +4 -3
- package/lib/matchers/toEqual.js.map +7 -0
- package/lib/matchers/toHaveURL.js +5 -6
- package/lib/matchers/toHaveURL.js.map +7 -0
- package/lib/matchers/toMatchAriaSnapshot.js +5 -5
- package/lib/matchers/toMatchAriaSnapshot.js.map +7 -0
- package/lib/matchers/toMatchSnapshot.js +9 -8
- package/lib/matchers/toMatchSnapshot.js.map +7 -0
- package/lib/matchers/toMatchText.js +9 -9
- package/lib/matchers/toMatchText.js.map +7 -0
- package/lib/mcp/browser/actions.d.js.map +7 -0
- package/lib/mcp/browser/browserContextFactory.js +62 -29
- package/lib/mcp/browser/browserContextFactory.js.map +7 -0
- package/lib/mcp/browser/browserServerBackend.js +17 -9
- package/lib/mcp/browser/browserServerBackend.js.map +7 -0
- package/lib/mcp/browser/codegen.js.map +7 -0
- package/lib/mcp/browser/config.js +65 -12
- package/lib/mcp/browser/config.js.map +7 -0
- package/lib/mcp/browser/context.js +71 -94
- package/lib/mcp/browser/context.js.map +7 -0
- package/lib/mcp/browser/response.js +172 -131
- package/lib/mcp/browser/response.js.map +7 -0
- package/lib/mcp/browser/sessionLog.js +19 -104
- package/lib/mcp/browser/sessionLog.js.map +7 -0
- package/lib/mcp/browser/tab.js +92 -41
- package/lib/mcp/browser/tab.js.map +7 -0
- package/lib/mcp/browser/tools/common.js +8 -6
- package/lib/mcp/browser/tools/common.js.map +7 -0
- package/lib/mcp/browser/tools/console.js +7 -5
- package/lib/mcp/browser/tools/console.js.map +7 -0
- package/lib/mcp/browser/tools/dialogs.js +4 -4
- package/lib/mcp/browser/tools/dialogs.js.map +7 -0
- package/lib/mcp/browser/tools/evaluate.js +11 -19
- package/lib/mcp/browser/tools/evaluate.js.map +7 -0
- package/lib/mcp/browser/tools/files.js +3 -3
- package/lib/mcp/browser/tools/files.js.map +7 -0
- package/lib/mcp/browser/tools/form.js +9 -19
- package/lib/mcp/browser/tools/form.js.map +7 -0
- package/lib/mcp/browser/tools/install.js +6 -3
- package/lib/mcp/browser/tools/install.js.map +7 -0
- package/lib/mcp/browser/tools/keyboard.js +34 -11
- package/lib/mcp/browser/tools/keyboard.js.map +7 -0
- package/lib/mcp/browser/tools/mouse.js +11 -11
- package/lib/mcp/browser/tools/mouse.js.map +7 -0
- package/lib/mcp/browser/tools/navigate.js +14 -5
- package/lib/mcp/browser/tools/navigate.js.map +7 -0
- package/lib/mcp/browser/tools/network.js +20 -11
- package/lib/mcp/browser/tools/network.js.map +7 -0
- package/lib/mcp/browser/tools/open.js +57 -0
- package/lib/mcp/browser/tools/pdf.js +9 -19
- package/lib/mcp/browser/tools/pdf.js.map +7 -0
- package/lib/mcp/browser/tools/runCode.js +11 -8
- package/lib/mcp/browser/tools/runCode.js.map +7 -0
- package/lib/mcp/browser/tools/screenshot.js +16 -29
- package/lib/mcp/browser/tools/screenshot.js.map +7 -0
- package/lib/mcp/browser/tools/snapshot.js +21 -29
- package/lib/mcp/browser/tools/snapshot.js.map +7 -0
- package/lib/mcp/browser/tools/tabs.js +12 -12
- package/lib/mcp/browser/tools/tabs.js.map +7 -0
- package/lib/mcp/browser/tools/tool.js +2 -4
- package/lib/mcp/browser/tools/tool.js.map +7 -0
- package/lib/mcp/browser/tools/tracing.js +6 -6
- package/lib/mcp/browser/tools/tracing.js.map +7 -0
- package/lib/mcp/browser/tools/utils.js +49 -44
- package/lib/mcp/browser/tools/utils.js.map +7 -0
- package/lib/mcp/browser/tools/verify.js +24 -34
- package/lib/mcp/browser/tools/verify.js.map +7 -0
- package/lib/mcp/browser/tools/wait.js +6 -6
- package/lib/mcp/browser/tools/wait.js.map +7 -0
- package/lib/mcp/browser/tools.js +3 -1
- package/lib/mcp/browser/tools.js.map +7 -0
- package/lib/mcp/browser/watchdog.js.map +7 -0
- package/lib/mcp/config.d.js.map +7 -0
- package/lib/mcp/extension/cdpRelay.js +1 -1
- package/lib/mcp/extension/cdpRelay.js.map +7 -0
- package/lib/mcp/extension/extensionContextFactory.js +6 -5
- package/lib/mcp/extension/extensionContextFactory.js.map +7 -0
- package/lib/mcp/extension/protocol.js.map +7 -0
- package/lib/mcp/index.js.map +7 -0
- package/lib/mcp/log.js.map +7 -0
- package/lib/mcp/program.js +15 -20
- package/lib/mcp/program.js.map +7 -0
- package/lib/mcp/sdk/bundle.js.map +7 -0
- package/lib/mcp/sdk/exports.js +0 -2
- package/lib/mcp/sdk/exports.js.map +7 -0
- package/lib/mcp/sdk/http.js +20 -55
- package/lib/mcp/sdk/http.js.map +7 -0
- package/lib/mcp/sdk/inProcessTransport.js.map +7 -0
- package/lib/mcp/sdk/proxyBackend.js.map +7 -0
- package/lib/mcp/sdk/server.js +29 -4
- package/lib/mcp/sdk/server.js.map +7 -0
- package/lib/mcp/sdk/tool.js +2 -2
- package/lib/mcp/sdk/tool.js.map +7 -0
- package/lib/mcp/terminal/cli.js +296 -0
- package/lib/mcp/terminal/command.js +56 -0
- package/lib/mcp/terminal/commands.js +333 -0
- package/lib/mcp/terminal/daemon.js +129 -0
- package/lib/mcp/terminal/help.json +32 -0
- package/lib/mcp/terminal/helpGenerator.js +88 -0
- package/lib/mcp/terminal/socketConnection.js +80 -0
- package/lib/mcp/test/browserBackend.js +3 -13
- package/lib/mcp/test/browserBackend.js.map +7 -0
- package/lib/mcp/test/generatorTools.js +9 -9
- package/lib/mcp/test/generatorTools.js.map +7 -0
- package/lib/mcp/test/plannerTools.js +23 -22
- package/lib/mcp/test/plannerTools.js.map +7 -0
- package/lib/mcp/test/seed.js.map +7 -0
- package/lib/mcp/test/streams.js.map +7 -0
- package/lib/mcp/test/testBackend.js +6 -6
- package/lib/mcp/test/testBackend.js.map +7 -0
- package/lib/mcp/test/testContext.js +9 -3
- package/lib/mcp/test/testContext.js.map +7 -0
- package/lib/mcp/test/testTool.js.map +7 -0
- package/lib/mcp/test/testTools.js +12 -10
- package/lib/mcp/test/testTools.js.map +7 -0
- package/lib/mcpBundleImpl.js.map +7 -0
- package/lib/plugins/gitCommitInfoPlugin.js.map +7 -0
- package/lib/plugins/index.js.map +7 -0
- package/lib/plugins/webServerPlugin.js.map +7 -0
- package/lib/program.js +18 -4
- package/lib/program.js.map +7 -0
- package/lib/reporters/base.js +29 -4
- package/lib/reporters/base.js.map +7 -0
- package/lib/reporters/blob.js +3 -0
- package/lib/reporters/blob.js.map +7 -0
- package/lib/reporters/dot.js +17 -0
- package/lib/reporters/dot.js.map +7 -0
- package/lib/reporters/empty.js.map +7 -0
- package/lib/reporters/github.js.map +7 -0
- package/lib/reporters/html.js +13 -3
- package/lib/reporters/html.js.map +7 -0
- package/lib/reporters/internalReporter.js +6 -0
- package/lib/reporters/internalReporter.js.map +7 -0
- package/lib/reporters/json.js.map +7 -0
- package/lib/reporters/junit.js.map +7 -0
- package/lib/reporters/line.js +18 -0
- package/lib/reporters/line.js.map +7 -0
- package/lib/reporters/list.js +22 -0
- package/lib/reporters/list.js.map +7 -0
- package/lib/reporters/listModeReporter.js.map +7 -0
- package/lib/reporters/markdown.js.map +7 -0
- package/lib/reporters/merge.js +25 -8
- package/lib/reporters/merge.js.map +7 -0
- package/lib/reporters/multiplexer.js +8 -0
- package/lib/reporters/multiplexer.js.map +7 -0
- package/lib/reporters/reporterV2.js.map +7 -0
- package/lib/reporters/smoothdeploy.js +191 -0
- package/lib/reporters/teleEmitter.js +22 -4
- package/lib/reporters/teleEmitter.js.map +7 -0
- package/lib/reporters/versions/blobV1.js.map +7 -0
- package/lib/runner/dispatcher.js +20 -4
- package/lib/runner/dispatcher.js.map +7 -0
- package/lib/runner/failureTracker.js.map +7 -0
- package/lib/runner/lastRun.js.map +7 -0
- package/lib/runner/loadUtils.js +2 -2
- package/lib/runner/loadUtils.js.map +7 -0
- package/lib/runner/loaderHost.js.map +7 -0
- package/lib/runner/processHost.js +19 -0
- package/lib/runner/processHost.js.map +7 -0
- package/lib/runner/projectUtils.js +1 -1
- package/lib/runner/projectUtils.js.map +7 -0
- package/lib/runner/rebase.js.map +7 -0
- package/lib/runner/reporters.js +3 -1
- package/lib/runner/reporters.js.map +7 -0
- package/lib/runner/sigIntWatcher.js.map +7 -0
- package/lib/runner/storage.js +91 -0
- package/lib/runner/taskRunner.js.map +7 -0
- package/lib/runner/tasks.js.map +7 -0
- package/lib/runner/testGroups.js +14 -6
- package/lib/runner/testGroups.js.map +7 -0
- package/lib/runner/testRunner.js +13 -4
- package/lib/runner/testRunner.js.map +7 -0
- package/lib/runner/testServer.js +2 -2
- package/lib/runner/testServer.js.map +7 -0
- package/lib/runner/uiModeReporter.js.map +7 -0
- package/lib/runner/vcs.js.map +7 -0
- package/lib/runner/watchMode.js +2 -1
- package/lib/runner/watchMode.js.map +7 -0
- package/lib/runner/workerHost.js +6 -0
- package/lib/runner/workerHost.js.map +7 -0
- package/lib/third_party/pirates.js.map +7 -0
- package/lib/third_party/tsconfig-loader.js.map +7 -0
- package/lib/transform/babelBundle.js +3 -0
- package/lib/transform/babelBundle.js.map +7 -0
- package/lib/transform/babelBundleImpl.js +134 -134
- package/lib/transform/babelBundleImpl.js.map +7 -0
- package/lib/transform/compilationCache.js +2 -0
- package/lib/transform/compilationCache.js.map +7 -0
- package/lib/transform/esmLoader.js +10 -11
- package/lib/transform/esmLoader.js.map +7 -0
- package/lib/transform/md.js +221 -0
- package/lib/transform/portTransport.js.map +7 -0
- package/lib/transform/transform.js +18 -8
- package/lib/transform/transform.js.map +7 -0
- package/lib/util.js +3 -6
- package/lib/util.js.map +7 -0
- package/lib/utilsBundle.js +7 -0
- package/lib/utilsBundle.js.map +7 -0
- package/lib/utilsBundleImpl.js +51 -48
- package/lib/utilsBundleImpl.js.map +7 -0
- package/lib/worker/fixtureRunner.js +6 -2
- package/lib/worker/fixtureRunner.js.map +7 -0
- package/lib/worker/testInfo.js +39 -19
- package/lib/worker/testInfo.js.map +7 -0
- package/lib/worker/testTracing.js.map +7 -0
- package/lib/worker/timeoutManager.js.map +7 -0
- package/lib/worker/util.js.map +7 -0
- package/lib/worker/workerMain.js +17 -16
- package/lib/worker/workerMain.js.map +7 -0
- package/package.json +2 -2
- package/test.mjs +1 -0
- package/types/test.d.ts +26 -6
- package/types/testReporter.d.ts +1 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/reporters/html.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport { Transform } from 'stream';\n\nimport { HttpServer, MultiMap, assert, calculateSha1, getPackageManagerExecCommand, copyFileAndMakeWritable, gracefullyProcessExitDoNotHang, removeFolders, sanitizeForFilePath, toPosixPath } from 'playwright-core/lib/utils';\nimport { colors } from 'playwright-core/lib/utils';\nimport { open } from 'playwright-core/lib/utilsBundle';\nimport { mime } from 'playwright-core/lib/utilsBundle';\nimport { yazl } from 'playwright-core/lib/zipBundle';\n\nimport { CommonReporterOptions, formatError, formatResultFailure, internalScreen } from './base';\nimport { codeFrameColumns } from '../transform/babelBundle';\nimport { resolveReporterOutputPath, stripAnsiEscapes } from '../util';\n\nimport type { ReporterV2 } from './reporterV2';\nimport type { HtmlReporterOptions as HtmlReporterConfigOptions, Metadata, TestAnnotation } from '../../types/test';\nimport type * as api from '../../types/testReporter';\nimport type { HTMLReport, HTMLReportOptions, Location, Stats, TestAttachment, TestCase, TestCaseSummary, TestFile, TestFileSummary, TestResult, TestStep } from '@html-reporter/types';\nimport type { ZipFile } from 'playwright-core/lib/zipBundle';\nimport type { TransformCallback } from 'stream';\n\ntype TestEntry = {\n testCase: TestCase;\n testCaseSummary: TestCaseSummary\n};\n\ntype HtmlReportOpenOption = NonNullable<HtmlReporterConfigOptions['open']>;\nconst htmlReportOptions: HtmlReportOpenOption[] = ['always', 'never', 'on-failure'];\n\nconst isHtmlReportOption = (type: string): type is HtmlReportOpenOption => {\n return htmlReportOptions.includes(type as HtmlReportOpenOption);\n};\n\nclass HtmlReporter implements ReporterV2 {\n private config!: api.FullConfig;\n private suite!: api.Suite;\n private _options: HtmlReporterConfigOptions & CommonReporterOptions;\n private _outputFolder!: string;\n private _attachmentsBaseURL!: string;\n private _open: string | undefined;\n private _port: number | undefined;\n private _host: string | undefined;\n private _buildResult: { ok: boolean, singleTestId: string | undefined } | undefined;\n private _topLevelErrors: api.TestError[] = [];\n\n constructor(options: HtmlReporterConfigOptions & CommonReporterOptions) {\n this._options = options;\n }\n\n version(): 'v2' {\n return 'v2';\n }\n\n printsToStdio() {\n return false;\n }\n\n onConfigure(config: api.FullConfig) {\n this.config = config;\n }\n\n onBegin(suite: api.Suite) {\n const { outputFolder, open, attachmentsBaseURL, host, port } = this._resolveOptions();\n this._outputFolder = outputFolder;\n this._open = open;\n this._host = host;\n this._port = port;\n this._attachmentsBaseURL = attachmentsBaseURL;\n const reportedWarnings = new Set<string>();\n for (const project of this.config.projects) {\n if (this._isSubdirectory(outputFolder, project.outputDir) || this._isSubdirectory(project.outputDir, outputFolder)) {\n const key = outputFolder + '|' + project.outputDir;\n if (reportedWarnings.has(key))\n continue;\n reportedWarnings.add(key);\n writeLine(colors.red(`Configuration Error: HTML reporter output folder clashes with the tests output folder:`));\n writeLine(`\n html reporter folder: ${colors.bold(outputFolder)}\n test results folder: ${colors.bold(project.outputDir)}`);\n writeLine('');\n writeLine(`HTML reporter will clear its output directory prior to being generated, which will lead to the artifact loss.\n`);\n }\n }\n this.suite = suite;\n }\n\n _resolveOptions(): { outputFolder: string, open: HtmlReportOpenOption, attachmentsBaseURL: string, host: string | undefined, port: number | undefined } {\n const outputFolder = reportFolderFromEnv() ?? resolveReporterOutputPath('playwright-report', this._options.configDir, this._options.outputFolder);\n return {\n outputFolder,\n open: getHtmlReportOptionProcessEnv() || this._options.open || 'on-failure',\n attachmentsBaseURL: process.env.PLAYWRIGHT_HTML_ATTACHMENTS_BASE_URL || this._options.attachmentsBaseURL || 'data/',\n host: process.env.PLAYWRIGHT_HTML_HOST || this._options.host,\n port: process.env.PLAYWRIGHT_HTML_PORT ? +process.env.PLAYWRIGHT_HTML_PORT : this._options.port,\n };\n }\n\n _isSubdirectory(parentDir: string, dir: string): boolean {\n const relativePath = path.relative(parentDir, dir);\n return !!relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath);\n }\n\n onError(error: api.TestError): void {\n this._topLevelErrors.push(error);\n }\n\n async onEnd(result: api.FullResult) {\n const projectSuites = this.suite.suites;\n await removeFolders([this._outputFolder]);\n let noSnippets: boolean | undefined;\n if (process.env.PLAYWRIGHT_HTML_NO_SNIPPETS === 'false' || process.env.PLAYWRIGHT_HTML_NO_SNIPPETS === '0')\n noSnippets = false;\n else if (process.env.PLAYWRIGHT_HTML_NO_SNIPPETS)\n noSnippets = true;\n noSnippets = noSnippets || this._options.noSnippets;\n\n let noCopyPrompt: boolean | undefined;\n if (process.env.PLAYWRIGHT_HTML_NO_COPY_PROMPT === 'false' || process.env.PLAYWRIGHT_HTML_NO_COPY_PROMPT === '0')\n noCopyPrompt = false;\n else if (process.env.PLAYWRIGHT_HTML_NO_COPY_PROMPT)\n noCopyPrompt = true;\n noCopyPrompt = noCopyPrompt || this._options.noCopyPrompt;\n\n const builder = new HtmlBuilder(this.config, this._outputFolder, this._attachmentsBaseURL, {\n title: process.env.PLAYWRIGHT_HTML_TITLE || this._options.title,\n noSnippets,\n noCopyPrompt,\n });\n this._buildResult = await builder.build(this.config.metadata, projectSuites, result, this._topLevelErrors);\n }\n\n async onExit() {\n if (process.env.CI || !this._buildResult)\n return;\n const { ok, singleTestId } = this._buildResult;\n const shouldOpen = !!process.stdin.isTTY && (this._open === 'always' || (!ok && this._open === 'on-failure'));\n if (shouldOpen) {\n await showHTMLReport(this._outputFolder, this._host, this._port, singleTestId);\n } else if (this._options._mode === 'test' && !!process.stdin.isTTY) {\n const packageManagerCommand = getPackageManagerExecCommand();\n const relativeReportPath = this._outputFolder === standaloneDefaultFolder() ? '' : ' ' + path.relative(process.cwd(), this._outputFolder);\n const hostArg = this._host ? ` --host ${this._host}` : '';\n const portArg = this._port ? ` --port ${this._port}` : '';\n writeLine('');\n writeLine('To open last HTML report run:');\n writeLine(colors.cyan(`\n ${packageManagerCommand} playwright show-report${relativeReportPath}${hostArg}${portArg}\n`));\n }\n }\n}\n\nfunction reportFolderFromEnv(): string | undefined {\n // Note: PLAYWRIGHT_HTML_REPORT is for backwards compatibility.\n const envValue = process.env.PLAYWRIGHT_HTML_OUTPUT_DIR || process.env.PLAYWRIGHT_HTML_REPORT;\n return envValue ? path.resolve(envValue) : undefined;\n}\n\nfunction getHtmlReportOptionProcessEnv(): HtmlReportOpenOption | undefined {\n // Note: PW_TEST_HTML_REPORT_OPEN is for backwards compatibility.\n const htmlOpenEnv = process.env.PLAYWRIGHT_HTML_OPEN || process.env.PW_TEST_HTML_REPORT_OPEN;\n if (!htmlOpenEnv)\n return undefined;\n if (!isHtmlReportOption(htmlOpenEnv)) {\n writeLine(colors.red(`Configuration Error: HTML reporter Invalid value for PLAYWRIGHT_HTML_OPEN: ${htmlOpenEnv}. Valid values are: ${htmlReportOptions.join(', ')}`));\n return undefined;\n }\n return htmlOpenEnv;\n}\n\nfunction standaloneDefaultFolder(): string {\n return reportFolderFromEnv() ?? resolveReporterOutputPath('playwright-report', process.cwd(), undefined);\n}\n\nexport async function showHTMLReport(reportFolder: string | undefined, host: string = 'localhost', port?: number, testId?: string) {\n const folder = reportFolder ?? standaloneDefaultFolder();\n try {\n assert(fs.statSync(folder).isDirectory());\n } catch (e) {\n writeLine(colors.red(`No report found at \"${folder}\"`));\n gracefullyProcessExitDoNotHang(1);\n return;\n }\n const server = startHtmlReportServer(folder);\n await server.start({ port, host, preferredPort: port ? undefined : 9323 });\n let url = server.urlPrefix('human-readable');\n writeLine('');\n writeLine(colors.cyan(` Serving HTML report at ${url}. Press Ctrl+C to quit.`));\n if (testId)\n url += `#?testId=${testId}`;\n url = url.replace('0.0.0.0', 'localhost');\n await open(url, { wait: true }).catch(() => {});\n await new Promise(() => {});\n}\n\nexport function startHtmlReportServer(folder: string): HttpServer {\n const server = new HttpServer();\n server.routePrefix('/', (request, response) => {\n let relativePath = new URL('http://localhost' + request.url).pathname;\n if (relativePath.startsWith('/trace/file')) {\n const url = new URL('http://localhost' + request.url!);\n try {\n return server.serveFile(request, response, url.searchParams.get('path')!);\n } catch (e) {\n return false;\n }\n }\n if (relativePath === '/')\n relativePath = '/index.html';\n const absolutePath = path.join(folder, ...relativePath.split('/'));\n return server.serveFile(request, response, absolutePath);\n });\n return server;\n}\n\ntype DataMap = Map<string, { testFile: TestFile, testFileSummary: TestFileSummary }>;\n\nclass HtmlBuilder {\n private _config: api.FullConfig;\n private _reportFolder: string;\n private _stepsInFile = new MultiMap<string, TestStep>();\n private _dataZipFile: ZipFile;\n private _hasTraces = false;\n private _attachmentsBaseURL: string;\n private _options: HTMLReportOptions;\n\n constructor(config: api.FullConfig, outputDir: string, attachmentsBaseURL: string, options: HTMLReportOptions) {\n this._config = config;\n this._reportFolder = outputDir;\n this._options = options;\n fs.mkdirSync(this._reportFolder, { recursive: true });\n this._dataZipFile = new yazl.ZipFile();\n this._attachmentsBaseURL = attachmentsBaseURL;\n }\n\n async build(metadata: Metadata, projectSuites: api.Suite[], result: api.FullResult, topLevelErrors: api.TestError[]): Promise<{ ok: boolean, singleTestId: string | undefined }> {\n const data: DataMap = new Map();\n for (const projectSuite of projectSuites) {\n const projectName = projectSuite.project()!.name;\n for (const fileSuite of projectSuite.suites) {\n const fileName = this._relativeLocation(fileSuite.location)!.file;\n this._createEntryForSuite(data, projectName, fileSuite, fileName, true);\n }\n }\n if (!this._options.noSnippets)\n createSnippets(this._stepsInFile);\n\n let ok = true;\n for (const [fileId, { testFile, testFileSummary }] of data) {\n const stats = testFileSummary.stats;\n for (const test of testFileSummary.tests) {\n if (test.outcome === 'expected')\n ++stats.expected;\n if (test.outcome === 'skipped')\n ++stats.skipped;\n if (test.outcome === 'unexpected')\n ++stats.unexpected;\n if (test.outcome === 'flaky')\n ++stats.flaky;\n ++stats.total;\n }\n stats.ok = stats.unexpected + stats.flaky === 0;\n if (!stats.ok)\n ok = false;\n\n const testCaseSummaryComparator = (t1: TestCaseSummary, t2: TestCaseSummary) => {\n const w1 = (t1.outcome === 'unexpected' ? 1000 : 0) + (t1.outcome === 'flaky' ? 1 : 0);\n const w2 = (t2.outcome === 'unexpected' ? 1000 : 0) + (t2.outcome === 'flaky' ? 1 : 0);\n return w2 - w1;\n };\n testFileSummary.tests.sort(testCaseSummaryComparator);\n\n this._addDataFile(fileId + '.json', testFile);\n }\n const htmlReport: HTMLReport = {\n metadata,\n startTime: result.startTime.getTime(),\n duration: result.duration,\n files: [...data.values()].map(e => e.testFileSummary),\n projectNames: projectSuites.map(r => r.project()!.name),\n stats: { ...[...data.values()].reduce((a, e) => addStats(a, e.testFileSummary.stats), emptyStats()) },\n errors: topLevelErrors.map(error => formatError(internalScreen, error).message),\n options: this._options,\n };\n htmlReport.files.sort((f1, f2) => {\n const w1 = f1.stats.unexpected * 1000 + f1.stats.flaky;\n const w2 = f2.stats.unexpected * 1000 + f2.stats.flaky;\n return w2 - w1;\n });\n\n this._addDataFile('report.json', htmlReport);\n\n let singleTestId: string | undefined;\n if (htmlReport.stats.total === 1) {\n const testFile: TestFile = data.values().next().value!.testFile;\n singleTestId = testFile.tests[0].testId;\n }\n\n // Copy app.\n const appFolder = path.join(require.resolve('playwright-core'), '..', 'lib', 'vite', 'htmlReport');\n await copyFileAndMakeWritable(path.join(appFolder, 'index.html'), path.join(this._reportFolder, 'index.html'));\n\n // Copy trace viewer.\n if (this._hasTraces) {\n const traceViewerFolder = path.join(require.resolve('playwright-core'), '..', 'lib', 'vite', 'traceViewer');\n const traceViewerTargetFolder = path.join(this._reportFolder, 'trace');\n const traceViewerAssetsTargetFolder = path.join(traceViewerTargetFolder, 'assets');\n fs.mkdirSync(traceViewerAssetsTargetFolder, { recursive: true });\n for (const file of fs.readdirSync(traceViewerFolder)) {\n if (file.endsWith('.map') || file.includes('watch') || file.includes('assets'))\n continue;\n await copyFileAndMakeWritable(path.join(traceViewerFolder, file), path.join(traceViewerTargetFolder, file));\n }\n for (const file of fs.readdirSync(path.join(traceViewerFolder, 'assets'))) {\n if (file.endsWith('.map') || file.includes('xtermModule'))\n continue;\n await copyFileAndMakeWritable(path.join(traceViewerFolder, 'assets', file), path.join(traceViewerAssetsTargetFolder, file));\n }\n }\n\n await this._writeReportData(path.join(this._reportFolder, 'index.html'));\n\n\n return { ok, singleTestId };\n }\n\n private async _writeReportData(filePath: string) {\n fs.appendFileSync(filePath, '<script id=\"playwrightReportBase64\" type=\"application/zip\">data:application/zip;base64,');\n await new Promise(f => {\n this._dataZipFile!.end(undefined, () => {\n this._dataZipFile!.outputStream\n .pipe(new Base64Encoder())\n .pipe(fs.createWriteStream(filePath, { flags: 'a' })).on('close', f);\n });\n });\n fs.appendFileSync(filePath, '</script>');\n }\n\n private _addDataFile(fileName: string, data: any) {\n this._dataZipFile.addBuffer(Buffer.from(JSON.stringify(data)), fileName);\n }\n\n private _createEntryForSuite(data: DataMap, projectName: string, suite: api.Suite, fileName: string, deep: boolean) {\n const fileId = calculateSha1(fileName).slice(0, 20);\n let fileEntry = data.get(fileId);\n if (!fileEntry) {\n fileEntry = {\n testFile: { fileId, fileName, tests: [] },\n testFileSummary: { fileId, fileName, tests: [], stats: emptyStats() },\n };\n data.set(fileId, fileEntry);\n }\n\n const { testFile, testFileSummary } = fileEntry;\n const testEntries: TestEntry[] = [];\n this._processSuite(suite, projectName, [], deep, testEntries);\n for (const test of testEntries) {\n testFile.tests.push(test.testCase);\n testFileSummary.tests.push(test.testCaseSummary);\n }\n }\n\n private _processSuite(suite: api.Suite, projectName: string, path: string[], deep: boolean, outTests: TestEntry[]) {\n const newPath = [...path, suite.title];\n suite.entries().forEach(e => {\n if (e.type === 'test')\n outTests.push(this._createTestEntry(e, projectName, newPath));\n else if (deep)\n this._processSuite(e, projectName, newPath, deep, outTests);\n });\n }\n\n private _createTestEntry(test: api.TestCase, projectName: string, path: string[]): TestEntry {\n const duration = test.results.reduce((a, r) => a + r.duration, 0);\n const location = this._relativeLocation(test.location)!;\n path = path.slice(1).filter(path => path.length > 0);\n const results = test.results.map(r => this._createTestResult(test, r));\n\n return {\n testCase: {\n testId: test.id,\n title: test.title,\n projectName,\n location,\n duration,\n annotations: this._serializeAnnotations(test.annotations),\n tags: test.tags,\n outcome: test.outcome(),\n path,\n results,\n ok: test.outcome() === 'expected' || test.outcome() === 'flaky',\n },\n testCaseSummary: {\n testId: test.id,\n title: test.title,\n projectName,\n location,\n duration,\n annotations: this._serializeAnnotations(test.annotations),\n tags: test.tags,\n outcome: test.outcome(),\n path,\n ok: test.outcome() === 'expected' || test.outcome() === 'flaky',\n results: results.map(result => {\n return { attachments: result.attachments.map(a => ({ name: a.name, contentType: a.contentType, path: a.path })) };\n }),\n },\n };\n }\n\n private _serializeAttachments(attachments: JsonAttachment[]) {\n let lastAttachment: TestAttachment | undefined;\n return attachments.map(a => {\n if (a.name === 'trace')\n this._hasTraces = true;\n\n if ((a.name === 'stdout' || a.name === 'stderr') && a.contentType === 'text/plain') {\n if (lastAttachment &&\n lastAttachment.name === a.name &&\n lastAttachment.contentType === a.contentType) {\n lastAttachment.body += stripAnsiEscapes(a.body as string);\n return null;\n }\n a.body = stripAnsiEscapes(a.body as string);\n lastAttachment = a as TestAttachment;\n return a;\n }\n\n if (a.path) {\n let fileName = a.path;\n try {\n const buffer = fs.readFileSync(a.path);\n const sha1 = calculateSha1(buffer) + path.extname(a.path);\n fileName = this._attachmentsBaseURL + sha1;\n fs.mkdirSync(path.join(this._reportFolder, 'data'), { recursive: true });\n fs.writeFileSync(path.join(this._reportFolder, 'data', sha1), buffer);\n } catch (e) {\n }\n return {\n name: a.name,\n contentType: a.contentType,\n path: fileName,\n body: a.body,\n };\n }\n\n if (a.body instanceof Buffer) {\n if (isTextContentType(a.contentType)) {\n // Content type is like this: \"text/html; charset=UTF-8\"\n const charset = a.contentType.match(/charset=(.*)/)?.[1];\n try {\n const body = a.body.toString(charset as any || 'utf-8');\n return {\n name: a.name,\n contentType: a.contentType,\n body,\n };\n } catch (e) {\n // Invalid encoding, fall through and save to file.\n }\n }\n\n fs.mkdirSync(path.join(this._reportFolder, 'data'), { recursive: true });\n const extension = sanitizeForFilePath(path.extname(a.name).replace(/^\\./, '')) || mime.getExtension(a.contentType) || 'dat';\n const sha1 = calculateSha1(a.body) + '.' + extension;\n fs.writeFileSync(path.join(this._reportFolder, 'data', sha1), a.body);\n return {\n name: a.name,\n contentType: a.contentType,\n path: this._attachmentsBaseURL + sha1,\n };\n }\n\n // string\n return {\n name: a.name,\n contentType: a.contentType,\n body: a.body,\n };\n }).filter(Boolean) as TestAttachment[];\n }\n\n private _serializeAnnotations(annotations: api.TestCase['annotations']): TestAnnotation[] {\n // Annotations can be pushed directly, with a wrong type.\n return annotations.map(a => ({\n type: a.type,\n description: a.description === undefined ? undefined : String(a.description),\n location: a.location ? {\n file: a.location.file,\n line: a.location.line,\n column: a.location.column,\n } : undefined,\n }));\n }\n\n private _createTestResult(test: api.TestCase, result: api.TestResult): TestResult {\n return {\n duration: result.duration,\n startTime: result.startTime.toISOString(),\n retry: result.retry,\n steps: dedupeSteps(result.steps).map(s => this._createTestStep(s, result)),\n errors: formatResultFailure(internalScreen, test, result, '').map(error => {\n return {\n message: error.message,\n codeframe: error.location ? createErrorCodeframe(error.message, error.location) : undefined\n };\n }),\n status: result.status,\n annotations: this._serializeAnnotations(result.annotations),\n attachments: this._serializeAttachments([\n ...result.attachments,\n ...result.stdout.map(m => stdioAttachment(m, 'stdout')),\n ...result.stderr.map(m => stdioAttachment(m, 'stderr'))]),\n };\n }\n\n private _createTestStep(dedupedStep: DedupedStep, result: api.TestResult): TestStep {\n const { step, duration, count } = dedupedStep;\n const skipped = dedupedStep.step.annotations?.find(a => a.type === 'skip');\n let title = step.title;\n if (skipped)\n title = `${title} (skipped${skipped.description ? ': ' + skipped.description : ''})`;\n const testStep: TestStep = {\n title,\n startTime: step.startTime.toISOString(),\n duration,\n steps: dedupeSteps(step.steps).map(s => this._createTestStep(s, result)),\n attachments: step.attachments.map(s => {\n const index = result.attachments.indexOf(s);\n if (index === -1)\n throw new Error('Unexpected, attachment not found');\n return index;\n }),\n location: this._relativeLocation(step.location),\n error: step.error?.message,\n count,\n skipped: !!skipped,\n };\n if (step.location)\n this._stepsInFile.set(step.location.file, testStep);\n return testStep;\n }\n\n private _relativeLocation(location: api.Location | undefined): api.Location | undefined {\n if (!location)\n return undefined;\n const file = toPosixPath(path.relative(this._config.rootDir, location.file));\n return {\n file,\n line: location.line,\n column: location.column,\n };\n }\n}\n\nconst emptyStats = (): Stats => {\n return {\n total: 0,\n expected: 0,\n unexpected: 0,\n flaky: 0,\n skipped: 0,\n ok: true,\n };\n};\n\nconst addStats = (stats: Stats, delta: Stats): Stats => {\n stats.total += delta.total;\n stats.skipped += delta.skipped;\n stats.expected += delta.expected;\n stats.unexpected += delta.unexpected;\n stats.flaky += delta.flaky;\n stats.ok = stats.ok && delta.ok;\n return stats;\n};\n\nclass Base64Encoder extends Transform {\n private _remainder: Buffer | undefined;\n\n override _transform(chunk: any, encoding: BufferEncoding, callback: TransformCallback): void {\n if (this._remainder) {\n chunk = Buffer.concat([this._remainder, chunk]);\n this._remainder = undefined;\n }\n\n const remaining = chunk.length % 3;\n if (remaining) {\n this._remainder = chunk.slice(chunk.length - remaining);\n chunk = chunk.slice(0, chunk.length - remaining);\n }\n chunk = chunk.toString('base64');\n this.push(Buffer.from(chunk));\n callback();\n }\n\n override _flush(callback: TransformCallback): void {\n if (this._remainder)\n this.push(Buffer.from(this._remainder.toString('base64')));\n callback();\n }\n}\n\nfunction isTextContentType(contentType: string) {\n return contentType.startsWith('text/') || contentType.startsWith('application/json');\n}\n\ntype JsonAttachment = {\n name: string;\n body?: string | Buffer;\n path?: string;\n contentType: string;\n};\n\nfunction stdioAttachment(chunk: Buffer | string, type: 'stdout' | 'stderr'): JsonAttachment {\n return {\n name: type,\n contentType: 'text/plain',\n body: typeof chunk === 'string' ? chunk : chunk.toString('utf-8')\n };\n}\n\ntype DedupedStep = { step: api.TestStep, count: number, duration: number };\n\nfunction dedupeSteps(steps: api.TestStep[]) {\n const result: DedupedStep[] = [];\n let lastResult = undefined;\n for (const step of steps) {\n const canDedupe = !step.error && step.duration >= 0 && step.location?.file && !step.steps.length;\n const lastStep = lastResult?.step;\n if (canDedupe && lastResult && lastStep && step.category === lastStep.category && step.title === lastStep.title && step.location?.file === lastStep.location?.file && step.location?.line === lastStep.location?.line && step.location?.column === lastStep.location?.column) {\n ++lastResult.count;\n lastResult.duration += step.duration;\n continue;\n }\n lastResult = { step, count: 1, duration: step.duration };\n result.push(lastResult);\n if (!canDedupe)\n lastResult = undefined;\n }\n return result;\n}\n\nfunction createSnippets(stepsInFile: MultiMap<string, TestStep>) {\n for (const file of stepsInFile.keys()) {\n let source: string;\n try {\n source = fs.readFileSync(file, 'utf-8') + '\\n//';\n } catch (e) {\n continue;\n }\n const lines = source.split('\\n').length;\n const highlighted = codeFrameColumns(source, { start: { line: lines, column: 1 } }, { highlightCode: true, linesAbove: lines, linesBelow: 0 });\n const highlightedLines = highlighted.split('\\n');\n const lineWithArrow = highlightedLines[highlightedLines.length - 1];\n for (const step of stepsInFile.get(file)) {\n // Don't bother with snippets that have less than 3 lines.\n if (step.location!.line < 2 || step.location!.line >= lines)\n continue;\n // Cut out snippet.\n const snippetLines = highlightedLines.slice(step.location!.line - 2, step.location!.line + 1);\n // Relocate arrow.\n const index = lineWithArrow.indexOf('^');\n const shiftedArrow = lineWithArrow.slice(0, index) + ' '.repeat(step.location!.column - 1) + lineWithArrow.slice(index);\n // Insert arrow line.\n snippetLines.splice(2, 0, shiftedArrow);\n step.snippet = snippetLines.join('\\n');\n }\n }\n}\n\nfunction createErrorCodeframe(message: string, location: Location) {\n let source: string;\n try {\n source = fs.readFileSync(location.file, 'utf-8') + '\\n//';\n } catch (e) {\n return;\n }\n\n return codeFrameColumns(\n source,\n {\n start: {\n line: location.line,\n column: location.column,\n },\n },\n {\n highlightCode: false,\n linesAbove: 100,\n linesBelow: 100,\n message: stripAnsiEscapes(message).split('\\n')[0] || undefined,\n }\n );\n}\n\nfunction writeLine(line: string) {\n // eslint-disable-next-line no-restricted-properties\n process.stdout.write(line + '\\n');\n}\n\nexport default HtmlReporter;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_utils", "import_utilsBundle", "open", "path", "fs"]
|
|
7
|
+
}
|
|
@@ -66,6 +66,10 @@ class InternalReporter {
|
|
|
66
66
|
onStdErr(chunk, test, result) {
|
|
67
67
|
this._reporter.onStdErr?.(chunk, test, result);
|
|
68
68
|
}
|
|
69
|
+
async onTestPaused(test, result) {
|
|
70
|
+
this._addSnippetToTestErrors(test, result);
|
|
71
|
+
return await this._reporter.onTestPaused?.(test, result);
|
|
72
|
+
}
|
|
69
73
|
onTestEnd(test, result) {
|
|
70
74
|
this._addSnippetToTestErrors(test, result);
|
|
71
75
|
this._reporter.onTestEnd?.(test, result);
|
|
@@ -112,6 +116,8 @@ function addLocationAndSnippetToError(config, error, file) {
|
|
|
112
116
|
const location = error.location;
|
|
113
117
|
if (!location)
|
|
114
118
|
return;
|
|
119
|
+
if (!!error.snippet)
|
|
120
|
+
return;
|
|
115
121
|
try {
|
|
116
122
|
const tokens = [];
|
|
117
123
|
const source = import_fs.default.readFileSync(location.file, "utf8");
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/reporters/internalReporter.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs';\n\nimport { monotonicTime } from 'playwright-core/lib/utils';\n\nimport { internalScreen, prepareErrorStack, relativeFilePath } from './base';\nimport { Multiplexer } from './multiplexer';\nimport { Suite } from '../common/test';\nimport { codeFrameColumns } from '../transform/babelBundle';\nimport { wrapReporterAsV2 } from './reporterV2';\n\nimport type { AnyReporter, ReporterV2 } from './reporterV2';\nimport type { FullConfig, FullResult, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter';\n\n\nexport class InternalReporter implements ReporterV2 {\n private _reporter: ReporterV2;\n private _didBegin = false;\n private _config!: FullConfig;\n private _startTime: Date | undefined;\n private _monotonicStartTime: number | undefined;\n\n constructor(reporters: AnyReporter[]) {\n this._reporter = new Multiplexer(reporters.map(wrapReporterAsV2));\n }\n\n version(): 'v2' {\n return 'v2';\n }\n\n onConfigure(config: FullConfig) {\n this._config = config;\n this._startTime = new Date();\n this._monotonicStartTime = monotonicTime();\n this._reporter.onConfigure?.(config);\n }\n\n onBegin(suite: Suite) {\n this._didBegin = true;\n this._reporter.onBegin?.(suite);\n }\n\n onTestBegin(test: TestCase, result: TestResult) {\n this._reporter.onTestBegin?.(test, result);\n }\n\n onStdOut(chunk: string | Buffer, test?: TestCase, result?: TestResult) {\n this._reporter.onStdOut?.(chunk, test, result);\n }\n\n onStdErr(chunk: string | Buffer, test?: TestCase, result?: TestResult) {\n this._reporter.onStdErr?.(chunk, test, result);\n }\n\n onTestEnd(test: TestCase, result: TestResult) {\n this._addSnippetToTestErrors(test, result);\n this._reporter.onTestEnd?.(test, result);\n }\n\n async onEnd(result: { status: FullResult['status'] }) {\n if (!this._didBegin) {\n // onBegin was not reported, emit it.\n this.onBegin(new Suite('', 'root'));\n }\n return await this._reporter.onEnd?.({\n ...result,\n startTime: this._startTime!,\n duration: monotonicTime() - this._monotonicStartTime!,\n });\n }\n\n async onExit() {\n await this._reporter.onExit?.();\n }\n\n onError(error: TestError) {\n addLocationAndSnippetToError(this._config, error);\n this._reporter.onError?.(error);\n }\n\n onStepBegin(test: TestCase, result: TestResult, step: TestStep) {\n this._reporter.onStepBegin?.(test, result, step);\n }\n\n onStepEnd(test: TestCase, result: TestResult, step: TestStep) {\n this._addSnippetToStepError(test, step);\n this._reporter.onStepEnd?.(test, result, step);\n }\n\n printsToStdio() {\n return this._reporter.printsToStdio ? this._reporter.printsToStdio() : true;\n }\n\n private _addSnippetToTestErrors(test: TestCase, result: TestResult) {\n for (const error of result.errors)\n addLocationAndSnippetToError(this._config, error, test.location.file);\n }\n\n private _addSnippetToStepError(test: TestCase, step: TestStep) {\n if (step.error)\n addLocationAndSnippetToError(this._config, step.error, test.location.file);\n }\n}\n\nexport function addLocationAndSnippetToError(config: FullConfig, error: TestError, file?: string) {\n if (error.stack && !error.location)\n error.location = prepareErrorStack(error.stack).location;\n const location = error.location;\n if (!location)\n return;\n\n try {\n const tokens = [];\n const source = fs.readFileSync(location.file, 'utf8');\n const codeFrame = codeFrameColumns(source, { start: location }, { highlightCode: true });\n // Convert /var/folders to /private/var/folders on Mac.\n if (!file || fs.realpathSync(file) !== location.file) {\n tokens.push(internalScreen.colors.gray(` at `) + `${relativeFilePath(internalScreen, config, location.file)}:${location.line}`);\n tokens.push('');\n }\n tokens.push(codeFrame);\n error.snippet = tokens.join('\\n');\n } catch (e) {\n // Failed to read the source file - that's ok.\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["fs"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/reporters/json.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport { toPosixPath, MultiMap } from 'playwright-core/lib/utils';\n\nimport { formatError, nonTerminalScreen, prepareErrorStack, resolveOutputFile, CommonReporterOptions } from './base';\nimport { getProjectId } from '../common/config';\n\nimport type { ReporterV2 } from './reporterV2';\nimport type { JsonReporterOptions } from '../../types/test';\nimport type { FullConfig, FullResult, JSONReport, JSONReportError, JSONReportSpec, JSONReportSuite, JSONReportTest, JSONReportTestResult, JSONReportTestStep, Location, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter';\n\nclass JSONReporter implements ReporterV2 {\n config!: FullConfig;\n suite!: Suite;\n private _errors: TestError[] = [];\n private _resolvedOutputFile: string | undefined;\n\n constructor(options: JsonReporterOptions & CommonReporterOptions) {\n this._resolvedOutputFile = resolveOutputFile('JSON', options)?.outputFile;\n }\n\n version(): 'v2' {\n return 'v2';\n }\n\n printsToStdio() {\n return !this._resolvedOutputFile;\n }\n\n onConfigure(config: FullConfig) {\n this.config = config;\n }\n\n onBegin(suite: Suite) {\n this.suite = suite;\n }\n\n onError(error: TestError): void {\n this._errors.push(error);\n }\n\n async onEnd(result: FullResult) {\n await outputReport(this._serializeReport(result), this._resolvedOutputFile);\n }\n\n private _serializeReport(result: FullResult): JSONReport {\n const report: JSONReport = {\n config: {\n ...removePrivateFields(this.config),\n rootDir: toPosixPath(this.config.rootDir),\n projects: this.config.projects.map(project => {\n return {\n outputDir: toPosixPath(project.outputDir),\n repeatEach: project.repeatEach,\n retries: project.retries,\n metadata: project.metadata,\n id: getProjectId(project),\n name: project.name,\n testDir: toPosixPath(project.testDir),\n testIgnore: serializePatterns(project.testIgnore),\n testMatch: serializePatterns(project.testMatch),\n timeout: project.timeout,\n };\n })\n },\n suites: this._mergeSuites(this.suite.suites),\n errors: this._errors,\n stats: {\n startTime: result.startTime.toISOString(),\n duration: result.duration,\n expected: 0,\n skipped: 0,\n unexpected: 0,\n flaky: 0,\n },\n };\n for (const test of this.suite.allTests())\n ++report.stats[test.outcome()];\n return report;\n }\n\n private _mergeSuites(suites: Suite[]): JSONReportSuite[] {\n const fileSuites = new MultiMap<string, JSONReportSuite>();\n for (const projectSuite of suites) {\n const projectId = getProjectId(projectSuite.project()!);\n const projectName = projectSuite.project()!.name;\n for (const fileSuite of projectSuite.suites) {\n const file = fileSuite.location!.file;\n const serialized = this._serializeSuite(projectId, projectName, fileSuite);\n if (serialized)\n fileSuites.set(file, serialized);\n }\n }\n\n const results: JSONReportSuite[] = [];\n for (const [, suites] of fileSuites) {\n const result: JSONReportSuite = {\n title: suites[0].title,\n file: suites[0].file,\n column: 0,\n line: 0,\n specs: [],\n };\n for (const suite of suites)\n this._mergeTestsFromSuite(result, suite);\n results.push(result);\n }\n return results;\n }\n\n private _relativeLocation(location: Location | undefined): Location {\n if (!location)\n return { file: '', line: 0, column: 0 };\n return {\n file: toPosixPath(path.relative(this.config.rootDir, location.file)),\n line: location.line,\n column: location.column,\n };\n }\n\n private _locationMatches(s1: JSONReportSuite | JSONReportSpec, s2: JSONReportSuite | JSONReportSpec) {\n return s1.file === s2.file && s1.line === s2.line && s1.column === s2.column;\n }\n\n private _mergeTestsFromSuite(to: JSONReportSuite, from: JSONReportSuite) {\n for (const fromSuite of from.suites || []) {\n const toSuite = (to.suites || []).find(s => s.title === fromSuite.title && this._locationMatches(s, fromSuite));\n if (toSuite) {\n this._mergeTestsFromSuite(toSuite, fromSuite);\n } else {\n if (!to.suites)\n to.suites = [];\n to.suites.push(fromSuite);\n }\n }\n\n for (const spec of from.specs || []) {\n const toSpec = to.specs.find(s => s.title === spec.title && s.file === toPosixPath(path.relative(this.config.rootDir, spec.file)) && s.line === spec.line && s.column === spec.column);\n if (toSpec)\n toSpec.tests.push(...spec.tests);\n else\n to.specs.push(spec);\n }\n }\n\n private _serializeSuite(projectId: string, projectName: string, suite: Suite): null | JSONReportSuite {\n if (!suite.allTests().length)\n return null;\n const suites = suite.suites.map(suite => this._serializeSuite(projectId, projectName, suite)).filter(s => s) as JSONReportSuite[];\n return {\n title: suite.title,\n ...this._relativeLocation(suite.location),\n specs: suite.tests.map(test => this._serializeTestSpec(projectId, projectName, test)),\n suites: suites.length ? suites : undefined,\n };\n }\n\n private _serializeTestSpec(projectId: string, projectName: string, test: TestCase): JSONReportSpec {\n return {\n title: test.title,\n ok: test.ok(),\n tags: test.tags.map(tag => tag.substring(1)), // Strip '@'.\n tests: [this._serializeTest(projectId, projectName, test)],\n id: test.id,\n ...this._relativeLocation(test.location),\n };\n }\n\n private _serializeTest(projectId: string, projectName: string, test: TestCase): JSONReportTest {\n return {\n timeout: test.timeout,\n annotations: test.annotations,\n expectedStatus: test.expectedStatus,\n projectId,\n projectName,\n results: test.results.map(r => this._serializeTestResult(r, test)),\n status: test.outcome(),\n };\n }\n\n private _serializeTestResult(result: TestResult, test: TestCase): JSONReportTestResult {\n const steps = result.steps.filter(s => s.category === 'test.step');\n const jsonResult: JSONReportTestResult = {\n workerIndex: result.workerIndex,\n parallelIndex: result.parallelIndex,\n status: result.status,\n duration: result.duration,\n error: result.error,\n errors: result.errors.map(e => this._serializeError(e)),\n stdout: result.stdout.map(s => stdioEntry(s)),\n stderr: result.stderr.map(s => stdioEntry(s)),\n retry: result.retry,\n steps: steps.length ? steps.map(s => this._serializeTestStep(s)) : undefined,\n startTime: result.startTime.toISOString(),\n annotations: result.annotations,\n attachments: result.attachments.map(a => ({\n name: a.name,\n contentType: a.contentType,\n path: a.path,\n body: a.body?.toString('base64')\n })),\n };\n if (result.error?.stack)\n jsonResult.errorLocation = prepareErrorStack(result.error.stack).location;\n return jsonResult;\n }\n\n private _serializeError(error: TestError): JSONReportError {\n return formatError(nonTerminalScreen, error);\n }\n\n private _serializeTestStep(step: TestStep): JSONReportTestStep {\n const steps = step.steps.filter(s => s.category === 'test.step');\n return {\n title: step.title,\n duration: step.duration,\n error: step.error,\n steps: steps.length ? steps.map(s => this._serializeTestStep(s)) : undefined,\n };\n }\n}\n\nasync function outputReport(report: JSONReport, resolvedOutputFile: string | undefined) {\n const reportString = JSON.stringify(report, undefined, 2);\n if (resolvedOutputFile) {\n await fs.promises.mkdir(path.dirname(resolvedOutputFile), { recursive: true });\n await fs.promises.writeFile(resolvedOutputFile, reportString);\n } else {\n // eslint-disable-next-line no-console\n console.log(reportString);\n }\n}\n\nfunction stdioEntry(s: string | Buffer): any {\n if (typeof s === 'string')\n return { text: s };\n return { buffer: s.toString('base64') };\n}\n\nfunction removePrivateFields(config: FullConfig): FullConfig {\n return Object.fromEntries(Object.entries(config).filter(([name, value]) => !name.startsWith('_'))) as FullConfig;\n}\n\nexport function serializePatterns(patterns: string | RegExp | (string | RegExp)[]): string[] {\n if (!Array.isArray(patterns))\n patterns = [patterns];\n return patterns.map(s => s.toString());\n}\n\nexport default JSONReporter;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["suites", "path", "suite", "fs"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/reporters/junit.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport { getAsBooleanFromENV } from 'playwright-core/lib/utils';\n\nimport { CommonReporterOptions, formatFailure, nonTerminalScreen, resolveOutputFile } from './base';\nimport { stripAnsiEscapes } from '../util';\n\nimport type { ReporterV2 } from './reporterV2';\nimport type { JUnitReporterOptions } from '../../types/test';\nimport type { FullConfig, FullResult, Suite, TestCase } from '../../types/testReporter';\n\nclass JUnitReporter implements ReporterV2 {\n private config!: FullConfig;\n private configDir: string;\n private suite!: Suite;\n private timestamp!: Date;\n private totalTests = 0;\n private totalFailures = 0;\n private totalSkipped = 0;\n private resolvedOutputFile: string | undefined;\n private stripANSIControlSequences = false;\n private includeProjectInTestName = false;\n\n constructor(options: JUnitReporterOptions & CommonReporterOptions) {\n this.stripANSIControlSequences = getAsBooleanFromENV('PLAYWRIGHT_JUNIT_STRIP_ANSI', !!options.stripANSIControlSequences);\n this.includeProjectInTestName = getAsBooleanFromENV('PLAYWRIGHT_JUNIT_INCLUDE_PROJECT_IN_TEST_NAME', !!options.includeProjectInTestName);\n this.configDir = options.configDir;\n this.resolvedOutputFile = resolveOutputFile('JUNIT', options)?.outputFile;\n }\n\n version(): 'v2' {\n return 'v2';\n }\n\n printsToStdio() {\n return !this.resolvedOutputFile;\n }\n\n onConfigure(config: FullConfig) {\n this.config = config;\n }\n\n onBegin(suite: Suite) {\n this.suite = suite;\n this.timestamp = new Date();\n }\n\n async onEnd(result: FullResult) {\n const children: XMLEntry[] = [];\n for (const projectSuite of this.suite.suites) {\n for (const fileSuite of projectSuite.suites)\n children.push(await this._buildTestSuite(projectSuite.title, fileSuite));\n }\n const tokens: string[] = [];\n\n const self = this;\n const root: XMLEntry = {\n name: 'testsuites',\n attributes: {\n id: process.env[`PLAYWRIGHT_JUNIT_SUITE_ID`] || '',\n name: process.env[`PLAYWRIGHT_JUNIT_SUITE_NAME`] || '',\n tests: self.totalTests,\n failures: self.totalFailures,\n skipped: self.totalSkipped,\n errors: 0,\n time: result.duration / 1000\n },\n children\n };\n\n serializeXML(root, tokens, this.stripANSIControlSequences);\n const reportString = tokens.join('\\n');\n if (this.resolvedOutputFile) {\n await fs.promises.mkdir(path.dirname(this.resolvedOutputFile), { recursive: true });\n await fs.promises.writeFile(this.resolvedOutputFile, reportString);\n } else {\n // eslint-disable-next-line no-console\n console.log(reportString);\n }\n }\n\n private async _buildTestSuite(projectName: string, suite: Suite): Promise<XMLEntry> {\n let tests = 0;\n let skipped = 0;\n let failures = 0;\n let duration = 0;\n const children: XMLEntry[] = [];\n const testCaseNamePrefix = projectName && this.includeProjectInTestName ? `[${projectName}] ` : '';\n\n for (const test of suite.allTests()){\n ++tests;\n if (test.outcome() === 'skipped')\n ++skipped;\n if (!test.ok())\n ++failures;\n for (const result of test.results)\n duration += result.duration;\n await this._addTestCase(suite.title, testCaseNamePrefix, test, children);\n }\n\n this.totalTests += tests;\n this.totalSkipped += skipped;\n this.totalFailures += failures;\n\n const entry: XMLEntry = {\n name: 'testsuite',\n attributes: {\n name: suite.title,\n timestamp: this.timestamp.toISOString(),\n hostname: projectName,\n tests,\n failures,\n skipped,\n time: duration / 1000,\n errors: 0,\n },\n children\n };\n\n return entry;\n }\n\n private async _addTestCase(suiteName: string, namePrefix: string, test: TestCase, entries: XMLEntry[]) {\n const entry = {\n name: 'testcase',\n attributes: {\n // Skip root, project, file\n name: namePrefix + test.titlePath().slice(3).join(' \u203A '),\n // filename\n classname: suiteName,\n time: (test.results.reduce((acc, value) => acc + value.duration, 0)) / 1000\n\n },\n children: [] as XMLEntry[]\n };\n entries.push(entry);\n\n // Xray Test Management supports testcase level properties, where additional metadata may be provided\n // some annotations are encoded as value attributes, other as cdata content; this implementation supports\n // Xray JUnit extensions but it also agnostic, so other tools can also take advantage of this format\n const properties: XMLEntry = {\n name: 'properties',\n children: [] as XMLEntry[]\n };\n\n for (const annotation of test.annotations) {\n const property: XMLEntry = {\n name: 'property',\n attributes: {\n name: annotation.type,\n value: (annotation?.description ? annotation.description : '')\n }\n };\n properties.children?.push(property);\n }\n\n if (properties.children?.length)\n entry.children.push(properties);\n\n if (test.outcome() === 'skipped') {\n entry.children.push({ name: 'skipped' });\n return;\n }\n\n if (!test.ok()) {\n entry.children.push({\n name: 'failure',\n attributes: {\n message: `${path.basename(test.location.file)}:${test.location.line}:${test.location.column} ${test.title}`,\n type: 'FAILURE',\n },\n text: stripAnsiEscapes(formatFailure(nonTerminalScreen, this.config, test))\n });\n }\n\n const systemOut: string[] = [];\n const systemErr: string[] = [];\n for (const result of test.results) {\n for (const item of result.stdout)\n systemOut.push(item.toString());\n for (const item of result.stderr)\n systemErr.push(item.toString());\n for (const attachment of result.attachments) {\n if (!attachment.path)\n continue;\n\n let attachmentPath = path.relative(this.configDir, attachment.path);\n try {\n if (this.resolvedOutputFile)\n attachmentPath = path.relative(path.dirname(this.resolvedOutputFile), attachment.path);\n } catch {\n systemOut.push(`\\nWarning: Unable to make attachment path ${attachment.path} relative to report output file ${this.resolvedOutputFile}`);\n }\n\n try {\n await fs.promises.access(attachment.path);\n systemOut.push(`\\n[[ATTACHMENT|${attachmentPath}]]\\n`);\n } catch {\n systemErr.push(`\\nWarning: attachment ${attachmentPath} is missing`);\n }\n }\n }\n // Note: it is important to only produce a single system-out/system-err entry\n // so that parsers in the wild understand it.\n if (systemOut.length)\n entry.children.push({ name: 'system-out', text: systemOut.join('') });\n if (systemErr.length)\n entry.children.push({ name: 'system-err', text: systemErr.join('') });\n }\n}\n\ntype XMLEntry = {\n name: string;\n attributes?: { [name: string]: string | number | boolean };\n children?: XMLEntry[];\n text?: string;\n};\n\nfunction serializeXML(entry: XMLEntry, tokens: string[], stripANSIControlSequences: boolean) {\n const attrs: string[] = [];\n for (const [name, value] of Object.entries(entry.attributes || {}))\n attrs.push(`${name}=\"${escape(String(value), stripANSIControlSequences, false)}\"`);\n tokens.push(`<${entry.name}${attrs.length ? ' ' : ''}${attrs.join(' ')}>`);\n for (const child of entry.children || [])\n serializeXML(child, tokens, stripANSIControlSequences);\n if (entry.text)\n tokens.push(escape(entry.text, stripANSIControlSequences, true));\n tokens.push(`</${entry.name}>`);\n}\n\n// See https://en.wikipedia.org/wiki/Valid_characters_in_XML\nconst discouragedXMLCharacters = /[\\u0000-\\u0008\\u000b-\\u000c\\u000e-\\u001f\\u007f-\\u0084\\u0086-\\u009f]/g;\n\nfunction escape(text: string, stripANSIControlSequences: boolean, isCharacterData: boolean): string {\n if (stripANSIControlSequences)\n text = stripAnsiEscapes(text);\n\n if (isCharacterData) {\n text = '<![CDATA[' + text.replace(/]]>/g, ']]>') + ']]>';\n } else {\n const escapeRe = /[&\"'<>]/g;\n text = text.replace(escapeRe, c => ({ '&': '&', '\"': '"', \"'\": ''', '<': '<', '>': '>' }[c]!));\n }\n\n text = text.replace(discouragedXMLCharacters, '');\n return text;\n}\n\nexport default JUnitReporter;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["fs", "path"]
|
|
7
|
+
}
|
package/lib/reporters/line.js
CHANGED
|
@@ -74,6 +74,24 @@ class LineReporter extends import_base.TerminalReporter {
|
|
|
74
74
|
if (this.screen.isTTY && step.category === "test.step")
|
|
75
75
|
this._updateLine(test, result, step.parent);
|
|
76
76
|
}
|
|
77
|
+
async onTestPaused(test, result) {
|
|
78
|
+
if (!process.stdin.isTTY && !process.env.PW_TEST_DEBUG_REPORTERS)
|
|
79
|
+
return;
|
|
80
|
+
if (!process.env.PW_TEST_DEBUG_REPORTERS)
|
|
81
|
+
this.screen.stdout.write(`\x1B[1A\x1B[2K`);
|
|
82
|
+
if (test.outcome() === "unexpected") {
|
|
83
|
+
this.writeLine(this.screen.colors.red(this.formatTestHeader(test, { indent: " ", index: ++this._failures })));
|
|
84
|
+
this.writeLine(this.formatResultErrors(test, result));
|
|
85
|
+
(0, import_base.markErrorsAsReported)(result);
|
|
86
|
+
this.writeLine(this.screen.colors.yellow(` Paused on error. Press Ctrl+C to end.`) + "\n\n");
|
|
87
|
+
} else {
|
|
88
|
+
this.writeLine(this.screen.colors.yellow(this.formatTestHeader(test, { indent: " " })));
|
|
89
|
+
this.writeLine(this.screen.colors.yellow(` Paused at test end. Press Ctrl+C to end.`) + "\n\n");
|
|
90
|
+
}
|
|
91
|
+
this._updateLine(test, result, void 0);
|
|
92
|
+
await new Promise(() => {
|
|
93
|
+
});
|
|
94
|
+
}
|
|
77
95
|
onTestEnd(test, result) {
|
|
78
96
|
super.onTestEnd(test, result);
|
|
79
97
|
if (!this.willRetry(test) && (test.outcome() === "flaky" || test.outcome() === "unexpected" || result.status === "interrupted")) {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/reporters/line.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TerminalReporter } from './base';\n\nimport type { FullResult, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter';\n\nclass LineReporter extends TerminalReporter {\n private _current = 0;\n private _failures = 0;\n private _lastTest: TestCase | undefined;\n private _didBegin = false;\n\n override onBegin(suite: Suite) {\n super.onBegin(suite);\n const startingMessage = this.generateStartingMessage();\n if (startingMessage) {\n this.writeLine(startingMessage);\n this.writeLine();\n }\n this._didBegin = true;\n }\n\n override onStdOut(chunk: string | Buffer, test?: TestCase, result?: TestResult) {\n super.onStdOut(chunk, test, result);\n this._dumpToStdio(test, chunk, this.screen.stdout);\n }\n\n override onStdErr(chunk: string | Buffer, test?: TestCase, result?: TestResult) {\n super.onStdErr(chunk, test, result);\n this._dumpToStdio(test, chunk, this.screen.stderr);\n }\n\n private _dumpToStdio(test: TestCase | undefined, chunk: string | Buffer, stream: NodeJS.WriteStream) {\n if (this.config.quiet)\n return;\n if (!process.env.PW_TEST_DEBUG_REPORTERS)\n stream.write(`\\u001B[1A\\u001B[2K`);\n if (test && this._lastTest !== test) {\n // Write new header for the output.\n const title = this.screen.colors.dim(this.formatTestTitle(test));\n stream.write(this.fitToScreen(title) + `\\n`);\n this._lastTest = test;\n }\n\n stream.write(chunk);\n if (chunk[chunk.length - 1] !== '\\n')\n this.writeLine();\n\n this.writeLine();\n }\n\n onTestBegin(test: TestCase, result: TestResult) {\n ++this._current;\n this._updateLine(test, result, undefined);\n }\n\n onStepBegin(test: TestCase, result: TestResult, step: TestStep) {\n if (this.screen.isTTY && step.category === 'test.step')\n this._updateLine(test, result, step);\n }\n\n onStepEnd(test: TestCase, result: TestResult, step: TestStep) {\n if (this.screen.isTTY && step.category === 'test.step')\n this._updateLine(test, result, step.parent);\n }\n\n override onTestEnd(test: TestCase, result: TestResult) {\n super.onTestEnd(test, result);\n if (!this.willRetry(test) && (test.outcome() === 'flaky' || test.outcome() === 'unexpected' || result.status === 'interrupted')) {\n if (!process.env.PW_TEST_DEBUG_REPORTERS)\n this.screen.stdout.write(`\\u001B[1A\\u001B[2K`);\n this.writeLine(this.formatFailure(test, ++this._failures));\n this.writeLine();\n }\n }\n\n private _updateLine(test: TestCase, result: TestResult, step?: TestStep) {\n const retriesPrefix = this.totalTestCount < this._current ? ` (retries)` : ``;\n const prefix = `[${this._current}/${this.totalTestCount}]${retriesPrefix} `;\n const currentRetrySuffix = result.retry ? this.screen.colors.yellow(` (retry #${result.retry})`) : '';\n const title = this.formatTestTitle(test, step) + currentRetrySuffix;\n if (process.env.PW_TEST_DEBUG_REPORTERS)\n this.screen.stdout.write(`${prefix + title}\\n`);\n else\n this.screen.stdout.write(`\\u001B[1A\\u001B[2K${prefix + this.fitToScreen(title, prefix)}\\n`);\n }\n\n override onError(error: TestError): void {\n super.onError(error);\n\n const message = this.formatError(error).message + '\\n';\n if (!process.env.PW_TEST_DEBUG_REPORTERS && this._didBegin)\n this.screen.stdout.write(`\\u001B[1A\\u001B[2K`);\n this.screen.stdout.write(message);\n this.writeLine();\n }\n\n override async onEnd(result: FullResult) {\n if (!process.env.PW_TEST_DEBUG_REPORTERS && this._didBegin)\n this.screen.stdout.write(`\\u001B[1A\\u001B[2K`);\n await super.onEnd(result);\n this.epilogue(false);\n }\n}\n\nexport default LineReporter;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/lib/reporters/list.js
CHANGED
|
@@ -38,6 +38,7 @@ class ListReporter extends import_base.TerminalReporter {
|
|
|
38
38
|
this._resultIndex = /* @__PURE__ */ new Map();
|
|
39
39
|
this._stepIndex = /* @__PURE__ */ new Map();
|
|
40
40
|
this._needNewLine = false;
|
|
41
|
+
this._paused = /* @__PURE__ */ new Set();
|
|
41
42
|
this._printSteps = (0, import_utils.getAsBooleanFromENV)("PLAYWRIGHT_LIST_PRINT_STEPS", options?.printSteps);
|
|
42
43
|
}
|
|
43
44
|
onBegin(suite) {
|
|
@@ -144,8 +145,29 @@ class ListReporter extends import_base.TerminalReporter {
|
|
|
144
145
|
this._updateLineCountAndNewLineFlagForOutput(text);
|
|
145
146
|
stream.write(chunk);
|
|
146
147
|
}
|
|
148
|
+
async onTestPaused(test, result) {
|
|
149
|
+
if (!process.stdin.isTTY && !process.env.PW_TEST_DEBUG_REPORTERS)
|
|
150
|
+
return;
|
|
151
|
+
this._paused.add(result);
|
|
152
|
+
this._updateTestLine(test, result);
|
|
153
|
+
this._maybeWriteNewLine();
|
|
154
|
+
if (test.outcome() === "unexpected") {
|
|
155
|
+
const errors = this.formatResultErrors(test, result);
|
|
156
|
+
this.writeLine(errors);
|
|
157
|
+
this._updateLineCountAndNewLineFlagForOutput(errors);
|
|
158
|
+
(0, import_base.markErrorsAsReported)(result);
|
|
159
|
+
}
|
|
160
|
+
this._appendLine(this.screen.colors.yellow(`Paused ${test.outcome() === "unexpected" ? "on error" : "at test end"}. Press Ctrl+C to end.`), this._testPrefix("", ""));
|
|
161
|
+
await new Promise(() => {
|
|
162
|
+
});
|
|
163
|
+
}
|
|
147
164
|
onTestEnd(test, result) {
|
|
148
165
|
super.onTestEnd(test, result);
|
|
166
|
+
const wasPaused = this._paused.delete(result);
|
|
167
|
+
if (!wasPaused)
|
|
168
|
+
this._updateTestLine(test, result);
|
|
169
|
+
}
|
|
170
|
+
_updateTestLine(test, result) {
|
|
149
171
|
const title = this.formatTestTitle(test);
|
|
150
172
|
let prefix = "";
|
|
151
173
|
let text = "";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/reporters/list.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getAsBooleanFromENV } from 'playwright-core/lib/utils';\nimport { ms as milliseconds } from 'playwright-core/lib/utilsBundle';\n\nimport { TerminalReporter, stepSuffix } from './base';\nimport { stripAnsiEscapes } from '../util';\n\nimport type { ListReporterOptions } from '../../types/test';\nimport type { FullResult, Suite, TestCase, TestError, TestResult, TestStep } from '../../types/testReporter';\nimport type { CommonReporterOptions, TerminalReporterOptions } from './base';\n\n// Allow it in the Visual Studio Code Terminal and the new Windows Terminal\nconst DOES_NOT_SUPPORT_UTF8_IN_TERMINAL = process.platform === 'win32' && process.env.TERM_PROGRAM !== 'vscode' && !process.env.WT_SESSION;\nconst POSITIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? 'ok' : '\u2713';\nconst NEGATIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? 'x' : '\u2718';\n\nclass ListReporter extends TerminalReporter {\n private _lastRow = 0;\n private _lastColumn = 0;\n private _testRows = new Map<TestCase, number>();\n private _stepRows = new Map<TestStep, number>();\n private _resultIndex = new Map<TestResult, string>();\n private _stepIndex = new Map<TestStep, string>();\n private _needNewLine = false;\n private _printSteps: boolean;\n\n constructor(options?: ListReporterOptions & CommonReporterOptions & TerminalReporterOptions) {\n super(options);\n this._printSteps = getAsBooleanFromENV('PLAYWRIGHT_LIST_PRINT_STEPS', options?.printSteps);\n }\n\n override onBegin(suite: Suite) {\n super.onBegin(suite);\n const startingMessage = this.generateStartingMessage();\n if (startingMessage) {\n this.writeLine(startingMessage);\n this.writeLine('');\n }\n }\n\n onTestBegin(test: TestCase, result: TestResult) {\n const index = String(this._resultIndex.size + 1);\n this._resultIndex.set(result, index);\n\n if (!this.screen.isTTY)\n return;\n this._maybeWriteNewLine();\n this._testRows.set(test, this._lastRow);\n const prefix = this._testPrefix(index, '');\n const line = this.screen.colors.dim(this.formatTestTitle(test)) + this._retrySuffix(result);\n this._appendLine(line, prefix);\n }\n\n override onStdOut(chunk: string | Buffer, test?: TestCase, result?: TestResult) {\n super.onStdOut(chunk, test, result);\n this._dumpToStdio(test, chunk, this.screen.stdout, 'out');\n }\n\n override onStdErr(chunk: string | Buffer, test?: TestCase, result?: TestResult) {\n super.onStdErr(chunk, test, result);\n this._dumpToStdio(test, chunk, this.screen.stderr, 'err');\n }\n\n private getStepIndex(testIndex: string, result: TestResult, step: TestStep): string {\n if (this._stepIndex.has(step))\n return this._stepIndex.get(step)!;\n\n const ordinal = ((result as any)[lastStepOrdinalSymbol] || 0) + 1;\n (result as any)[lastStepOrdinalSymbol] = ordinal;\n const stepIndex = `${testIndex}.${ordinal}`;\n this._stepIndex.set(step, stepIndex);\n return stepIndex;\n }\n\n onStepBegin(test: TestCase, result: TestResult, step: TestStep) {\n if (step.category !== 'test.step')\n return;\n const testIndex = this._resultIndex.get(result) || '';\n\n if (!this.screen.isTTY)\n return;\n\n if (this._printSteps) {\n this._maybeWriteNewLine();\n this._stepRows.set(step, this._lastRow);\n const prefix = this._testPrefix(this.getStepIndex(testIndex, result, step), '');\n const line = test.title + this.screen.colors.dim(stepSuffix(step));\n this._appendLine(line, prefix);\n } else {\n this._updateOrAppendLine(this._testRows, test, this.screen.colors.dim(this.formatTestTitle(test, step)) + this._retrySuffix(result), this._testPrefix(testIndex, ''));\n }\n }\n\n onStepEnd(test: TestCase, result: TestResult, step: TestStep) {\n if (step.category !== 'test.step')\n return;\n\n const testIndex = this._resultIndex.get(result) || '';\n if (!this._printSteps) {\n if (this.screen.isTTY)\n this._updateOrAppendLine(this._testRows, test, this.screen.colors.dim(this.formatTestTitle(test, step.parent)) + this._retrySuffix(result), this._testPrefix(testIndex, ''));\n return;\n }\n\n const index = this.getStepIndex(testIndex, result, step);\n const title = this.screen.isTTY ? test.title + this.screen.colors.dim(stepSuffix(step)) : this.formatTestTitle(test, step);\n const prefix = this._testPrefix(index, '');\n let text = '';\n if (step.error)\n text = this.screen.colors.red(title);\n else\n text = title;\n text += this.screen.colors.dim(` (${milliseconds(step.duration)})`);\n\n this._updateOrAppendLine(this._stepRows, step, text, prefix);\n }\n\n private _maybeWriteNewLine() {\n if (this._needNewLine) {\n this._needNewLine = false;\n this.screen.stdout.write('\\n');\n ++this._lastRow;\n this._lastColumn = 0;\n }\n }\n\n private _updateLineCountAndNewLineFlagForOutput(text: string) {\n this._needNewLine = text[text.length - 1] !== '\\n';\n if (!this.screen.ttyWidth)\n return;\n for (const ch of text) {\n if (ch === '\\n') {\n this._lastColumn = 0;\n ++this._lastRow;\n continue;\n }\n ++this._lastColumn;\n if (this._lastColumn > this.screen.ttyWidth) {\n this._lastColumn = 0;\n ++this._lastRow;\n }\n }\n }\n\n private _dumpToStdio(test: TestCase | undefined, chunk: string | Buffer, stream: NodeJS.WriteStream, stdio: 'out' | 'err') {\n if (this.config.quiet)\n return;\n const text = chunk.toString('utf-8');\n this._updateLineCountAndNewLineFlagForOutput(text);\n stream.write(chunk);\n }\n\n override onTestEnd(test: TestCase, result: TestResult) {\n super.onTestEnd(test, result);\n\n const title = this.formatTestTitle(test);\n let prefix = '';\n let text = '';\n\n // In TTY mode test index is incremented in onTestStart\n // and in non-TTY mode it is incremented onTestEnd.\n let index = this._resultIndex.get(result);\n if (!index) {\n index = String(this._resultIndex.size + 1);\n this._resultIndex.set(result, index);\n }\n\n if (result.status === 'skipped') {\n prefix = this._testPrefix(index, this.screen.colors.green('-'));\n // Do not show duration for skipped.\n text = this.screen.colors.cyan(title) + this._retrySuffix(result);\n } else {\n const statusMark = result.status === 'passed' ? POSITIVE_STATUS_MARK : NEGATIVE_STATUS_MARK;\n if (result.status === test.expectedStatus) {\n prefix = this._testPrefix(index, this.screen.colors.green(statusMark));\n text = title;\n } else {\n prefix = this._testPrefix(index, this.screen.colors.red(statusMark));\n text = this.screen.colors.red(title);\n }\n text += this._retrySuffix(result) + this.screen.colors.dim(` (${milliseconds(result.duration)})`);\n }\n\n this._updateOrAppendLine(this._testRows, test, text, prefix);\n }\n\n private _updateOrAppendLine<T>(entityRowNumbers: Map<T, number>, entity: T, text: string, prefix: string) {\n const row = entityRowNumbers.get(entity);\n // Only update the line if we assume that the line is still on the screen\n if (row !== undefined && this.screen.isTTY && this._lastRow - row < this.screen.ttyHeight) {\n this._updateLine(row, text, prefix);\n } else {\n this._maybeWriteNewLine();\n entityRowNumbers.set(entity, this._lastRow);\n this._appendLine(text, prefix);\n }\n }\n\n private _appendLine(text: string, prefix: string) {\n const line = prefix + this.fitToScreen(text, prefix);\n if (process.env.PW_TEST_DEBUG_REPORTERS) {\n this.screen.stdout.write('#' + this._lastRow + ' : ' + line + '\\n');\n } else {\n this.screen.stdout.write(line);\n this.screen.stdout.write('\\n');\n }\n ++this._lastRow;\n this._lastColumn = 0;\n }\n\n private _updateLine(row: number, text: string, prefix: string) {\n const line = prefix + this.fitToScreen(text, prefix);\n if (process.env.PW_TEST_DEBUG_REPORTERS)\n this.screen.stdout.write('#' + row + ' : ' + line + '\\n');\n else\n this._updateLineForTTY(row, line);\n }\n\n private _updateLineForTTY(row: number, line: string) {\n // Go up if needed\n if (row !== this._lastRow)\n this.screen.stdout.write(`\\u001B[${this._lastRow - row}A`);\n // Erase line, go to the start\n this.screen.stdout.write('\\u001B[2K\\u001B[0G');\n this.screen.stdout.write(line);\n // Go down if needed.\n if (row !== this._lastRow)\n this.screen.stdout.write(`\\u001B[${this._lastRow - row}E`);\n }\n\n private _testPrefix(index: string, statusMark: string) {\n const statusMarkLength = stripAnsiEscapes(statusMark).length;\n const indexLength = Math.ceil(Math.log10(this.totalTestCount + 1));\n return ' ' + statusMark + ' '.repeat(3 - statusMarkLength) + this.screen.colors.dim(index.padStart(indexLength) + ' ');\n }\n\n private _retrySuffix(result: TestResult) {\n return (result.retry ? this.screen.colors.yellow(` (retry #${result.retry})`) : '');\n }\n\n override onError(error: TestError): void {\n super.onError(error);\n this._maybeWriteNewLine();\n const message = this.formatError(error).message + '\\n';\n this._updateLineCountAndNewLineFlagForOutput(message);\n this.screen.stdout.write(message);\n }\n\n override async onEnd(result: FullResult) {\n await super.onEnd(result);\n this.screen.stdout.write('\\n');\n this.epilogue(true);\n }\n}\n\nconst lastStepOrdinalSymbol = Symbol('lastStepOrdinal');\n\nexport default ListReporter;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["milliseconds"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/reporters/listModeReporter.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright Microsoft Corporation. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport path from 'path';\n\nimport { formatError, terminalScreen } from './base';\n\nimport type { FullConfig, TestError } from '../../types/testReporter';\nimport type { Suite } from '../common/test';\nimport type { TerminalScreen } from './base';\nimport type { ReporterV2 } from './reporterV2';\n\nclass ListModeReporter implements ReporterV2 {\n private config!: FullConfig;\n private screen: TerminalScreen;\n private _options: { screen?: TerminalScreen, includeTestId?: boolean };\n\n constructor(options: { screen?: TerminalScreen, includeTestId?: boolean } = {}) {\n this._options = options;\n this.screen = options?.screen ?? terminalScreen;\n }\n\n version(): 'v2' {\n return 'v2';\n }\n\n onConfigure(config: FullConfig) {\n this.config = config;\n }\n\n onBegin(suite: Suite): void {\n this._writeLine(`Listing tests:`);\n const tests = suite.allTests();\n const files = new Set<string>();\n for (const test of tests) {\n // root, project, file, ...describes, test\n const [, projectName, , ...titles] = test.titlePath();\n const location = `${path.relative(this.config.rootDir, test.location.file)}:${test.location.line}:${test.location.column}`;\n const testId = this._options.includeTestId ? `[id=${test.id}] ` : '';\n const projectLabel = this._options.includeTestId ? `project=` : '';\n const projectTitle = projectName ? `[${projectLabel}${projectName}] \u203A ` : '';\n this._writeLine(` ${testId}${projectTitle}${location} \u203A ${titles.join(' \u203A ')}`);\n files.add(test.location.file);\n }\n this._writeLine(`Total: ${tests.length} ${tests.length === 1 ? 'test' : 'tests'} in ${files.size} ${files.size === 1 ? 'file' : 'files'}`);\n }\n\n onError(error: TestError) {\n this.screen.stderr.write('\\n' + formatError(terminalScreen, error).message + '\\n');\n }\n\n private _writeLine(line: string) {\n this.screen.stdout.write(line + '\\n');\n }\n}\n\nexport default ListModeReporter;\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA,kBAAiB;AAEjB,kBAA4C;AAO5C,MAAM,iBAAuC;AAAA,EAK3C,YAAY,UAAgE,CAAC,GAAG;AAC9E,SAAK,WAAW;AAChB,SAAK,SAAS,SAAS,UAAU;AAAA,EACnC;AAAA,EAEA,UAAgB;AACd,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,QAAoB;AAC9B,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,QAAQ,OAAoB;AAC1B,SAAK,WAAW,gBAAgB;AAChC,UAAM,QAAQ,MAAM,SAAS;AAC7B,UAAM,QAAQ,oBAAI,IAAY;AAC9B,eAAW,QAAQ,OAAO;AAExB,YAAM,CAAC,EAAE,aAAa,EAAE,GAAG,MAAM,IAAI,KAAK,UAAU;AACpD,YAAM,WAAW,GAAG,YAAAA,QAAK,SAAS,KAAK,OAAO,SAAS,KAAK,SAAS,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,MAAM;AACxH,YAAM,SAAS,KAAK,SAAS,gBAAgB,OAAO,KAAK,EAAE,OAAO;AAClE,YAAM,eAAe,KAAK,SAAS,gBAAgB,aAAa;AAChE,YAAM,eAAe,cAAc,IAAI,YAAY,GAAG,WAAW,cAAS;AAC1E,WAAK,WAAW,KAAK,MAAM,GAAG,YAAY,GAAG,QAAQ,WAAM,OAAO,KAAK,UAAK,CAAC,EAAE;AAC/E,YAAM,IAAI,KAAK,SAAS,IAAI;AAAA,IAC9B;AACA,SAAK,WAAW,UAAU,MAAM,MAAM,IAAI,MAAM,WAAW,IAAI,SAAS,OAAO,OAAO,MAAM,IAAI,IAAI,MAAM,SAAS,IAAI,SAAS,OAAO,EAAE;AAAA,EAC3I;AAAA,EAEA,QAAQ,OAAkB;AACxB,SAAK,OAAO,OAAO,MAAM,WAAO,yBAAY,4BAAgB,KAAK,EAAE,UAAU,IAAI;AAAA,EACnF;AAAA,EAEQ,WAAW,MAAc;AAC/B,SAAK,OAAO,OAAO,MAAM,OAAO,IAAI;AAAA,EACtC;AACF;AAEA,IAAO,2BAAQ;",
|
|
6
|
+
"names": ["path"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/reporters/markdown.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport type { FullConfig, FullResult, Reporter, Suite, TestCase, TestError } from '@playwright/test/reporter';\n\ntype MarkdownReporterOptions = {\n configDir: string, // TODO: make it public?\n outputFile?: string;\n};\n\nclass MarkdownReporter implements Reporter {\n private _options: MarkdownReporterOptions;\n private _fatalErrors: TestError[] = [];\n protected _config!: FullConfig;\n private _suite!: Suite;\n\n constructor(options: MarkdownReporterOptions) {\n this._options = options;\n }\n\n printsToStdio() {\n return false;\n }\n\n onBegin(config: FullConfig, suite: Suite) {\n this._config = config;\n this._suite = suite;\n }\n\n onError(error: TestError) {\n this._fatalErrors.push(error);\n }\n\n async onEnd(result: FullResult) {\n const summary = this._generateSummary();\n const lines: string[] = [];\n if (this._fatalErrors.length)\n lines.push(`**${this._fatalErrors.length} fatal errors, not part of any test**`);\n if (summary.unexpected.length) {\n lines.push(`**${summary.unexpected.length} failed**`);\n this._printTestList(':x:', summary.unexpected, lines);\n }\n if (summary.flaky.length) {\n lines.push(`<details>`);\n lines.push(`<summary><b>${summary.flaky.length} flaky</b></summary>`);\n this._printTestList(':warning:', summary.flaky, lines, ' <br/>');\n lines.push(`</details>`);\n lines.push(``);\n }\n if (summary.interrupted.length) {\n lines.push(`<details>`);\n lines.push(`<summary><b>${summary.interrupted.length} interrupted</b></summary>`);\n this._printTestList(':warning:', summary.interrupted, lines, ' <br/>');\n lines.push(`</details>`);\n lines.push(``);\n }\n const skipped = summary.skipped ? `, ${summary.skipped} skipped` : '';\n const didNotRun = summary.didNotRun ? `, ${summary.didNotRun} did not run` : '';\n lines.push(`**${summary.expected} passed${skipped}${didNotRun}**`);\n lines.push(``);\n\n await this.publishReport(lines.join('\\n'));\n }\n\n protected async publishReport(report: string): Promise<void> {\n const maybeRelativeFile = this._options.outputFile || 'report.md';\n const reportFile = path.resolve(this._options.configDir, maybeRelativeFile);\n await fs.promises.mkdir(path.dirname(reportFile), { recursive: true });\n await fs.promises.writeFile(reportFile, report);\n }\n\n protected _generateSummary() {\n let didNotRun = 0;\n let skipped = 0;\n let expected = 0;\n const interrupted: TestCase[] = [];\n const interruptedToPrint: TestCase[] = [];\n const unexpected: TestCase[] = [];\n const flaky: TestCase[] = [];\n\n this._suite.allTests().forEach(test => {\n switch (test.outcome()) {\n case 'skipped': {\n if (test.results.some(result => result.status === 'interrupted')) {\n if (test.results.some(result => !!result.error))\n interruptedToPrint.push(test);\n interrupted.push(test);\n } else if (!test.results.length || test.expectedStatus !== 'skipped') {\n ++didNotRun;\n } else {\n ++skipped;\n }\n break;\n }\n case 'expected': ++expected; break;\n case 'unexpected': unexpected.push(test); break;\n case 'flaky': flaky.push(test); break;\n }\n });\n\n return {\n didNotRun,\n skipped,\n expected,\n interrupted,\n unexpected,\n flaky,\n };\n }\n\n private _printTestList(prefix: string, tests: TestCase[], lines: string[], suffix?: string) {\n for (const test of tests)\n lines.push(`${prefix} ${formatTestTitle(this._config.rootDir, test)}${suffix || ''}`);\n lines.push(``);\n }\n}\n\nfunction formatTestTitle(rootDir: string, test: TestCase): string {\n // root, project, file, ...describes, test\n const [, projectName, , ...titles] = test.titlePath();\n const relativeTestPath = path.relative(rootDir, test.location.file);\n // intentionally leave out column to prevent writing test.spec.ts:100:5 - GitHub turns that into \uD83D\uDCAF\n const location = `${relativeTestPath}:${test.location.line}`;\n const projectTitle = projectName ? `[${projectName}] \u203A ` : '';\n const testTitle = `${projectTitle}${location} \u203A ${titles.join(' \u203A ')}`;\n const extraTags = test.tags.filter(t => !testTitle.includes(t));\n const formattedTags = extraTags.map(t => `\\`${t}\\``).join(' ');\n return `${testTitle}${extraTags.length ? ' ' + formattedTags : ''}`;\n}\n\nexport default MarkdownReporter;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["path", "fs"]
|
|
7
|
+
}
|
package/lib/reporters/merge.js
CHANGED
|
@@ -55,10 +55,15 @@ async function createMergedReport(config, dir, reporterDescriptions, rootDirOver
|
|
|
55
55
|
throw new Error(`No report files found in ${dir}`);
|
|
56
56
|
const eventData = await mergeEvents(dir, shardFiles, stringPool, printStatus, rootDirOverride);
|
|
57
57
|
const pathSeparator = rootDirOverride ? import_path.default.sep : eventData.pathSeparatorFromMetadata ?? import_path.default.sep;
|
|
58
|
+
const pathPackage = pathSeparator === "/" ? import_path.default.posix : import_path.default.win32;
|
|
58
59
|
const receiver = new import_teleReceiver.TeleReporterReceiver(multiplexer, {
|
|
59
60
|
mergeProjects: false,
|
|
60
61
|
mergeTestCases: false,
|
|
61
|
-
|
|
62
|
+
// When merging on a different OS, an absolute path like `C:\foo\bar` from win may look like
|
|
63
|
+
// a relative path on posix, and vice versa.
|
|
64
|
+
// Therefore, we cannot use `path.resolve()` here - it will resolve relative-looking paths
|
|
65
|
+
// against `process.cwd()`, while we just want to normalize ".." and "." segments.
|
|
66
|
+
resolvePath: (rootDir, relativePath) => stringPool.internString(pathPackage.normalize(pathPackage.join(rootDir, relativePath))),
|
|
62
67
|
configOverrides: config.config
|
|
63
68
|
});
|
|
64
69
|
printStatus(`processing test events`);
|
|
@@ -72,7 +77,7 @@ async function createMergedReport(config, dir, reporterDescriptions, rootDirOver
|
|
|
72
77
|
}
|
|
73
78
|
};
|
|
74
79
|
await dispatchEvents(eventData.prologue);
|
|
75
|
-
for (const { reportFile, eventPatchers, metadata, tags } of eventData.reports) {
|
|
80
|
+
for (const { reportFile, eventPatchers, metadata, tags, startTime, duration } of eventData.reports) {
|
|
76
81
|
const reportJsonl = await import_fs.default.promises.readFile(reportFile);
|
|
77
82
|
const events = parseTestEvents(reportJsonl);
|
|
78
83
|
new import_stringInternPool.JsonStringInternalizer(stringPool).traverse(events);
|
|
@@ -83,6 +88,12 @@ async function createMergedReport(config, dir, reporterDescriptions, rootDirOver
|
|
|
83
88
|
eventPatchers.patchers.push(new GlobalErrorPatcher(tags.join(" ")));
|
|
84
89
|
eventPatchers.patchEvents(events);
|
|
85
90
|
await dispatchEvents(events);
|
|
91
|
+
multiplexer.onMachineEnd({
|
|
92
|
+
startTime: new Date(startTime),
|
|
93
|
+
duration,
|
|
94
|
+
tag: tags,
|
|
95
|
+
shardIndex: metadata.shard?.current
|
|
96
|
+
});
|
|
86
97
|
}
|
|
87
98
|
await dispatchEvents(eventData.epilogue);
|
|
88
99
|
}
|
|
@@ -181,6 +192,8 @@ async function mergeEvents(dir, shardReportFiles, stringPool, printStatus, rootD
|
|
|
181
192
|
eventPatchers.patchers.push(new PathSeparatorPatcher(metadata.pathSeparator));
|
|
182
193
|
eventPatchers.patchEvents(parsedEvents);
|
|
183
194
|
let tags = [];
|
|
195
|
+
let startTime = 0;
|
|
196
|
+
let duration = 0;
|
|
184
197
|
for (const event of parsedEvents) {
|
|
185
198
|
if (event.method === "onConfigure") {
|
|
186
199
|
configureEvents.push(event);
|
|
@@ -188,14 +201,18 @@ async function mergeEvents(dir, shardReportFiles, stringPool, printStatus, rootD
|
|
|
188
201
|
} else if (event.method === "onProject") {
|
|
189
202
|
projectEvents.push(event);
|
|
190
203
|
} else if (event.method === "onEnd") {
|
|
191
|
-
endEvents.push(event);
|
|
204
|
+
endEvents.push({ event, metadata, tags });
|
|
205
|
+
startTime = event.params.result.startTime;
|
|
206
|
+
duration = event.params.result.duration;
|
|
192
207
|
}
|
|
193
208
|
}
|
|
194
209
|
reports.push({
|
|
195
210
|
eventPatchers,
|
|
196
211
|
reportFile: localPath,
|
|
197
212
|
metadata,
|
|
198
|
-
tags
|
|
213
|
+
tags,
|
|
214
|
+
startTime,
|
|
215
|
+
duration
|
|
199
216
|
});
|
|
200
217
|
}
|
|
201
218
|
return {
|
|
@@ -270,8 +287,8 @@ function mergeConfigs(to, from) {
|
|
|
270
287
|
function mergeEndEvents(endEvents) {
|
|
271
288
|
let startTime = endEvents.length ? 1e13 : Date.now();
|
|
272
289
|
let status = "passed";
|
|
273
|
-
let
|
|
274
|
-
for (const event of endEvents) {
|
|
290
|
+
let endTime = 0;
|
|
291
|
+
for (const { event } of endEvents) {
|
|
275
292
|
const shardResult = event.params.result;
|
|
276
293
|
if (shardResult.status === "failed")
|
|
277
294
|
status = "failed";
|
|
@@ -280,12 +297,12 @@ function mergeEndEvents(endEvents) {
|
|
|
280
297
|
else if (shardResult.status === "interrupted" && status !== "failed" && status !== "timedout")
|
|
281
298
|
status = "interrupted";
|
|
282
299
|
startTime = Math.min(startTime, shardResult.startTime);
|
|
283
|
-
|
|
300
|
+
endTime = Math.max(endTime, shardResult.startTime + shardResult.duration);
|
|
284
301
|
}
|
|
285
302
|
const result = {
|
|
286
303
|
status,
|
|
287
304
|
startTime,
|
|
288
|
-
duration
|
|
305
|
+
duration: endTime - startTime
|
|
289
306
|
};
|
|
290
307
|
return {
|
|
291
308
|
method: "onEnd",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/reporters/merge.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs';\nimport path from 'path';\n\nimport { ZipFile } from 'playwright-core/lib/utils';\n\nimport { currentBlobReportVersion } from './blob';\nimport { Multiplexer } from './multiplexer';\nimport { JsonStringInternalizer, StringInternPool } from '../isomorphic/stringInternPool';\nimport { TeleReporterReceiver } from '../isomorphic/teleReceiver';\nimport { createReporters } from '../runner/reporters';\nimport { relativeFilePath } from '../util';\n\nimport type { ReporterDescription, TestAnnotation } from '../../types/test';\nimport type { TestError } from '../../types/testReporter';\nimport type { FullConfigInternal } from '../common/config';\nimport type { BlobReportMetadata, JsonAttachment, JsonConfig, JsonEvent, JsonFullResult, JsonLocation, JsonOnConfigureEvent, JsonOnEndEvent, JsonOnProjectEvent, JsonProject, JsonSuite, JsonTestCase } from '../isomorphic/teleReceiver';\nimport type * as blobV1 from './versions/blobV1';\n\ntype StatusCallback = (message: string) => void;\n\ntype ReportData = {\n eventPatchers: JsonEventPatchers;\n reportFile: string;\n metadata: BlobReportMetadata;\n tags: string[];\n};\n\nexport async function createMergedReport(config: FullConfigInternal, dir: string, reporterDescriptions: ReporterDescription[], rootDirOverride: string | undefined) {\n const reporters = await createReporters(config, 'merge', reporterDescriptions);\n const multiplexer = new Multiplexer(reporters);\n const stringPool = new StringInternPool();\n\n let printStatus: StatusCallback = () => {};\n if (!multiplexer.printsToStdio()) {\n printStatus = printStatusToStdout;\n printStatus(`merging reports from ${dir}`);\n }\n\n const shardFiles = await sortedShardFiles(dir);\n if (shardFiles.length === 0)\n throw new Error(`No report files found in ${dir}`);\n const eventData = await mergeEvents(dir, shardFiles, stringPool, printStatus, rootDirOverride);\n // If explicit config is provided, use platform path separator, otherwise use the one from the report (if any).\n const pathSeparator = rootDirOverride ? path.sep : (eventData.pathSeparatorFromMetadata ?? path.sep);\n const receiver = new TeleReporterReceiver(multiplexer, {\n mergeProjects: false,\n mergeTestCases: false,\n resolvePath: (rootDir, relativePath) => stringPool.internString(rootDir + pathSeparator + relativePath),\n configOverrides: config.config,\n });\n printStatus(`processing test events`);\n\n const dispatchEvents = async (events: JsonEvent[]) => {\n for (const event of events) {\n if (event.method === 'onEnd')\n printStatus(`building final report`);\n await receiver.dispatch(event);\n if (event.method === 'onEnd')\n printStatus(`finished building report`);\n }\n };\n\n await dispatchEvents(eventData.prologue);\n for (const { reportFile, eventPatchers, metadata, tags } of eventData.reports) {\n const reportJsonl = await fs.promises.readFile(reportFile);\n const events = parseTestEvents(reportJsonl);\n new JsonStringInternalizer(stringPool).traverse(events);\n eventPatchers.patchers.push(new AttachmentPathPatcher(dir));\n if (metadata.name)\n eventPatchers.patchers.push(new GlobalErrorPatcher(metadata.name));\n if (tags.length)\n eventPatchers.patchers.push(new GlobalErrorPatcher(tags.join(' ')));\n eventPatchers.patchEvents(events);\n await dispatchEvents(events);\n }\n await dispatchEvents(eventData.epilogue);\n}\n\nconst commonEventNames = ['onBlobReportMetadata', 'onConfigure', 'onProject', 'onBegin', 'onEnd'];\nconst commonEvents = new Set(commonEventNames);\nconst commonEventRegex = new RegExp(`${commonEventNames.join('|')}`);\n\nfunction parseCommonEvents(reportJsonl: Buffer): JsonEvent[] {\n return splitBufferLines(reportJsonl)\n .map(line => line.toString('utf8'))\n .filter(line => commonEventRegex.test(line)) // quick filter\n .map(line => JSON.parse(line) as JsonEvent)\n .filter(event => commonEvents.has(event.method));\n}\n\nfunction parseTestEvents(reportJsonl: Buffer): JsonEvent[] {\n return splitBufferLines(reportJsonl)\n .map(line => line.toString('utf8'))\n .filter(line => line.length)\n .map(line => JSON.parse(line) as JsonEvent)\n .filter(event => !commonEvents.has(event.method));\n}\n\nfunction splitBufferLines(buffer: Buffer) {\n const lines = [];\n let start = 0;\n while (start < buffer.length) {\n // 0x0A is the byte for '\\n'\n const end = buffer.indexOf(0x0A, start);\n if (end === -1) {\n lines.push(buffer.slice(start));\n break;\n }\n lines.push(buffer.slice(start, end));\n start = end + 1;\n }\n return lines;\n}\n\nasync function extractAndParseReports(dir: string, shardFiles: string[], internalizer: JsonStringInternalizer, printStatus: StatusCallback) {\n const shardEvents: { file: string, localPath: string, metadata: BlobReportMetadata, parsedEvents: JsonEvent[] }[] = [];\n await fs.promises.mkdir(path.join(dir, 'resources'), { recursive: true });\n\n const reportNames = new UniqueFileNameGenerator();\n for (const file of shardFiles) {\n const absolutePath = path.join(dir, file);\n printStatus(`extracting: ${relativeFilePath(absolutePath)}`);\n const zipFile = new ZipFile(absolutePath);\n const entryNames = await zipFile.entries();\n for (const entryName of entryNames.sort()) {\n let fileName = path.join(dir, entryName);\n const content = await zipFile.read(entryName);\n if (entryName.endsWith('.jsonl')) {\n fileName = reportNames.makeUnique(fileName);\n let parsedEvents = parseCommonEvents(content);\n // Passing reviver to JSON.parse doesn't work, as the original strings\n // keep being used. To work around that we traverse the parsed events\n // as a post-processing step.\n internalizer.traverse(parsedEvents);\n const metadata = findMetadata(parsedEvents, file);\n parsedEvents = modernizer.modernize(metadata.version, parsedEvents);\n shardEvents.push({\n file,\n localPath: fileName,\n metadata,\n parsedEvents\n });\n }\n await fs.promises.writeFile(fileName, content);\n }\n zipFile.close();\n }\n return shardEvents;\n}\n\nfunction findMetadata(events: JsonEvent[], file: string): BlobReportMetadata {\n if (events[0]?.method !== 'onBlobReportMetadata')\n throw new Error(`No metadata event found in ${file}`);\n const metadata = events[0].params;\n if (metadata.version > currentBlobReportVersion)\n throw new Error(`Blob report ${file} was created with a newer version of Playwright.`);\n return metadata;\n}\n\nasync function mergeEvents(dir: string, shardReportFiles: string[], stringPool: StringInternPool, printStatus: StatusCallback, rootDirOverride: string | undefined): Promise<{\n prologue: JsonEvent[];\n reports: ReportData[];\n epilogue: JsonEvent[];\n pathSeparatorFromMetadata?: string;\n}> {\n const internalizer = new JsonStringInternalizer(stringPool);\n\n const configureEvents: JsonOnConfigureEvent[] = [];\n const projectEvents: JsonOnProjectEvent[] = [];\n const endEvents: JsonOnEndEvent[] = [];\n\n const blobs = await extractAndParseReports(dir, shardReportFiles, internalizer, printStatus);\n // Sort by (report name; shard; file name), so that salt generation below is deterministic when:\n // - report names are unique;\n // - report names are missing;\n // - report names are clashing between shards.\n blobs.sort((a, b) => {\n const nameA = a.metadata.name ?? '';\n const nameB = b.metadata.name ?? '';\n if (nameA !== nameB)\n return nameA.localeCompare(nameB);\n const shardA = a.metadata.shard?.current ?? 0;\n const shardB = b.metadata.shard?.current ?? 0;\n if (shardA !== shardB)\n return shardA - shardB;\n return a.file.localeCompare(b.file);\n });\n\n printStatus(`merging events`);\n\n const reports: ReportData[] = [];\n const globalTestIdSet = new Set<string>();\n\n for (let i = 0; i < blobs.length; ++i) {\n // Generate unique salt for each blob.\n const { parsedEvents, metadata, localPath } = blobs[i];\n const eventPatchers = new JsonEventPatchers();\n eventPatchers.patchers.push(new IdsPatcher(\n stringPool,\n metadata.name,\n String(i),\n globalTestIdSet,\n ));\n // Only patch path separators if we are merging reports with explicit config.\n if (rootDirOverride)\n eventPatchers.patchers.push(new PathSeparatorPatcher(metadata.pathSeparator));\n eventPatchers.patchEvents(parsedEvents);\n\n let tags: string[] = [];\n for (const event of parsedEvents) {\n if (event.method === 'onConfigure') {\n configureEvents.push(event);\n tags = event.params.config.tags || [];\n } else if (event.method === 'onProject') {\n projectEvents.push(event);\n } else if (event.method === 'onEnd') {\n endEvents.push(event);\n }\n }\n\n // Save information about the reports to stream their test events later.\n reports.push({\n eventPatchers,\n reportFile: localPath,\n metadata,\n tags,\n });\n }\n\n return {\n prologue: [\n mergeConfigureEvents(configureEvents, rootDirOverride),\n ...projectEvents,\n { method: 'onBegin', params: undefined },\n ],\n reports,\n epilogue: [\n mergeEndEvents(endEvents),\n { method: 'onExit', params: undefined },\n ],\n pathSeparatorFromMetadata: blobs[0]?.metadata.pathSeparator,\n };\n}\n\nfunction mergeConfigureEvents(configureEvents: JsonOnConfigureEvent[], rootDirOverride: string | undefined): JsonEvent {\n if (!configureEvents.length)\n throw new Error('No configure events found');\n let config: JsonConfig = {\n configFile: undefined,\n globalTimeout: 0,\n maxFailures: 0,\n metadata: {\n },\n rootDir: '',\n version: '',\n workers: 0,\n globalSetup: null,\n globalTeardown: null,\n };\n for (const event of configureEvents)\n config = mergeConfigs(config, event.params.config);\n\n if (rootDirOverride) {\n config.rootDir = rootDirOverride;\n } else {\n const rootDirs = new Set(configureEvents.map(e => e.params.config.rootDir));\n if (rootDirs.size > 1) {\n throw new Error([\n `Blob reports being merged were recorded with different test directories, and`,\n `merging cannot proceed. This may happen if you are merging reports from`,\n `machines with different environments, like different operating systems or`,\n `if the tests ran with different playwright configs.`,\n ``,\n `You can force merge by specifying a merge config file with \"-c\" option. If`,\n `you'd like all test paths to be correct, make sure 'testDir' in the merge config`,\n `file points to the actual tests location.`,\n ``,\n `Found directories:`,\n ...rootDirs\n ].join('\\n'));\n }\n }\n\n return {\n method: 'onConfigure',\n params: {\n config,\n }\n };\n}\n\nfunction mergeConfigs(to: JsonConfig, from: JsonConfig): JsonConfig {\n return {\n ...to,\n ...from,\n metadata: {\n ...to.metadata,\n ...from.metadata,\n actualWorkers: (to.metadata.actualWorkers || 0) + (from.metadata.actualWorkers || 0),\n },\n workers: to.workers + from.workers,\n };\n}\n\nfunction mergeEndEvents(endEvents: JsonOnEndEvent[]): JsonEvent {\n let startTime = endEvents.length ? 10000000000000 : Date.now();\n let status: JsonFullResult['status'] = 'passed';\n let duration: number = 0;\n\n for (const event of endEvents) {\n const shardResult = event.params.result;\n if (shardResult.status === 'failed')\n status = 'failed';\n else if (shardResult.status === 'timedout' && status !== 'failed')\n status = 'timedout';\n else if (shardResult.status === 'interrupted' && status !== 'failed' && status !== 'timedout')\n status = 'interrupted';\n startTime = Math.min(startTime, shardResult.startTime);\n duration = Math.max(duration, shardResult.duration);\n }\n const result: JsonFullResult = {\n status,\n startTime,\n duration,\n };\n return {\n method: 'onEnd',\n params: {\n result\n }\n };\n}\n\nasync function sortedShardFiles(dir: string) {\n const files = await fs.promises.readdir(dir);\n return files.filter(file => file.endsWith('.zip')).sort();\n}\n\nfunction printStatusToStdout(message: string) {\n // eslint-disable-next-line no-restricted-properties\n process.stdout.write(`${message}\\n`);\n}\n\nclass UniqueFileNameGenerator {\n private _usedNames = new Set<string>();\n\n makeUnique(name: string): string {\n if (!this._usedNames.has(name)) {\n this._usedNames.add(name);\n return name;\n }\n const extension = path.extname(name);\n name = name.substring(0, name.length - extension.length);\n let index = 0;\n while (true) {\n const candidate = `${name}-${++index}${extension}`;\n if (!this._usedNames.has(candidate)) {\n this._usedNames.add(candidate);\n return candidate;\n }\n }\n }\n}\n\nclass IdsPatcher {\n private _stringPool: StringInternPool;\n private _botName: string | undefined;\n private _salt: string;\n private _testIdsMap: Map<string, string>;\n private _globalTestIdSet: Set<string>;\n\n constructor(\n stringPool: StringInternPool,\n botName: string | undefined,\n salt: string,\n globalTestIdSet: Set<string>,\n ) {\n this._stringPool = stringPool;\n this._botName = botName;\n this._salt = salt;\n this._testIdsMap = new Map();\n this._globalTestIdSet = globalTestIdSet;\n }\n\n patchEvent(event: JsonEvent) {\n const { method, params } = event;\n switch (method) {\n case 'onProject':\n this._onProject(params.project);\n return;\n case 'onAttach':\n case 'onTestBegin':\n case 'onStepBegin':\n case 'onStepEnd':\n case 'onStdIO':\n params.testId = params.testId ? this._mapTestId(params.testId) : undefined;\n return;\n case 'onTestEnd':\n params.test.testId = this._mapTestId(params.test.testId);\n return;\n }\n }\n\n private _onProject(project: JsonProject) {\n project.metadata ??= {};\n project.suites.forEach(suite => this._updateTestIds(suite));\n }\n\n private _updateTestIds(suite: JsonSuite) {\n suite.entries.forEach(entry => {\n if ('testId' in entry)\n this._updateTestId(entry);\n else\n this._updateTestIds(entry);\n });\n }\n\n private _updateTestId(test: JsonTestCase) {\n test.testId = this._mapTestId(test.testId);\n if (this._botName) {\n test.tags = test.tags || [];\n test.tags.unshift('@' + this._botName);\n }\n }\n\n private _mapTestId(testId: string): string {\n const t1 = this._stringPool.internString(testId);\n if (this._testIdsMap.has(t1))\n // already mapped\n return this._testIdsMap.get(t1)!;\n if (this._globalTestIdSet.has(t1)) {\n // test id is used in another blob, so we need to salt it.\n const t2 = this._stringPool.internString(testId + this._salt);\n this._globalTestIdSet.add(t2);\n this._testIdsMap.set(t1, t2);\n return t2;\n }\n this._globalTestIdSet.add(t1);\n this._testIdsMap.set(t1, t1);\n return t1;\n }\n}\n\nclass AttachmentPathPatcher {\n constructor(private _resourceDir: string) {\n }\n\n patchEvent(event: JsonEvent) {\n if (event.method === 'onAttach')\n this._patchAttachments(event.params.attachments);\n else if (event.method === 'onTestEnd')\n this._patchAttachments(event.params.result.attachments ?? []);\n }\n\n private _patchAttachments(attachments: JsonAttachment[]) {\n for (const attachment of attachments) {\n if (!attachment.path)\n continue;\n\n attachment.path = path.join(this._resourceDir, attachment.path);\n }\n }\n}\n\nclass PathSeparatorPatcher {\n private _from: string;\n private _to: string;\n constructor(from?: string) {\n this._from = from ?? (path.sep === '/' ? '\\\\' : '/');\n this._to = path.sep;\n }\n\n patchEvent(jsonEvent: JsonEvent) {\n if (this._from === this._to)\n return;\n if (jsonEvent.method === 'onProject') {\n this._updateProject(jsonEvent.params.project);\n return;\n }\n if (jsonEvent.method === 'onTestEnd') {\n const test = jsonEvent.params.test;\n test.annotations?.forEach(annotation => this._updateAnnotationLocation(annotation));\n const testResult = jsonEvent.params.result;\n testResult.annotations?.forEach(annotation => this._updateAnnotationLocation(annotation));\n testResult.errors.forEach(error => this._updateErrorLocations(error));\n (testResult.attachments ?? []).forEach(attachment => {\n if (attachment.path)\n attachment.path = this._updatePath(attachment.path);\n });\n return;\n }\n if (jsonEvent.method === 'onStepBegin') {\n const step = jsonEvent.params.step;\n this._updateLocation(step.location);\n return;\n }\n if (jsonEvent.method === 'onStepEnd') {\n const step = jsonEvent.params.step;\n this._updateErrorLocations(step.error);\n step.annotations?.forEach(annotation => this._updateAnnotationLocation(annotation));\n return;\n }\n if (jsonEvent.method === 'onAttach') {\n const attach = jsonEvent.params;\n attach.attachments.forEach(attachment => {\n if (attachment.path)\n attachment.path = this._updatePath(attachment.path);\n });\n return;\n }\n }\n\n private _updateProject(project: JsonProject) {\n project.outputDir = this._updatePath(project.outputDir);\n project.testDir = this._updatePath(project.testDir);\n project.snapshotDir = this._updatePath(project.snapshotDir);\n project.suites.forEach(suite => this._updateSuite(suite, true));\n }\n\n private _updateSuite(suite: JsonSuite, isFileSuite: boolean = false) {\n this._updateLocation(suite.location);\n if (isFileSuite)\n suite.title = this._updatePath(suite.title);\n for (const entry of suite.entries) {\n if ('testId' in entry) {\n this._updateLocation(entry.location);\n entry.annotations?.forEach(annotation => this._updateAnnotationLocation(annotation));\n } else {\n this._updateSuite(entry);\n }\n }\n }\n\n private _updateErrorLocations(error: TestError | undefined) {\n while (error) {\n this._updateLocation(error.location);\n error = error.cause;\n }\n }\n\n private _updateAnnotationLocation(annotation: TestAnnotation) {\n this._updateLocation(annotation.location);\n }\n\n private _updateLocation(location?: JsonLocation) {\n if (location)\n location.file = this._updatePath(location.file);\n }\n\n private _updatePath(text: string): string {\n return text.split(this._from).join(this._to);\n }\n}\n\nclass GlobalErrorPatcher {\n private _prefix: string;\n\n constructor(botName: string) {\n this._prefix = `(${botName}) `;\n }\n\n patchEvent(event: JsonEvent) {\n if (event.method !== 'onError')\n return;\n const error = event.params.error;\n if (error.message !== undefined)\n error.message = this._prefix + error.message;\n if (error.stack !== undefined)\n error.stack = this._prefix + error.stack;\n }\n}\n\ninterface JsonEventPatcher {\n patchEvent(event: JsonEvent): void;\n}\n\nclass JsonEventPatchers {\n readonly patchers: JsonEventPatcher[] = [];\n\n patchEvents(events: JsonEvent[]) {\n for (const event of events) {\n for (const patcher of this.patchers)\n patcher.patchEvent(event);\n }\n }\n}\n\nclass BlobModernizer {\n modernize(fromVersion: number, events: JsonEvent[]): JsonEvent[] {\n const result = [];\n for (const event of events)\n result.push(...this._modernize(fromVersion, event));\n return result;\n }\n\n private _modernize(fromVersion: number, event: JsonEvent): JsonEvent[] {\n let events = [event];\n for (let version = fromVersion; version < currentBlobReportVersion; ++version)\n events = (this as any)[`_modernize_${version}_to_${version + 1}`].call(this, events);\n return events;\n }\n\n _modernize_1_to_2(events: JsonEvent[]): JsonEvent[] {\n return events.map(event => {\n if (event.method === 'onProject') {\n const modernizeSuite = (suite: blobV1.JsonSuite): JsonSuite => {\n const newSuites = suite.suites.map(modernizeSuite);\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { suites, tests, ...remainder } = suite;\n return { entries: [...newSuites, ...tests], ...remainder };\n };\n const project = event.params.project;\n project.suites = (project.suites as unknown as blobV1.JsonSuite[]).map(modernizeSuite);\n }\n return event;\n });\n }\n}\n\nconst modernizer = new BlobModernizer();\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA,gBAAe;AACf,kBAAiB;AAEjB,mBAAwB;AAExB,kBAA0C;AAC1C,yBAA4B;AAC5B,8BAAyD;AACzD,0BAAqC;AACrC,uBAAgC;AAChC,kBAAiC;AAiBjC,eAAsB,mBAAmB,QAA4B,KAAa,sBAA6C,iBAAqC;AAClK,QAAM,YAAY,UAAM,kCAAgB,QAAQ,SAAS,oBAAoB;AAC7E,QAAM,cAAc,IAAI,+BAAY,SAAS;AAC7C,QAAM,aAAa,IAAI,yCAAiB;AAExC,MAAI,cAA8B,MAAM;AAAA,EAAC;AACzC,MAAI,CAAC,YAAY,cAAc,GAAG;AAChC,kBAAc;AACd,gBAAY,wBAAwB,GAAG,EAAE;AAAA,EAC3C;AAEA,QAAM,aAAa,MAAM,iBAAiB,GAAG;AAC7C,MAAI,WAAW,WAAW;AACxB,UAAM,IAAI,MAAM,4BAA4B,GAAG,EAAE;AACnD,QAAM,YAAY,MAAM,YAAY,KAAK,YAAY,YAAY,aAAa,eAAe;AAE7F,QAAM,gBAAgB,kBAAkB,YAAAA,QAAK,MAAO,UAAU,6BAA6B,YAAAA,QAAK;AAChG,QAAM,WAAW,IAAI,yCAAqB,aAAa;AAAA,IACrD,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,aAAa,CAAC,SAAS,iBAAiB,WAAW,aAAa,UAAU,gBAAgB,YAAY;AAAA,IACtG,iBAAiB,OAAO;AAAA,EAC1B,CAAC;AACD,cAAY,wBAAwB;AAEpC,QAAM,iBAAiB,OAAO,WAAwB;AACpD,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,WAAW;AACnB,oBAAY,uBAAuB;AACrC,YAAM,SAAS,SAAS,KAAK;AAC7B,UAAI,MAAM,WAAW;AACnB,oBAAY,0BAA0B;AAAA,IAC1C;AAAA,EACF;AAEA,QAAM,eAAe,UAAU,QAAQ;AACvC,aAAW,EAAE,YAAY,eAAe,UAAU,KAAK,KAAK,UAAU,SAAS;AAC7E,UAAM,cAAc,MAAM,UAAAC,QAAG,SAAS,SAAS,UAAU;AACzD,UAAM,SAAS,gBAAgB,WAAW;AAC1C,QAAI,+CAAuB,UAAU,EAAE,SAAS,MAAM;AACtD,kBAAc,SAAS,KAAK,IAAI,sBAAsB,GAAG,CAAC;AAC1D,QAAI,SAAS;AACX,oBAAc,SAAS,KAAK,IAAI,mBAAmB,SAAS,IAAI,CAAC;AACnE,QAAI,KAAK;AACP,oBAAc,SAAS,KAAK,IAAI,mBAAmB,KAAK,KAAK,GAAG,CAAC,CAAC;AACpE,kBAAc,YAAY,MAAM;AAChC,UAAM,eAAe,MAAM;AAAA,EAC7B;AACA,QAAM,eAAe,UAAU,QAAQ;AACzC;AAEA,MAAM,mBAAmB,CAAC,wBAAwB,eAAe,aAAa,WAAW,OAAO;AAChG,MAAM,eAAe,IAAI,IAAI,gBAAgB;AAC7C,MAAM,mBAAmB,IAAI,OAAO,GAAG,iBAAiB,KAAK,GAAG,CAAC,EAAE;AAEnE,SAAS,kBAAkB,aAAkC;AAC3D,SAAO,iBAAiB,WAAW,EAC9B,IAAI,UAAQ,KAAK,SAAS,MAAM,CAAC,EACjC,OAAO,UAAQ,iBAAiB,KAAK,IAAI,CAAC,EAC1C,IAAI,UAAQ,KAAK,MAAM,IAAI,CAAc,EACzC,OAAO,WAAS,aAAa,IAAI,MAAM,MAAM,CAAC;AACrD;AAEA,SAAS,gBAAgB,aAAkC;AACzD,SAAO,iBAAiB,WAAW,EAC9B,IAAI,UAAQ,KAAK,SAAS,MAAM,CAAC,EACjC,OAAO,UAAQ,KAAK,MAAM,EAC1B,IAAI,UAAQ,KAAK,MAAM,IAAI,CAAc,EACzC,OAAO,WAAS,CAAC,aAAa,IAAI,MAAM,MAAM,CAAC;AACtD;AAEA,SAAS,iBAAiB,QAAgB;AACxC,QAAM,QAAQ,CAAC;AACf,MAAI,QAAQ;AACZ,SAAO,QAAQ,OAAO,QAAQ;AAE5B,UAAM,MAAM,OAAO,QAAQ,IAAM,KAAK;AACtC,QAAI,QAAQ,IAAI;AACd,YAAM,KAAK,OAAO,MAAM,KAAK,CAAC;AAC9B;AAAA,IACF;AACA,UAAM,KAAK,OAAO,MAAM,OAAO,GAAG,CAAC;AACnC,YAAQ,MAAM;AAAA,EAChB;AACA,SAAO;AACT;AAEA,eAAe,uBAAuB,KAAa,YAAsB,cAAsC,aAA6B;AAC1I,QAAM,cAA8G,CAAC;AACrH,QAAM,UAAAA,QAAG,SAAS,MAAM,YAAAD,QAAK,KAAK,KAAK,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;AAExE,QAAM,cAAc,IAAI,wBAAwB;AAChD,aAAW,QAAQ,YAAY;AAC7B,UAAM,eAAe,YAAAA,QAAK,KAAK,KAAK,IAAI;AACxC,gBAAY,mBAAe,8BAAiB,YAAY,CAAC,EAAE;AAC3D,UAAM,UAAU,IAAI,qBAAQ,YAAY;AACxC,UAAM,aAAa,MAAM,QAAQ,QAAQ;AACzC,eAAW,aAAa,WAAW,KAAK,GAAG;AACzC,UAAI,WAAW,YAAAA,QAAK,KAAK,KAAK,SAAS;AACvC,YAAM,UAAU,MAAM,QAAQ,KAAK,SAAS;AAC5C,UAAI,UAAU,SAAS,QAAQ,GAAG;AAChC,mBAAW,YAAY,WAAW,QAAQ;AAC1C,YAAI,eAAe,kBAAkB,OAAO;AAI5C,qBAAa,SAAS,YAAY;AAClC,cAAM,WAAW,aAAa,cAAc,IAAI;AAChD,uBAAe,WAAW,UAAU,SAAS,SAAS,YAAY;AAClE,oBAAY,KAAK;AAAA,UACf;AAAA,UACA,WAAW;AAAA,UACX;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AACA,YAAM,UAAAC,QAAG,SAAS,UAAU,UAAU,OAAO;AAAA,IAC/C;AACA,YAAQ,MAAM;AAAA,EAChB;AACA,SAAO;AACT;AAEA,SAAS,aAAa,QAAqB,MAAkC;AAC3E,MAAI,OAAO,CAAC,GAAG,WAAW;AACxB,UAAM,IAAI,MAAM,8BAA8B,IAAI,EAAE;AACtD,QAAM,WAAW,OAAO,CAAC,EAAE;AAC3B,MAAI,SAAS,UAAU;AACrB,UAAM,IAAI,MAAM,eAAe,IAAI,kDAAkD;AACvF,SAAO;AACT;AAEA,eAAe,YAAY,KAAa,kBAA4B,YAA8B,aAA6B,iBAK5H;AACD,QAAM,eAAe,IAAI,+CAAuB,UAAU;AAE1D,QAAM,kBAA0C,CAAC;AACjD,QAAM,gBAAsC,CAAC;AAC7C,QAAM,YAA8B,CAAC;AAErC,QAAM,QAAQ,MAAM,uBAAuB,KAAK,kBAAkB,cAAc,WAAW;AAK3F,QAAM,KAAK,CAAC,GAAG,MAAM;AACnB,UAAM,QAAQ,EAAE,SAAS,QAAQ;AACjC,UAAM,QAAQ,EAAE,SAAS,QAAQ;AACjC,QAAI,UAAU;AACZ,aAAO,MAAM,cAAc,KAAK;AAClC,UAAM,SAAS,EAAE,SAAS,OAAO,WAAW;AAC5C,UAAM,SAAS,EAAE,SAAS,OAAO,WAAW;AAC5C,QAAI,WAAW;AACb,aAAO,SAAS;AAClB,WAAO,EAAE,KAAK,cAAc,EAAE,IAAI;AAAA,EACpC,CAAC;AAED,cAAY,gBAAgB;AAE5B,QAAM,UAAwB,CAAC;AAC/B,QAAM,kBAAkB,oBAAI,IAAY;AAExC,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,EAAE,GAAG;AAErC,UAAM,EAAE,cAAc,UAAU,UAAU,IAAI,MAAM,CAAC;AACrD,UAAM,gBAAgB,IAAI,kBAAkB;AAC5C,kBAAc,SAAS,KAAK,IAAI;AAAA,MAC5B;AAAA,MACA,SAAS;AAAA,MACT,OAAO,CAAC;AAAA,MACR;AAAA,IACJ,CAAC;AAED,QAAI;AACF,oBAAc,SAAS,KAAK,IAAI,qBAAqB,SAAS,aAAa,CAAC;AAC9E,kBAAc,YAAY,YAAY;AAEtC,QAAI,OAAiB,CAAC;AACtB,eAAW,SAAS,cAAc;AAChC,UAAI,MAAM,WAAW,eAAe;AAClC,wBAAgB,KAAK,KAAK;AAC1B,eAAO,MAAM,OAAO,OAAO,QAAQ,CAAC;AAAA,MACtC,WAAW,MAAM,WAAW,aAAa;AACvC,sBAAc,KAAK,KAAK;AAAA,MAC1B,WAAW,MAAM,WAAW,SAAS;AACnC,kBAAU,KAAK,KAAK;AAAA,MACtB;AAAA,IACF;AAGA,YAAQ,KAAK;AAAA,MACX;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,UAAU;AAAA,MACR,qBAAqB,iBAAiB,eAAe;AAAA,MACrD,GAAG;AAAA,MACH,EAAE,QAAQ,WAAW,QAAQ,OAAU;AAAA,IACzC;AAAA,IACA;AAAA,IACA,UAAU;AAAA,MACR,eAAe,SAAS;AAAA,MACxB,EAAE,QAAQ,UAAU,QAAQ,OAAU;AAAA,IACxC;AAAA,IACA,2BAA2B,MAAM,CAAC,GAAG,SAAS;AAAA,EAChD;AACF;AAEA,SAAS,qBAAqB,iBAAyC,iBAAgD;AACrH,MAAI,CAAC,gBAAgB;AACnB,UAAM,IAAI,MAAM,2BAA2B;AAC7C,MAAI,SAAqB;AAAA,IACvB,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,aAAa;AAAA,IACb,UAAU,CACV;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,aAAa;AAAA,IACb,gBAAgB;AAAA,EAClB;AACA,aAAW,SAAS;AAClB,aAAS,aAAa,QAAQ,MAAM,OAAO,MAAM;AAEnD,MAAI,iBAAiB;AACnB,WAAO,UAAU;AAAA,EACnB,OAAO;AACL,UAAM,WAAW,IAAI,IAAI,gBAAgB,IAAI,OAAK,EAAE,OAAO,OAAO,OAAO,CAAC;AAC1E,QAAI,SAAS,OAAO,GAAG;AACrB,YAAM,IAAI,MAAM;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,GAAG;AAAA,MACL,EAAE,KAAK,IAAI,CAAC;AAAA,IACd;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,aAAa,IAAgB,MAA8B;AAClE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG;AAAA,IACH,UAAU;AAAA,MACR,GAAG,GAAG;AAAA,MACN,GAAG,KAAK;AAAA,MACR,gBAAgB,GAAG,SAAS,iBAAiB,MAAM,KAAK,SAAS,iBAAiB;AAAA,IACpF;AAAA,IACA,SAAS,GAAG,UAAU,KAAK;AAAA,EAC7B;AACF;AAEA,SAAS,eAAe,WAAwC;AAC9D,MAAI,YAAY,UAAU,SAAS,OAAiB,KAAK,IAAI;AAC7D,MAAI,SAAmC;AACvC,MAAI,WAAmB;AAEvB,aAAW,SAAS,WAAW;AAC7B,UAAM,cAAc,MAAM,OAAO;AACjC,QAAI,YAAY,WAAW;AACzB,eAAS;AAAA,aACF,YAAY,WAAW,cAAc,WAAW;AACvD,eAAS;AAAA,aACF,YAAY,WAAW,iBAAiB,WAAW,YAAY,WAAW;AACjF,eAAS;AACX,gBAAY,KAAK,IAAI,WAAW,YAAY,SAAS;AACrD,eAAW,KAAK,IAAI,UAAU,YAAY,QAAQ;AAAA,EACpD;AACA,QAAM,SAAyB;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,iBAAiB,KAAa;AAC3C,QAAM,QAAQ,MAAM,UAAAA,QAAG,SAAS,QAAQ,GAAG;AAC3C,SAAO,MAAM,OAAO,UAAQ,KAAK,SAAS,MAAM,CAAC,EAAE,KAAK;AAC1D;AAEA,SAAS,oBAAoB,SAAiB;AAE5C,UAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AACrC;AAEA,MAAM,wBAAwB;AAAA,EAA9B;AACE,SAAQ,aAAa,oBAAI,IAAY;AAAA;AAAA,EAErC,WAAW,MAAsB;AAC/B,QAAI,CAAC,KAAK,WAAW,IAAI,IAAI,GAAG;AAC9B,WAAK,WAAW,IAAI,IAAI;AACxB,aAAO;AAAA,IACT;AACA,UAAM,YAAY,YAAAD,QAAK,QAAQ,IAAI;AACnC,WAAO,KAAK,UAAU,GAAG,KAAK,SAAS,UAAU,MAAM;AACvD,QAAI,QAAQ;AACZ,WAAO,MAAM;AACX,YAAM,YAAY,GAAG,IAAI,IAAI,EAAE,KAAK,GAAG,SAAS;AAChD,UAAI,CAAC,KAAK,WAAW,IAAI,SAAS,GAAG;AACnC,aAAK,WAAW,IAAI,SAAS;AAC7B,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;AAEA,MAAM,WAAW;AAAA,EAOf,YACE,YACA,SACA,MACA,iBACA;AACA,SAAK,cAAc;AACnB,SAAK,WAAW;AAChB,SAAK,QAAQ;AACb,SAAK,cAAc,oBAAI,IAAI;AAC3B,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEA,WAAW,OAAkB;AAC3B,UAAM,EAAE,QAAQ,OAAO,IAAI;AAC3B,YAAQ,QAAQ;AAAA,MACd,KAAK;AACH,aAAK,WAAW,OAAO,OAAO;AAC9B;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACH,eAAO,SAAS,OAAO,SAAS,KAAK,WAAW,OAAO,MAAM,IAAI;AACjE;AAAA,MACF,KAAK;AACH,eAAO,KAAK,SAAS,KAAK,WAAW,OAAO,KAAK,MAAM;AACvD;AAAA,IACJ;AAAA,EACF;AAAA,EAEQ,WAAW,SAAsB;AACvC,YAAQ,aAAa,CAAC;AACtB,YAAQ,OAAO,QAAQ,WAAS,KAAK,eAAe,KAAK,CAAC;AAAA,EAC5D;AAAA,EAEQ,eAAe,OAAkB;AACvC,UAAM,QAAQ,QAAQ,WAAS;AAC7B,UAAI,YAAY;AACd,aAAK,cAAc,KAAK;AAAA;AAExB,aAAK,eAAe,KAAK;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EAEQ,cAAc,MAAoB;AACxC,SAAK,SAAS,KAAK,WAAW,KAAK,MAAM;AACzC,QAAI,KAAK,UAAU;AACjB,WAAK,OAAO,KAAK,QAAQ,CAAC;AAC1B,WAAK,KAAK,QAAQ,MAAM,KAAK,QAAQ;AAAA,IACvC;AAAA,EACF;AAAA,EAEQ,WAAW,QAAwB;AACzC,UAAM,KAAK,KAAK,YAAY,aAAa,MAAM;AAC/C,QAAI,KAAK,YAAY,IAAI,EAAE;AAEzB,aAAO,KAAK,YAAY,IAAI,EAAE;AAChC,QAAI,KAAK,iBAAiB,IAAI,EAAE,GAAG;AAEjC,YAAM,KAAK,KAAK,YAAY,aAAa,SAAS,KAAK,KAAK;AAC5D,WAAK,iBAAiB,IAAI,EAAE;AAC5B,WAAK,YAAY,IAAI,IAAI,EAAE;AAC3B,aAAO;AAAA,IACT;AACA,SAAK,iBAAiB,IAAI,EAAE;AAC5B,SAAK,YAAY,IAAI,IAAI,EAAE;AAC3B,WAAO;AAAA,EACT;AACF;AAEA,MAAM,sBAAsB;AAAA,EAC1B,YAAoB,cAAsB;AAAtB;AAAA,EACpB;AAAA,EAEA,WAAW,OAAkB;AAC3B,QAAI,MAAM,WAAW;AACnB,WAAK,kBAAkB,MAAM,OAAO,WAAW;AAAA,aACxC,MAAM,WAAW;AACxB,WAAK,kBAAkB,MAAM,OAAO,OAAO,eAAe,CAAC,CAAC;AAAA,EAChE;AAAA,EAEQ,kBAAkB,aAA+B;AACvD,eAAW,cAAc,aAAa;AACpC,UAAI,CAAC,WAAW;AACd;AAEF,iBAAW,OAAO,YAAAA,QAAK,KAAK,KAAK,cAAc,WAAW,IAAI;AAAA,IAChE;AAAA,EACF;AACF;AAEA,MAAM,qBAAqB;AAAA,EAGzB,YAAY,MAAe;AACzB,SAAK,QAAQ,SAAS,YAAAA,QAAK,QAAQ,MAAM,OAAO;AAChD,SAAK,MAAM,YAAAA,QAAK;AAAA,EAClB;AAAA,EAEA,WAAW,WAAsB;AAC/B,QAAI,KAAK,UAAU,KAAK;AACtB;AACF,QAAI,UAAU,WAAW,aAAa;AACpC,WAAK,eAAe,UAAU,OAAO,OAAO;AAC5C;AAAA,IACF;AACA,QAAI,UAAU,WAAW,aAAa;AACpC,YAAM,OAAO,UAAU,OAAO;AAC9B,WAAK,aAAa,QAAQ,gBAAc,KAAK,0BAA0B,UAAU,CAAC;AAClF,YAAM,aAAa,UAAU,OAAO;AACpC,iBAAW,aAAa,QAAQ,gBAAc,KAAK,0BAA0B,UAAU,CAAC;AACxF,iBAAW,OAAO,QAAQ,WAAS,KAAK,sBAAsB,KAAK,CAAC;AACpE,OAAC,WAAW,eAAe,CAAC,GAAG,QAAQ,gBAAc;AACnD,YAAI,WAAW;AACb,qBAAW,OAAO,KAAK,YAAY,WAAW,IAAI;AAAA,MACtD,CAAC;AACD;AAAA,IACF;AACA,QAAI,UAAU,WAAW,eAAe;AACtC,YAAM,OAAO,UAAU,OAAO;AAC9B,WAAK,gBAAgB,KAAK,QAAQ;AAClC;AAAA,IACF;AACA,QAAI,UAAU,WAAW,aAAa;AACpC,YAAM,OAAO,UAAU,OAAO;AAC9B,WAAK,sBAAsB,KAAK,KAAK;AACrC,WAAK,aAAa,QAAQ,gBAAc,KAAK,0BAA0B,UAAU,CAAC;AAClF;AAAA,IACF;AACA,QAAI,UAAU,WAAW,YAAY;AACnC,YAAM,SAAS,UAAU;AACzB,aAAO,YAAY,QAAQ,gBAAc;AACvC,YAAI,WAAW;AACb,qBAAW,OAAO,KAAK,YAAY,WAAW,IAAI;AAAA,MACtD,CAAC;AACD;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,eAAe,SAAsB;AAC3C,YAAQ,YAAY,KAAK,YAAY,QAAQ,SAAS;AACtD,YAAQ,UAAU,KAAK,YAAY,QAAQ,OAAO;AAClD,YAAQ,cAAc,KAAK,YAAY,QAAQ,WAAW;AAC1D,YAAQ,OAAO,QAAQ,WAAS,KAAK,aAAa,OAAO,IAAI,CAAC;AAAA,EAChE;AAAA,EAEQ,aAAa,OAAkB,cAAuB,OAAO;AACnE,SAAK,gBAAgB,MAAM,QAAQ;AACnC,QAAI;AACF,YAAM,QAAQ,KAAK,YAAY,MAAM,KAAK;AAC5C,eAAW,SAAS,MAAM,SAAS;AACjC,UAAI,YAAY,OAAO;AACrB,aAAK,gBAAgB,MAAM,QAAQ;AACnC,cAAM,aAAa,QAAQ,gBAAc,KAAK,0BAA0B,UAAU,CAAC;AAAA,MACrF,OAAO;AACL,aAAK,aAAa,KAAK;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,sBAAsB,OAA8B;AAC1D,WAAO,OAAO;AACZ,WAAK,gBAAgB,MAAM,QAAQ;AACnC,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF;AAAA,EAEQ,0BAA0B,YAA4B;AAC5D,SAAK,gBAAgB,WAAW,QAAQ;AAAA,EAC1C;AAAA,EAEQ,gBAAgB,UAAyB;AAC/C,QAAI;AACF,eAAS,OAAO,KAAK,YAAY,SAAS,IAAI;AAAA,EAClD;AAAA,EAEQ,YAAY,MAAsB;AACxC,WAAO,KAAK,MAAM,KAAK,KAAK,EAAE,KAAK,KAAK,GAAG;AAAA,EAC7C;AACF;AAEA,MAAM,mBAAmB;AAAA,EAGvB,YAAY,SAAiB;AAC3B,SAAK,UAAU,IAAI,OAAO;AAAA,EAC5B;AAAA,EAEA,WAAW,OAAkB;AAC3B,QAAI,MAAM,WAAW;AACnB;AACF,UAAM,QAAQ,MAAM,OAAO;AAC3B,QAAI,MAAM,YAAY;AACpB,YAAM,UAAU,KAAK,UAAU,MAAM;AACvC,QAAI,MAAM,UAAU;AAClB,YAAM,QAAQ,KAAK,UAAU,MAAM;AAAA,EACvC;AACF;AAMA,MAAM,kBAAkB;AAAA,EAAxB;AACE,SAAS,WAA+B,CAAC;AAAA;AAAA,EAEzC,YAAY,QAAqB;AAC/B,eAAW,SAAS,QAAQ;AAC1B,iBAAW,WAAW,KAAK;AACzB,gBAAQ,WAAW,KAAK;AAAA,IAC5B;AAAA,EACF;AACF;AAEA,MAAM,eAAe;AAAA,EACnB,UAAU,aAAqB,QAAkC;AAC/D,UAAM,SAAS,CAAC;AAChB,eAAW,SAAS;AAClB,aAAO,KAAK,GAAG,KAAK,WAAW,aAAa,KAAK,CAAC;AACpD,WAAO;AAAA,EACT;AAAA,EAEQ,WAAW,aAAqB,OAA+B;AACrE,QAAI,SAAS,CAAC,KAAK;AACnB,aAAS,UAAU,aAAa,UAAU,sCAA0B,EAAE;AACpE,eAAU,KAAa,cAAc,OAAO,OAAO,UAAU,CAAC,EAAE,EAAE,KAAK,MAAM,MAAM;AACrF,WAAO;AAAA,EACT;AAAA,EAEA,kBAAkB,QAAkC;AAClD,WAAO,OAAO,IAAI,WAAS;AACzB,UAAI,MAAM,WAAW,aAAa;AAChC,cAAM,iBAAiB,CAAC,UAAuC;AAC7D,gBAAM,YAAY,MAAM,OAAO,IAAI,cAAc;AAEjD,gBAAM,EAAE,QAAQ,OAAO,GAAG,UAAU,IAAI;AACxC,iBAAO,EAAE,SAAS,CAAC,GAAG,WAAW,GAAG,KAAK,GAAG,GAAG,UAAU;AAAA,QAC3D;AACA,cAAM,UAAU,MAAM,OAAO;AAC7B,gBAAQ,SAAU,QAAQ,OAAyC,IAAI,cAAc;AAAA,MACvF;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;AAEA,MAAM,aAAa,IAAI,eAAe;",
|
|
6
|
+
"names": ["path", "fs"]
|
|
7
|
+
}
|