@arghajit/dummy 0.1.0-beta-25 → 0.1.0-beta-26
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.
package/README.md
CHANGED
|
@@ -7,53 +7,7 @@ _The ultimate Playwright reporter — Interactive dashboard with historical tren
|
|
|
7
7
|
|
|
8
8
|
## 
|
|
9
9
|
|
|
10
|
-
##
|
|
11
|
-
|
|
12
|
-
### 🖥️ Desktop View
|
|
13
|
-
|
|
14
|
-
<div align="center" style="display: flex; gap: 20px; justify-content: center; flex-wrap: wrap;">
|
|
15
|
-
<a href="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//playwright-pulse-static-report-desktop.html.png" target="_blank"> <img src="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//playwright-pulse-static-report-desktop.html.png" alt="Dashboard Overview" width="300"/>
|
|
16
|
-
<p align="center"><strong>Dashboard Overview</strong></p>
|
|
17
|
-
</a>
|
|
18
|
-
<a href="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//Test-run-desktop.png" target="_blank"> <img src="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//Test-run-desktop.png" alt="Test Details" width="300"/>
|
|
19
|
-
<p align="center"><strong>Test Details</strong>
|
|
20
|
-
</p>
|
|
21
|
-
</a>
|
|
22
|
-
<a href="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//Test-error-desktop.png" target="_blank"> <img src="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//Test-run-desktop.png" alt="Test Failure Details" width="300"/>
|
|
23
|
-
<p align="center"><strong>Test Failure Details</strong>
|
|
24
|
-
</p>
|
|
25
|
-
</a>
|
|
26
|
-
<a href="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//Test-trends-desktop.png" target="_blank"> <img src="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//Test-trends-desktop.png" alt="Filter View" width="300"/>
|
|
27
|
-
<p align="center"><strong>Test Trends</strong></p>
|
|
28
|
-
</a>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
### 📱 Mobile View
|
|
32
|
-
|
|
33
|
-
<div align="center" style="display: flex; gap: 20px; justify-content: center; flex-wrap: wrap;">
|
|
34
|
-
|
|
35
|
-
<a href="https://postimg.cc/CzJBLR5N" target="_blank">
|
|
36
|
-
<img src="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//playwright-pulse-static-report-Dashboard.html.png" alt="Mobile Dashboard Overview" width="300"/>
|
|
37
|
-
<p align="center"><strong>Dashboard Overview</strong></p>
|
|
38
|
-
</a>
|
|
39
|
-
|
|
40
|
-
<a href="https://postimg.cc/G8YTczT8" target="_blank">
|
|
41
|
-
<img src="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//playwright-pulse-static-report_Test-results.html.png" alt="Test Details" width="300"/>
|
|
42
|
-
<p align="center"><strong>Test Details</strong></p>
|
|
43
|
-
</a>
|
|
44
|
-
|
|
45
|
-
<a href="https://postimg.cc/G8YTczT8" target="_blank">
|
|
46
|
-
<img src="https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//playwright-pulse-static-report-Trends.html.png" alt="Test Trends" width="300"/>
|
|
47
|
-
<p align="center"><strong>Test Trends</strong></p>
|
|
48
|
-
</a>
|
|
49
|
-
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
### Email Report Example
|
|
53
|
-
|
|
54
|
-
[](https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//Email-report-mobile-template.jpeg)
|
|
55
|
-
|
|
56
|
-
[](https://ocpaxmghzmfbuhxzxzae.supabase.co/storage/v1/object/public/images//pulse-email-summary.html.png)
|
|
10
|
+
## **Documentation**: [Pulse Report](https://playwright-pulse-report.netlify.app/)
|
|
57
11
|
|
|
58
12
|
## Available Scripts
|
|
59
13
|
|
|
@@ -91,10 +45,6 @@ Run with `npm run <command>`
|
|
|
91
45
|
|
|
92
46
|
```bash
|
|
93
47
|
npm install @arghajit/playwright-pulse-report@latest --save-dev
|
|
94
|
-
# or
|
|
95
|
-
yarn add @arghajit/playwright-pulse-report@latest --dev
|
|
96
|
-
# or
|
|
97
|
-
pnpm add @arghajit/playwright-pulse-report@latest --save-dev
|
|
98
48
|
```
|
|
99
49
|
|
|
100
50
|
### 2. Configure Playwright
|
|
@@ -172,7 +122,7 @@ npx generate-report
|
|
|
172
122
|
npx send-email
|
|
173
123
|
```
|
|
174
124
|
|
|
175
|
-
NOTE:
|
|
125
|
+
NOTE: Email will be sent with a light-weight html file, which can be opened in mail preview application.
|
|
176
126
|
|
|
177
127
|
## 🤖 AI Analysis
|
|
178
128
|
|
|
@@ -274,6 +224,51 @@ The dashboard includes AI-powered test analysis that provides:
|
|
|
274
224
|
```bash
|
|
275
225
|
npm install @arghajit/playwright-pulse-report@latest
|
|
276
226
|
```
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## ⚙️ Advanced Configuration
|
|
230
|
+
|
|
231
|
+
### Handling Sequential Test Runs
|
|
232
|
+
|
|
233
|
+
By default, the reporter will overwrite the `playwright-pulse-report.json` file on each new test run. This is usually what we want. However, if we run tests sequentially in the same job, like this:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
npx playwright test test1.spec.ts && npx playwright test test2.spec.ts
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
By default, In this above scenario, the report from test1 will be lost. To solve this, you can use the resetOnEachRun option.
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
// playwright.config.ts
|
|
243
|
+
import { defineConfig } from "@playwright/test";
|
|
244
|
+
import * as path from "path";
|
|
245
|
+
|
|
246
|
+
// Define where the final report JSON and HTML should go
|
|
247
|
+
const PULSE_REPORT_DIR = path.resolve(__dirname, "pulse-report"); // Example: a directory in your project root
|
|
248
|
+
|
|
249
|
+
export default defineConfig({
|
|
250
|
+
reporter: [
|
|
251
|
+
["list"],
|
|
252
|
+
[
|
|
253
|
+
"@arghajit/playwright-pulse-report",
|
|
254
|
+
{
|
|
255
|
+
outputDir: PULSE_REPORT_DIR,
|
|
256
|
+
// Add this option
|
|
257
|
+
resetOnEachRun: false, // Default is true
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
],
|
|
261
|
+
// ...
|
|
262
|
+
});
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**How it works when resetOnEachRun: false:**
|
|
266
|
+
|
|
267
|
+
- On the first run, it saves report-1.json to a pulse-report/pulse-results directory and creates the main playwright-pulse-report.json from it.
|
|
268
|
+
- On the second run, it saves report-2.json to the same directory.
|
|
269
|
+
- It then automatically reads both report-1.json and report-2.json, merges them, and updates the main playwright-pulse-report.json with the combined results.
|
|
270
|
+
|
|
271
|
+
***This ensures your final report is always a complete summary of all sequential test runs.***
|
|
277
272
|
|
|
278
273
|
---
|
|
279
274
|
|
|
@@ -300,7 +295,7 @@ npm run pulse-dashboard
|
|
|
300
295
|
|
|
301
296
|
*(Run from project root containing `pulse-report/` directory)*
|
|
302
297
|
|
|
303
|
-
**NPM Package**: [pulse-
|
|
298
|
+
**NPM Package**: [playwright-pulse-report](https://www.npmjs.com/package/@arghajit/playwright-pulse-report)
|
|
304
299
|
|
|
305
300
|
**Tech Stack**: Next.js, TypeScript, Tailwind CSS, Playwright
|
|
306
301
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/typescript/lib/lib.es2022.d.ts","../../node_modules/typescript/lib/lib.es2023.d.ts","../../node_modules/typescript/lib/lib.es2024.d.ts","../../node_modules/typescript/lib/lib.esnext.d.ts","../../node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../node_modules/typescript/lib/lib.es2023.array.d.ts","../../node_modules/typescript/lib/lib.es2023.collection.d.ts","../../node_modules/typescript/lib/lib.es2023.intl.d.ts","../../node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2024.collection.d.ts","../../node_modules/typescript/lib/lib.es2024.object.d.ts","../../node_modules/typescript/lib/lib.es2024.promise.d.ts","../../node_modules/typescript/lib/lib.es2024.regexp.d.ts","../../node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2024.string.d.ts","../../node_modules/typescript/lib/lib.esnext.array.d.ts","../../node_modules/typescript/lib/lib.esnext.collection.d.ts","../../node_modules/typescript/lib/lib.esnext.intl.d.ts","../../node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../node_modules/typescript/lib/lib.esnext.decorators.d.ts","../../node_modules/typescript/lib/lib.esnext.iterator.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/playwright-core/types/protocol.d.ts","../../node_modules/playwright-core/types/structs.d.ts","../../node_modules/playwright-core/types/types.d.ts","../../node_modules/playwright/types/test.d.ts","../../node_modules/playwright/types/testreporter.d.ts","../../node_modules/@playwright/test/reporter.d.ts","../../node_modules/@types/react/global.d.ts","../../node_modules/csstype/index.d.ts","../../node_modules/@types/prop-types/index.d.ts","../../node_modules/@types/react/index.d.ts","../../node_modules/lucide-react/dist/lucide-react.d.ts","../../src/types/index.ts","../../src/lib/report-types.ts","../../src/reporter/playwright-pulse-reporter.ts","../../node_modules/@types/caseless/index.d.ts","../../node_modules/@types/d3-array/index.d.ts","../../node_modules/@types/d3-color/index.d.ts","../../node_modules/@types/d3-ease/index.d.ts","../../node_modules/@types/d3-interpolate/index.d.ts","../../node_modules/@types/d3-path/index.d.ts","../../node_modules/@types/d3-time/index.d.ts","../../node_modules/@types/d3-scale/index.d.ts","../../node_modules/@types/d3-shape/index.d.ts","../../node_modules/@types/d3-timer/index.d.ts","../../node_modules/@types/json-schema/index.d.ts","../../node_modules/@types/long/index.d.ts","../../node_modules/@types/node/compatibility/disposable.d.ts","../../node_modules/@types/node/compatibility/indexable.d.ts","../../node_modules/@types/node/compatibility/iterators.d.ts","../../node_modules/@types/node/compatibility/index.d.ts","../../node_modules/@types/node/globals.typedarray.d.ts","../../node_modules/@types/node/buffer.buffer.d.ts","../../node_modules/buffer/index.d.ts","../../node_modules/undici-types/header.d.ts","../../node_modules/undici-types/readable.d.ts","../../node_modules/undici-types/file.d.ts","../../node_modules/undici-types/fetch.d.ts","../../node_modules/undici-types/formdata.d.ts","../../node_modules/undici-types/connector.d.ts","../../node_modules/undici-types/client.d.ts","../../node_modules/undici-types/errors.d.ts","../../node_modules/undici-types/dispatcher.d.ts","../../node_modules/undici-types/global-dispatcher.d.ts","../../node_modules/undici-types/global-origin.d.ts","../../node_modules/undici-types/pool-stats.d.ts","../../node_modules/undici-types/pool.d.ts","../../node_modules/undici-types/handlers.d.ts","../../node_modules/undici-types/balanced-pool.d.ts","../../node_modules/undici-types/agent.d.ts","../../node_modules/undici-types/mock-interceptor.d.ts","../../node_modules/undici-types/mock-agent.d.ts","../../node_modules/undici-types/mock-client.d.ts","../../node_modules/undici-types/mock-pool.d.ts","../../node_modules/undici-types/mock-errors.d.ts","../../node_modules/undici-types/proxy-agent.d.ts","../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../node_modules/undici-types/retry-handler.d.ts","../../node_modules/undici-types/retry-agent.d.ts","../../node_modules/undici-types/api.d.ts","../../node_modules/undici-types/interceptors.d.ts","../../node_modules/undici-types/util.d.ts","../../node_modules/undici-types/cookies.d.ts","../../node_modules/undici-types/patch.d.ts","../../node_modules/undici-types/websocket.d.ts","../../node_modules/undici-types/eventsource.d.ts","../../node_modules/undici-types/filereader.d.ts","../../node_modules/undici-types/diagnostics-channel.d.ts","../../node_modules/undici-types/content-type.d.ts","../../node_modules/undici-types/cache.d.ts","../../node_modules/undici-types/index.d.ts","../../node_modules/@types/node/globals.d.ts","../../node_modules/@types/node/assert.d.ts","../../node_modules/@types/node/assert/strict.d.ts","../../node_modules/@types/node/async_hooks.d.ts","../../node_modules/@types/node/buffer.d.ts","../../node_modules/@types/node/child_process.d.ts","../../node_modules/@types/node/cluster.d.ts","../../node_modules/@types/node/console.d.ts","../../node_modules/@types/node/constants.d.ts","../../node_modules/@types/node/crypto.d.ts","../../node_modules/@types/node/dgram.d.ts","../../node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/@types/node/dns.d.ts","../../node_modules/@types/node/dns/promises.d.ts","../../node_modules/@types/node/domain.d.ts","../../node_modules/@types/node/dom-events.d.ts","../../node_modules/@types/node/events.d.ts","../../node_modules/@types/node/fs.d.ts","../../node_modules/@types/node/fs/promises.d.ts","../../node_modules/@types/node/http.d.ts","../../node_modules/@types/node/http2.d.ts","../../node_modules/@types/node/https.d.ts","../../node_modules/@types/node/inspector.d.ts","../../node_modules/@types/node/module.d.ts","../../node_modules/@types/node/net.d.ts","../../node_modules/@types/node/os.d.ts","../../node_modules/@types/node/path.d.ts","../../node_modules/@types/node/perf_hooks.d.ts","../../node_modules/@types/node/process.d.ts","../../node_modules/@types/node/punycode.d.ts","../../node_modules/@types/node/querystring.d.ts","../../node_modules/@types/node/readline.d.ts","../../node_modules/@types/node/readline/promises.d.ts","../../node_modules/@types/node/repl.d.ts","../../node_modules/@types/node/sea.d.ts","../../node_modules/@types/node/stream.d.ts","../../node_modules/@types/node/stream/promises.d.ts","../../node_modules/@types/node/stream/consumers.d.ts","../../node_modules/@types/node/stream/web.d.ts","../../node_modules/@types/node/string_decoder.d.ts","../../node_modules/@types/node/test.d.ts","../../node_modules/@types/node/timers.d.ts","../../node_modules/@types/node/timers/promises.d.ts","../../node_modules/@types/node/tls.d.ts","../../node_modules/@types/node/trace_events.d.ts","../../node_modules/@types/node/tty.d.ts","../../node_modules/@types/node/url.d.ts","../../node_modules/@types/node/util.d.ts","../../node_modules/@types/node/v8.d.ts","../../node_modules/@types/node/vm.d.ts","../../node_modules/@types/node/wasi.d.ts","../../node_modules/@types/node/worker_threads.d.ts","../../node_modules/@types/node/zlib.d.ts","../../node_modules/@types/node/index.d.ts","../../node_modules/@types/react-dom/index.d.ts","../../node_modules/@types/request/node_modules/form-data/index.d.ts","../../node_modules/@types/tough-cookie/index.d.ts","../../node_modules/@types/request/index.d.ts","../../node_modules/@types/shimmer/index.d.ts","../../node_modules/@types/triple-beam/index.d.ts","../../node_modules/@types/yauzl/index.d.ts"],"fileIdsList":[[83,110,153],[110,153],[95,110,153],[99,110,153],[98,110,153],[110,150,153],[110,152,153],[153],[110,153,158,187],[110,153,154,159,165,166,173,184,195],[110,153,154,155,165,173],[105,106,107,110,153],[110,153,156,196],[110,153,157,158,166,174],[110,153,158,184,192],[110,153,159,161,165,173],[110,152,153,160],[110,153,161,162],[110,153,165],[110,153,163,165],[110,152,153,165],[110,153,165,166,167,184,195],[110,153,165,166,167,180,184,187],[110,148,153,200],[110,153,161,165,168,173,184,195],[110,153,165,166,168,169,173,184,192,195],[110,153,168,170,184,192,195],[108,109,110,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201],[110,153,165,171],[110,153,172,195,200],[110,153,161,165,173,184],[110,153,174],[110,153,175],[110,152,153,176],[110,150,151,152,153,154,155,156,157,158,159,160,161,162,163,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201],[110,153,178],[110,153,179],[110,153,165,180,181],[110,153,180,182,196,198],[110,153,165,184,185,186,187],[110,153,184,186],[110,153,184,185],[110,153,187],[110,153,188],[110,150,153,184],[110,153,165,190,191],[110,153,190,191],[110,153,158,173,184,192],[110,153,193],[110,153,173,194],[110,153,168,179,195],[110,153,158,196],[110,153,184,197],[110,153,172,198],[110,153,199],[110,153,158,165,167,176,184,195,198,200],[110,153,184,201],[88,110,153],[85,86,87,110,153],[93,110,153,166,168,170,173,184,195,202,204,205],[110,153,168,184,202],[110,153,165,184,202],[81,110,153],[79,80,110,153,154,166,184],[82,110,153],[110,120,124,153,195],[110,120,153,184,195],[110,115,153],[110,117,120,153,192,195],[110,153,173,192],[110,153,202],[110,115,153,202],[110,117,120,153,173,195],[110,112,113,116,119,153,165,184,195],[110,120,127,153],[110,112,118,153],[110,120,141,142,153],[110,116,120,153,187,195,202],[110,141,153,202],[110,114,115,153,202],[110,120,153],[110,114,115,116,117,118,119,120,121,122,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,142,143,144,145,146,147,153],[110,120,135,153],[110,120,127,128,153],[110,118,120,128,129,153],[110,119,153],[110,112,115,120,153],[110,120,124,128,129,153],[110,124,153],[110,118,120,123,153,195],[110,112,117,120,127,153],[110,153,184],[110,115,120,141,153,200,202],[90,110,153],[84,90,91,110,153,167,175],[89,110,153]],"fileInfos":[{"version":"e41c290ef7dd7dab3493e6cbe5909e0148edf4a8dad0271be08edec368a0f7b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"8fd575e12870e9944c7e1d62e1f5a73fcf23dd8d3a321f2a2c74c20d022283fe","impliedFormat":1},{"version":"e12a46ce14b817d4c9e6b2b478956452330bf00c9801b79de46f7a1815b5bd40","impliedFormat":1},{"version":"4fd3f3422b2d2a3dfd5cdd0f387b3a8ec45f006c6ea896a4cb41264c2100bb2c","affectsGlobalScope":true,"impliedFormat":1},{"version":"69e65d976bf166ce4a9e6f6c18f94d2424bf116e90837ace179610dbccad9b42","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"62bb211266ee48b2d0edf0d8d1b191f0c24fc379a82bd4c1692a082c540bc6b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"936e80ad36a2ee83fc3caf008e7c4c5afe45b3cf3d5c24408f039c1d47bdc1df","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"fef8cfad2e2dc5f5b3d97a6f4f2e92848eb1b88e897bb7318cef0e2820bceaab","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"f1e2a172204962276504466a6393426d2ca9c54894b1ad0a6c9dad867a65f876","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"b5ce7a470bc3628408429040c4e3a53a27755022a32fd05e2cb694e7015386c7","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"bab26767638ab3557de12c900f0b91f710c7dc40ee9793d5a27d32c04f0bf646","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"87dc0f382502f5bbce5129bdc0aea21e19a3abbc19259e0b43ae038a9fc4e326","affectsGlobalScope":true,"impliedFormat":1},{"version":"b1cb28af0c891c8c96b2d6b7be76bd394fddcfdb4709a20ba05a7c1605eea0f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2fef54945a13095fdb9b84f705f2b5994597640c46afeb2ce78352fab4cb3279","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac77cb3e8c6d3565793eb90a8373ee8033146315a3dbead3bde8db5eaf5e5ec6","affectsGlobalScope":true,"impliedFormat":1},{"version":"56e4ed5aab5f5920980066a9409bfaf53e6d21d3f8d020c17e4de584d29600ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ece9f17b3866cc077099c73f4983bddbcb1dc7ddb943227f1ec070f529dedd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a6282c8827e4b9a95f4bf4f5c205673ada31b982f50572d27103df8ceb8013c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c9319a09485199c1f7b0498f2988d6d2249793ef67edda49d1e584746be9032","affectsGlobalScope":true,"impliedFormat":1},{"version":"e3a2a0cee0f03ffdde24d89660eba2685bfbdeae955a6c67e8c4c9fd28928eeb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4b1d2c51d058fc21ec2629fff7a76249dec2e36e12960ea056e3ef89174080f","affectsGlobalScope":true,"impliedFormat":1},{"version":"61d6a2092f48af66dbfb220e31eea8b10bc02b6932d6e529005fd2d7b3281290","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"0ef72620b8ed8555b1a571fba0573059b427c72c0f8fe0af12117c01deaa62aa","impliedFormat":1},{"version":"32727845ab5bd8a9ef3e4844c567c09f6d418fcf0f90d381c00652a6f23e7f6e","impliedFormat":1},{"version":"317522008ac4f9a976630cb65fd5b072d7aea6da0a93ec0cfe0c0b0336337ee2","impliedFormat":1},{"version":"e241a236efd22fd53f0cad74d812bece9bc1691bf3890e95705a6e3b73e2f98e","affectsGlobalScope":true,"impliedFormat":1},{"version":"d3cd566b0923109e83f1fe321c59266003ba22668d73195cf53e2eab3a71746f","impliedFormat":1},{"version":"04392f8e190f9e51301f73d17bbb34babd54858c1efc932d2193962f66dabae2","impliedFormat":1},{"version":"36a2e4c9a67439aca5f91bb304611d5ae6e20d420503e96c230cf8fcdc948d94","affectsGlobalScope":true,"impliedFormat":1},{"version":"8a8eb4ebffd85e589a1cc7c178e291626c359543403d58c9cd22b81fab5b1fb9","impliedFormat":1},{"version":"65ff5a0aefd7817a03c1ad04fee85c9cdd3ec415cc3c9efec85d8008d4d5e4ee","impliedFormat":1},{"version":"b89c2ddec6bd955e8721d41e24ca667de06882338d88b183c2cdc1f41f4c5a34","affectsGlobalScope":true,"impliedFormat":1},{"version":"6717dad91e44ad22d68f1fc0db74e5eb5398c2c06a2943bf06d3a168e8b1ba45","impliedFormat":99},{"version":"83aa54434d56363ddc949b3af4dd9eccd2fa9db2ecbae5c4a12b6984f66a630c","signature":"9f468e28df7bf40a346ac2cdd8b64e9f10cf2fbec522b58b92fef46b17c42720"},{"version":"331a971aff7a6da8693ab1ab38961996fecd854f6a639d430c81f8207dc92e96","signature":"14e0d6b6ab7688c7a2b60eb9c844d911175dd49a0e950b19863a5e09b8f9f6bd"},{"version":"c43cfd76af4b5b3dbe5d13d8f3e4ff975093fc952e444f1ad7d2263160c04b25","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"2174e20517788d2a1379fc0aaacd87899a70f9e0197b4295edabfe75c4db03d8","impliedFormat":1},{"version":"e0c868a08451c879984ccf4d4e3c1240b3be15af8988d230214977a3a3dad4ce","impliedFormat":1},{"version":"6fc1a4f64372593767a9b7b774e9b3b92bf04e8785c3f9ea98973aa9f4bbe490","impliedFormat":1},{"version":"ff09b6fbdcf74d8af4e131b8866925c5e18d225540b9b19ce9485ca93e574d84","impliedFormat":1},{"version":"d5895252efa27a50f134a9b580aa61f7def5ab73d0a8071f9b5bf9a317c01c2d","impliedFormat":1},{"version":"2c378d9368abcd2eba8c29b294d40909845f68557bc0b38117e4f04fc56e5f9c","impliedFormat":1},{"version":"56208c500dcb5f42be7e18e8cb578f257a1a89b94b3280c506818fed06391805","impliedFormat":1},{"version":"0c94c2e497e1b9bcfda66aea239d5d36cd980d12a6d9d59e66f4be1fa3da5d5a","impliedFormat":1},{"version":"bb220eaac1677e2ad82ac4e7fd3e609a0c7b6f2d6d9c673a35068c97f9fcd5cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"1f366bde16e0513fa7b64f87f86689c4d36efd85afce7eb24753e9c99b91c319","impliedFormat":1},{"version":"f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","impliedFormat":1},{"version":"0e60e0cbf2283adfd5a15430ae548cd2f662d581b5da6ecd98220203e7067c70","impliedFormat":1},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"a79e62f1e20467e11a904399b8b18b18c0c6eea6b50c1168bf215356d5bebfaf","affectsGlobalScope":true,"impliedFormat":1},{"version":"0fd06258805d26c72f5997e07a23155d322d5f05387adb3744a791fe6a0b042d","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"24bd580b5743dc56402c440dc7f9a4f5d592ad7a419f25414d37a7bfe11e342b","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"6bdc71028db658243775263e93a7db2fd2abfce3ca569c3cca5aee6ed5eb186d","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"4d2b0eb911816f66abe4970898f97a2cfc902bcd743cbfa5017fad79f7ef90d8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"e53a3c2a9f624d90f24bf4588aacd223e7bec1b9d0d479b68d2f4a9e6011147f","impliedFormat":1},{"version":"24b8685c62562f5d98615c5a0c1d05f297cf5065f15246edfe99e81ec4c0e011","impliedFormat":1},{"version":"93507c745e8f29090efb99399c3f77bec07db17acd75634249dc92f961573387","impliedFormat":1},{"version":"339dc5265ee5ed92e536a93a04c4ebbc2128f45eeec6ed29f379e0085283542c","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"08faa97886e71757779428dd4c69a545c32c85fd629d1116d42710b32c6378bc","affectsGlobalScope":true,"impliedFormat":1},{"version":"a72ffc815104fb5c075106ebca459b2d55d07862a773768fce89efc621b3964b","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"3d77c73be94570813f8cadd1f05ebc3dc5e2e4fdefe4d340ca20cd018724ee36","impliedFormat":1},{"version":"d674383111e06b6741c4ad2db962131b5b0fa4d0294b998566c635e86195a453","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3e58c4c18a031cbb17abec7a4ad0bd5ae9fc70c1f4ba1e7fb921ad87c504aca","impliedFormat":1},{"version":"a3e8bafb2af8e850c644f4be7f5156cf7d23b7bfdc3b786bd4d10ed40329649c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"a40826e8476694e90da94aa008283a7de50d1dafd37beada623863f1901cb7fb","impliedFormat":1},{"version":"f77d9188e41291acf14f476e931972460a303e1952538f9546e7b370cb8d0d20","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d04e3640dd9eb67f7f1e5bd3d0bf96c784666f7aefc8ac1537af6f2d38d4c29","impliedFormat":1},{"version":"3c884d9d9ec454bdf0d5a0b8465bf8297d2caa4d853851d92cc417ac6f30b969","impliedFormat":1},{"version":"5a369483ac4cfbdf0331c248deeb36140e6907db5e1daed241546b4a2055f82c","impliedFormat":1},{"version":"e8f5b5cc36615c17d330eaf8eebbc0d6bdd942c25991f96ef122f246f4ff722f","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"ee1ee365d88c4c6c0c0a5a5701d66ebc27ccd0bcfcfaa482c6e2e7fe7b98edf7","affectsGlobalScope":true,"impliedFormat":1},{"version":"0ada07543808f3b967624645a8e1ccd446f8b01ade47842acf1328aec899fed0","affectsGlobalScope":true,"impliedFormat":1},{"version":"c4a806152acbef81593f96cae6f2b04784d776457d97adbe2694478b243fcf03","impliedFormat":1},{"version":"71adf5dbc59568663d252a46179e71e4d544c053978bfc526d11543a3f716f42","impliedFormat":1},{"version":"c60db41f7bee80fb80c0b12819f5e465c8c8b465578da43e36d04f4a4646f57d","impliedFormat":1},{"version":"93bd413918fa921c8729cef45302b24d8b6c7855d72d5bf82d3972595ae8dcbf","impliedFormat":1},{"version":"4ff41188773cbf465807dd2f7059c7494cbee5115608efc297383832a1150c43","impliedFormat":1},{"version":"dccdf1677e531e33f8ac961a68bc537418c9a414797c1ea7e91307501cdc3f5e","impliedFormat":1},{"version":"e184c4b8918ef56c8c9e68bd79f3f3780e2d0d75bf2b8a41da1509a40c2deb46","affectsGlobalScope":true,"impliedFormat":1},{"version":"d206b4baf4ddcc15d9d69a9a2f4999a72a2c6adeaa8af20fa7a9960816287555","impliedFormat":1},{"version":"93f437e1398a4f06a984f441f7fa7a9f0535c04399619b5c22e0b87bdee182cb","impliedFormat":1},{"version":"afbe24ab0d74694372baa632ecb28bb375be53f3be53f9b07ecd7fc994907de5","impliedFormat":1},{"version":"70731d10d5311bd4cf710ef7f6539b62660f4b0bfdbb3f9fbe1d25fe6366a7fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"6b19db3600a17af69d4f33d08cc7076a7d19fb65bb36e442cac58929ec7c9482","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"137c2894e8f3e9672d401cc0a305dc7b1db7c69511cf6d3970fb53302f9eae09","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"8145e07aad6da5f23f2fcd8c8e4c5c13fb26ee986a79d03b0829b8fce152d8b2","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"235bfb54b4869c26f7e98e3d1f68dbfc85acf4cf5c38a4444a006fbf74a8a43d","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"93452d394fdd1dc551ec62f5042366f011a00d342d36d50793b3529bfc9bd633","impliedFormat":1},{"version":"bb715efb4857eb94539eafb420352105a0cff40746837c5140bf6b035dd220ba","affectsGlobalScope":true,"impliedFormat":1},{"version":"1851a3b4db78664f83901bb9cac9e45e03a37bb5933cc5bf37e10bb7e91ab4eb","impliedFormat":1},{"version":"fdedf82878e4c744bc2a1c1e802ae407d63474da51f14a54babe039018e53d8f","affectsGlobalScope":true,"impliedFormat":1},{"version":"27d8987fd22d92efe6560cf0ce11767bf089903ffe26047727debfd1f3bf438b","affectsGlobalScope":true,"impliedFormat":1},{"version":"578d8bb6dcb2a1c03c4c3f8eb71abc9677e1a5c788b7f24848e3138ce17f3400","impliedFormat":1},{"version":"4f029899f9bae07e225c43aef893590541b2b43267383bf5e32e3a884d219ed5","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"5b566927cad2ed2139655d55d690ffa87df378b956e7fe1c96024c4d9f75c4cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"bce947017cb7a2deebcc4f5ba04cead891ce6ad1602a4438ae45ed9aa1f39104","affectsGlobalScope":true,"impliedFormat":1},{"version":"d3dffd70e6375b872f0b4e152de4ae682d762c61a24881ecc5eb9f04c5caf76f","impliedFormat":1},{"version":"e2c72c065a36bc9ab2a00ac6a6f51e71501619a72c0609defd304d46610487a4","impliedFormat":1},{"version":"d91a7d8b5655c42986f1bdfe2105c4408f472831c8f20cf11a8c3345b6b56c8c","impliedFormat":1},{"version":"616075a6ac578cf5a013ee12964188b4412823796ce0b202c6f1d2e4ca8480d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"e8a979b8af001c9fc2e774e7809d233c8ca955a28756f52ee5dee88ccb0611d2","impliedFormat":1},{"version":"cac793cc47c29e26e4ac3601dcb00b4435ebed26203485790e44f2ad8b6ad847","impliedFormat":1},{"version":"17ed71200119e86ccef2d96b73b02ce8854b76ad6bd21b5021d4269bec527b5f","impliedFormat":1},{"version":"e91ad231af87f864b3f07cd0e39b1cf6c133988156f087c1c3ccb0a5491c9115","impliedFormat":1},{"version":"03c258e060b7da220973f84b89615e4e9850e9b5d30b3a8e4840b3e3268ae8eb","impliedFormat":1},{"version":"319c37263037e8d9481a3dc7eadf6afa6a5f5c002189ebe28776ac1a62a38e15","impliedFormat":1},{"version":"837f5c12e3e94ee97aca37aa2a50ede521e5887fb7fa89330f5625b70597e116","impliedFormat":1},{"version":"908217c4f2244ec402b73533ebfcc46d6dcd34fc1c807ff403d7f98702abb3bc","impliedFormat":1},{"version":"74d5a87c3616cd5d8691059d531504403aa857e09cbaecb1c64dfb9ace0db185","impliedFormat":1}],"root":[90,92],"options":{"allowJs":true,"declaration":true,"declarationDir":"./","emitDeclarationOnly":false,"esModuleInterop":true,"jsx":2,"module":1,"outDir":"./","skipLibCheck":true,"strict":true,"target":3},"referencedMap":[[84,1],[93,2],[94,2],[95,2],[96,2],[97,3],[98,2],[100,4],[101,5],[99,2],[102,2],[103,2],[104,2],[150,6],[151,6],[152,7],[110,8],[153,9],[154,10],[155,11],[105,2],[108,12],[106,2],[107,2],[156,13],[157,14],[158,15],[159,16],[160,17],[161,18],[162,18],[164,19],[163,20],[165,21],[166,22],[167,23],[149,24],[109,2],[168,25],[169,26],[170,27],[202,28],[171,29],[172,30],[173,31],[174,32],[175,33],[176,34],[177,35],[178,36],[179,37],[180,38],[181,38],[182,39],[183,2],[184,40],[186,41],[185,42],[187,43],[188,44],[189,45],[190,46],[191,47],[192,48],[193,49],[194,50],[195,51],[196,52],[197,53],[198,54],[199,55],[200,56],[201,57],[87,2],[203,58],[85,2],[88,59],[206,60],[204,61],[207,2],[205,2],[208,2],[209,62],[111,2],[86,2],[89,58],[79,2],[80,63],[81,64],[82,63],[83,65],[77,2],[78,2],[13,2],[14,2],[16,2],[15,2],[2,2],[17,2],[18,2],[19,2],[20,2],[21,2],[22,2],[23,2],[24,2],[3,2],[25,2],[26,2],[4,2],[27,2],[31,2],[28,2],[29,2],[30,2],[32,2],[33,2],[34,2],[5,2],[35,2],[36,2],[37,2],[38,2],[6,2],[42,2],[39,2],[40,2],[41,2],[43,2],[7,2],[44,2],[49,2],[50,2],[45,2],[46,2],[47,2],[48,2],[8,2],[54,2],[51,2],[52,2],[53,2],[55,2],[9,2],[56,2],[57,2],[58,2],[60,2],[59,2],[61,2],[62,2],[10,2],[63,2],[64,2],[65,2],[11,2],[66,2],[67,2],[68,2],[69,2],[70,2],[1,2],[71,2],[72,2],[12,2],[75,2],[74,2],[73,2],[76,2],[127,66],[137,67],[126,66],[147,68],[118,69],[117,70],[146,71],[140,72],[145,73],[120,74],[134,75],[119,76],[143,77],[115,78],[114,71],[144,79],[116,80],[121,81],[122,2],[125,81],[112,2],[148,82],[138,83],[129,84],[130,85],[132,86],[128,87],[131,88],[141,71],[123,89],[124,90],[133,91],[113,92],[136,83],[135,81],[139,2],[142,93],[91,94],[92,95],[90,96]],"version":"5.7.3"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arghajit/dummy",
|
|
3
3
|
"author": "Arghajit Singha",
|
|
4
|
-
"version": "0.1.0-beta-
|
|
4
|
+
"version": "0.1.0-beta-26",
|
|
5
5
|
"description": "A Playwright reporter and dashboard for visualizing test results.",
|
|
6
6
|
"homepage": "https://playwright-pulse-report.netlify.app/",
|
|
7
7
|
"keywords": [
|
|
@@ -240,8 +240,8 @@ function generateMinifiedHTML(reportData) {
|
|
|
240
240
|
<head>
|
|
241
241
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
242
242
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
243
|
-
<link rel="icon" type="image/png" href="https://i.postimg.cc/
|
|
244
|
-
<link rel="apple-touch-icon" href="https://i.postimg.cc/
|
|
243
|
+
<link rel="icon" type="image/png" href="https://i.postimg.cc/v817w4sg/logo.png">
|
|
244
|
+
<link rel="apple-touch-icon" href="https://i.postimg.cc/v817w4sg/logo.png">
|
|
245
245
|
<title>Playwright Pulse Summary Report</title>
|
|
246
246
|
<style>
|
|
247
247
|
:root {
|
|
@@ -299,8 +299,8 @@ function generateMinifiedHTML(reportData) {
|
|
|
299
299
|
color: var(--primary-color);
|
|
300
300
|
}
|
|
301
301
|
#report-logo {
|
|
302
|
-
height:
|
|
303
|
-
width:
|
|
302
|
+
height: 40px;
|
|
303
|
+
width: 55px;
|
|
304
304
|
}
|
|
305
305
|
.run-info {
|
|
306
306
|
font-size: 0.9em;
|
|
@@ -482,7 +482,7 @@ function generateMinifiedHTML(reportData) {
|
|
|
482
482
|
<div class="container">
|
|
483
483
|
<header class="report-header">
|
|
484
484
|
<div class="report-header-title">
|
|
485
|
-
<img id="report-logo" src="
|
|
485
|
+
<img id="report-logo" src="https://i.postimg.cc/v817w4sg/logo.png" alt="Report Logo">
|
|
486
486
|
<h1>Playwright Pulse Summary</h1>
|
|
487
487
|
</div>
|
|
488
488
|
<div class="run-info">
|
|
@@ -1019,6 +1019,260 @@ function generateEnvironmentDashboard(environment, dashboardHeight = 600) {
|
|
|
1019
1019
|
</div>
|
|
1020
1020
|
`;
|
|
1021
1021
|
}
|
|
1022
|
+
function generateWorkerDistributionChart(results) {
|
|
1023
|
+
if (!results || results.length === 0) {
|
|
1024
|
+
return '<div class="no-data">No test results data available to display worker distribution.</div>';
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
// 1. Sort results by startTime to ensure chronological order
|
|
1028
|
+
const sortedResults = [...results].sort((a, b) => {
|
|
1029
|
+
const timeA = a.startTime ? new Date(a.startTime).getTime() : 0;
|
|
1030
|
+
const timeB = b.startTime ? new Date(b.startTime).getTime() : 0;
|
|
1031
|
+
return timeA - timeB;
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
const workerData = sortedResults.reduce((acc, test) => {
|
|
1035
|
+
const workerId =
|
|
1036
|
+
typeof test.workerId !== "undefined" ? test.workerId : "N/A";
|
|
1037
|
+
if (!acc[workerId]) {
|
|
1038
|
+
acc[workerId] = { passed: 0, failed: 0, skipped: 0, tests: [] };
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
const status = String(test.status).toLowerCase();
|
|
1042
|
+
if (status === "passed" || status === "failed" || status === "skipped") {
|
|
1043
|
+
acc[workerId][status]++;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
const testTitleParts = test.name.split(" > ");
|
|
1047
|
+
const testTitle =
|
|
1048
|
+
testTitleParts[testTitleParts.length - 1] || "Unnamed Test";
|
|
1049
|
+
// Store both name and status for each test
|
|
1050
|
+
acc[workerId].tests.push({ name: testTitle, status: status });
|
|
1051
|
+
|
|
1052
|
+
return acc;
|
|
1053
|
+
}, {});
|
|
1054
|
+
|
|
1055
|
+
const workerIds = Object.keys(workerData).sort((a, b) => {
|
|
1056
|
+
if (a === "N/A") return 1;
|
|
1057
|
+
if (b === "N/A") return -1;
|
|
1058
|
+
return parseInt(a, 10) - parseInt(b, 10);
|
|
1059
|
+
});
|
|
1060
|
+
|
|
1061
|
+
if (workerIds.length === 0) {
|
|
1062
|
+
return '<div class="no-data">Could not determine worker distribution from test data.</div>';
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
const chartId = `workerDistChart-${Date.now()}-${Math.random()
|
|
1066
|
+
.toString(36)
|
|
1067
|
+
.substring(2, 7)}`;
|
|
1068
|
+
const renderFunctionName = `renderWorkerDistChart_${chartId.replace(
|
|
1069
|
+
/-/g,
|
|
1070
|
+
"_"
|
|
1071
|
+
)}`;
|
|
1072
|
+
const modalJsNamespace = `modal_funcs_${chartId.replace(/-/g, "_")}`;
|
|
1073
|
+
|
|
1074
|
+
// The categories now just need the name for the axis labels
|
|
1075
|
+
const categories = workerIds.map((id) => `Worker ${id}`);
|
|
1076
|
+
|
|
1077
|
+
// We pass the full data separately to the script
|
|
1078
|
+
const fullWorkerData = workerIds.map((id) => ({
|
|
1079
|
+
id: id,
|
|
1080
|
+
name: `Worker ${id}`,
|
|
1081
|
+
tests: workerData[id].tests,
|
|
1082
|
+
}));
|
|
1083
|
+
|
|
1084
|
+
const passedData = workerIds.map((id) => workerData[id].passed);
|
|
1085
|
+
const failedData = workerIds.map((id) => workerData[id].failed);
|
|
1086
|
+
const skippedData = workerIds.map((id) => workerData[id].skipped);
|
|
1087
|
+
|
|
1088
|
+
const categoriesString = JSON.stringify(categories);
|
|
1089
|
+
const fullDataString = JSON.stringify(fullWorkerData);
|
|
1090
|
+
const seriesString = JSON.stringify([
|
|
1091
|
+
{ name: "Passed", data: passedData, color: "var(--success-color)" },
|
|
1092
|
+
{ name: "Failed", data: failedData, color: "var(--danger-color)" },
|
|
1093
|
+
{ name: "Skipped", data: skippedData, color: "var(--warning-color)" },
|
|
1094
|
+
]);
|
|
1095
|
+
|
|
1096
|
+
// The HTML now includes the chart container, the modal, and styles for the modal
|
|
1097
|
+
return `
|
|
1098
|
+
<style>
|
|
1099
|
+
.worker-modal-overlay {
|
|
1100
|
+
position: fixed; z-index: 1050; left: 0; top: 0; width: 100%; height: 100%;
|
|
1101
|
+
overflow: auto; background-color: rgba(0,0,0,0.6);
|
|
1102
|
+
display: none; align-items: center; justify-content: center;
|
|
1103
|
+
}
|
|
1104
|
+
.worker-modal-content {
|
|
1105
|
+
background-color: #3d4043;
|
|
1106
|
+
color: var(--card-background-color);
|
|
1107
|
+
margin: auto; padding: 20px; border: 1px solid var(--border-color, #888);
|
|
1108
|
+
width: 80%; max-width: 700px; border-radius: 8px;
|
|
1109
|
+
position: relative; box-shadow: 0 5px 15px rgba(0,0,0,0.5);
|
|
1110
|
+
}
|
|
1111
|
+
.worker-modal-close {
|
|
1112
|
+
position: absolute; top: 10px; right: 20px;
|
|
1113
|
+
font-size: 28px; font-weight: bold; cursor: pointer;
|
|
1114
|
+
line-height: 1;
|
|
1115
|
+
}
|
|
1116
|
+
.worker-modal-close:hover, .worker-modal-close:focus {
|
|
1117
|
+
color: var(--text-color, #000);
|
|
1118
|
+
}
|
|
1119
|
+
#worker-modal-body-${chartId} ul {
|
|
1120
|
+
list-style-type: none; padding-left: 0; margin-top: 15px; max-height: 45vh; overflow-y: auto;
|
|
1121
|
+
}
|
|
1122
|
+
#worker-modal-body-${chartId} li {
|
|
1123
|
+
padding: 8px 5px; border-bottom: 1px solid var(--border-color, #eee);
|
|
1124
|
+
font-size: 0.9em;
|
|
1125
|
+
}
|
|
1126
|
+
#worker-modal-body-${chartId} li:last-child {
|
|
1127
|
+
border-bottom: none;
|
|
1128
|
+
}
|
|
1129
|
+
#worker-modal-body-${chartId} li > span {
|
|
1130
|
+
display: inline-block;
|
|
1131
|
+
width: 70px;
|
|
1132
|
+
font-weight: bold;
|
|
1133
|
+
text-align: right;
|
|
1134
|
+
margin-right: 10px;
|
|
1135
|
+
}
|
|
1136
|
+
</style>
|
|
1137
|
+
|
|
1138
|
+
<div id="${chartId}" class="trend-chart-container lazy-load-chart" data-render-function-name="${renderFunctionName}" style="min-height: 350px;">
|
|
1139
|
+
<div class="no-data">Loading Worker Distribution Chart...</div>
|
|
1140
|
+
</div>
|
|
1141
|
+
|
|
1142
|
+
<div id="worker-modal-${chartId}" class="worker-modal-overlay">
|
|
1143
|
+
<div class="worker-modal-content">
|
|
1144
|
+
<span class="worker-modal-close">×</span>
|
|
1145
|
+
<h3 id="worker-modal-title-${chartId}" style="text-align: center; margin-top: 0; margin-bottom: 25px; font-size: 1.25em; font-weight: 600; color: #fff"></h3>
|
|
1146
|
+
<div id="worker-modal-body-${chartId}"></div>
|
|
1147
|
+
</div>
|
|
1148
|
+
</div>
|
|
1149
|
+
|
|
1150
|
+
<script>
|
|
1151
|
+
// Namespace for modal functions to avoid global scope pollution
|
|
1152
|
+
window.${modalJsNamespace} = {};
|
|
1153
|
+
|
|
1154
|
+
window.${renderFunctionName} = function() {
|
|
1155
|
+
const chartContainer = document.getElementById('${chartId}');
|
|
1156
|
+
if (!chartContainer) { console.error("Chart container ${chartId} not found."); return; }
|
|
1157
|
+
|
|
1158
|
+
// --- Modal Setup ---
|
|
1159
|
+
const modal = document.getElementById('worker-modal-${chartId}');
|
|
1160
|
+
const modalTitle = document.getElementById('worker-modal-title-${chartId}');
|
|
1161
|
+
const modalBody = document.getElementById('worker-modal-body-${chartId}');
|
|
1162
|
+
const closeModalBtn = modal.querySelector('.worker-modal-close');
|
|
1163
|
+
|
|
1164
|
+
window.${modalJsNamespace}.open = function(worker) {
|
|
1165
|
+
if (!worker) return;
|
|
1166
|
+
modalTitle.textContent = 'Test Details for ' + worker.name;
|
|
1167
|
+
|
|
1168
|
+
let testListHtml = '<ul>';
|
|
1169
|
+
if (worker.tests && worker.tests.length > 0) {
|
|
1170
|
+
worker.tests.forEach(test => {
|
|
1171
|
+
let color = 'inherit';
|
|
1172
|
+
if (test.status === 'passed') color = 'var(--success-color)';
|
|
1173
|
+
else if (test.status === 'failed') color = 'var(--danger-color)';
|
|
1174
|
+
else if (test.status === 'skipped') color = 'var(--warning-color)';
|
|
1175
|
+
|
|
1176
|
+
const escapedName = test.name.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
1177
|
+
testListHtml += \`<li style="color: \${color};"><span style="color: \${color}">[\${test.status.toUpperCase()}]</span> \${escapedName}</li>\`;
|
|
1178
|
+
});
|
|
1179
|
+
} else {
|
|
1180
|
+
testListHtml += '<li>No detailed test data available for this worker.</li>';
|
|
1181
|
+
}
|
|
1182
|
+
testListHtml += '</ul>';
|
|
1183
|
+
|
|
1184
|
+
modalBody.innerHTML = testListHtml;
|
|
1185
|
+
modal.style.display = 'flex';
|
|
1186
|
+
};
|
|
1187
|
+
|
|
1188
|
+
const closeModal = function() {
|
|
1189
|
+
modal.style.display = 'none';
|
|
1190
|
+
};
|
|
1191
|
+
|
|
1192
|
+
closeModalBtn.onclick = closeModal;
|
|
1193
|
+
modal.onclick = function(event) {
|
|
1194
|
+
// Close if clicked on the dark overlay background
|
|
1195
|
+
if (event.target == modal) {
|
|
1196
|
+
closeModal();
|
|
1197
|
+
}
|
|
1198
|
+
};
|
|
1199
|
+
|
|
1200
|
+
|
|
1201
|
+
// --- Highcharts Setup ---
|
|
1202
|
+
if (typeof Highcharts !== 'undefined') {
|
|
1203
|
+
try {
|
|
1204
|
+
chartContainer.innerHTML = '';
|
|
1205
|
+
const fullData = ${fullDataString};
|
|
1206
|
+
|
|
1207
|
+
const chartOptions = {
|
|
1208
|
+
chart: { type: 'bar', height: 350, backgroundColor: 'transparent' },
|
|
1209
|
+
title: { text: null },
|
|
1210
|
+
xAxis: {
|
|
1211
|
+
categories: ${categoriesString},
|
|
1212
|
+
title: { text: 'Worker ID' },
|
|
1213
|
+
labels: { style: { color: 'var(--text-color-secondary)' }}
|
|
1214
|
+
},
|
|
1215
|
+
yAxis: {
|
|
1216
|
+
min: 0,
|
|
1217
|
+
title: { text: 'Number of Tests' },
|
|
1218
|
+
labels: { style: { color: 'var(--text-color-secondary)' }},
|
|
1219
|
+
stackLabels: { enabled: true, style: { fontWeight: 'bold', color: 'var(--text-color)' } }
|
|
1220
|
+
},
|
|
1221
|
+
legend: { reversed: true, itemStyle: { fontSize: "12px", color: 'var(--text-color)' } },
|
|
1222
|
+
plotOptions: {
|
|
1223
|
+
series: {
|
|
1224
|
+
stacking: 'normal',
|
|
1225
|
+
cursor: 'pointer',
|
|
1226
|
+
point: {
|
|
1227
|
+
events: {
|
|
1228
|
+
click: function () {
|
|
1229
|
+
// 'this.x' is the index of the category
|
|
1230
|
+
const workerData = fullData[this.x];
|
|
1231
|
+
window.${modalJsNamespace}.open(workerData);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
},
|
|
1237
|
+
tooltip: {
|
|
1238
|
+
shared: true,
|
|
1239
|
+
headerFormat: '<b>{point.key}</b> (Click for details)<br/>',
|
|
1240
|
+
pointFormat: '<span style="color:{series.color}">●</span> {series.name}: <b>{point.y}</b><br/>',
|
|
1241
|
+
footerFormat: 'Total: <b>{point.total}</b>'
|
|
1242
|
+
},
|
|
1243
|
+
series: ${seriesString},
|
|
1244
|
+
credits: { enabled: false }
|
|
1245
|
+
};
|
|
1246
|
+
Highcharts.chart('${chartId}', chartOptions);
|
|
1247
|
+
} catch (e) {
|
|
1248
|
+
console.error("Error rendering chart ${chartId}:", e);
|
|
1249
|
+
chartContainer.innerHTML = '<div class="no-data">Error rendering worker distribution chart.</div>';
|
|
1250
|
+
}
|
|
1251
|
+
} else {
|
|
1252
|
+
chartContainer.innerHTML = '<div class="no-data">Charting library not available for worker distribution.</div>';
|
|
1253
|
+
}
|
|
1254
|
+
};
|
|
1255
|
+
</script>
|
|
1256
|
+
`;
|
|
1257
|
+
}
|
|
1258
|
+
const infoTooltip = `
|
|
1259
|
+
<span class="info-tooltip" style="display: inline-block; margin-left: 8px;">
|
|
1260
|
+
<span class="info-icon"
|
|
1261
|
+
style="cursor: pointer; font-size: 1.25rem;"
|
|
1262
|
+
onclick="window.workerInfoPrompt()">ℹ️</span>
|
|
1263
|
+
</span>
|
|
1264
|
+
<script>
|
|
1265
|
+
window.workerInfoPrompt = function() {
|
|
1266
|
+
const message = 'Why is worker -1 special?\\n\\n' +
|
|
1267
|
+
'Playwright assigns skipped tests to worker -1 because:\\n' +
|
|
1268
|
+
'1. They don\\'t require browser execution\\n' +
|
|
1269
|
+
'2. This keeps real workers focused on actual tests\\n' +
|
|
1270
|
+
'3. Maintains clean reporting\\n\\n' +
|
|
1271
|
+
'This is an intentional optimization by Playwright.';
|
|
1272
|
+
alert(message);
|
|
1273
|
+
}
|
|
1274
|
+
</script>
|
|
1275
|
+
`;
|
|
1022
1276
|
function generateTestHistoryContent(trendData) {
|
|
1023
1277
|
if (
|
|
1024
1278
|
!trendData ||
|
|
@@ -1267,11 +1521,16 @@ function generateSuitesWidget(suitesData) {
|
|
|
1267
1521
|
</div>`;
|
|
1268
1522
|
}
|
|
1269
1523
|
function getAttachmentIcon(contentType) {
|
|
1270
|
-
if (contentType
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
if (
|
|
1524
|
+
if (!contentType) return "📎"; // Handle undefined/null
|
|
1525
|
+
|
|
1526
|
+
const normalizedType = contentType.toLowerCase();
|
|
1527
|
+
|
|
1528
|
+
if (normalizedType.includes("pdf")) return "📄";
|
|
1529
|
+
if (normalizedType.includes("json")) return "{ }";
|
|
1530
|
+
if (/html/.test(normalizedType)) return "🌐"; // Fixed: regex for any HTML type
|
|
1531
|
+
if (normalizedType.includes("xml")) return "<>";
|
|
1532
|
+
if (normalizedType.includes("csv")) return "📊";
|
|
1533
|
+
if (normalizedType.startsWith("text/")) return "📝";
|
|
1275
1534
|
return "📎";
|
|
1276
1535
|
}
|
|
1277
1536
|
function generateHTML(reportData, trendData = null) {
|
|
@@ -1329,14 +1588,14 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1329
1588
|
<div class="step-details" style="display: none;">
|
|
1330
1589
|
${
|
|
1331
1590
|
step.codeLocation
|
|
1332
|
-
? `<div class="step-info"><strong>Location:</strong> ${sanitizeHTML(
|
|
1591
|
+
? `<div class="step-info code-section"><strong>Location:</strong> ${sanitizeHTML(
|
|
1333
1592
|
step.codeLocation
|
|
1334
1593
|
)}</div>`
|
|
1335
1594
|
: ""
|
|
1336
1595
|
}
|
|
1337
1596
|
${
|
|
1338
1597
|
step.errorMessage
|
|
1339
|
-
? `<div class="
|
|
1598
|
+
? `<div class="test-error-summary">
|
|
1340
1599
|
${
|
|
1341
1600
|
step.stackTrace
|
|
1342
1601
|
? `<div class="stack-trace">${formatPlaywrightError(
|
|
@@ -1443,13 +1702,21 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1443
1702
|
}
|
|
1444
1703
|
<h4>Steps</h4>
|
|
1445
1704
|
<div class="steps-list">${generateStepsHTML(test.steps)}</div>
|
|
1446
|
-
${
|
|
1447
|
-
test.stdout
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1705
|
+
${(() => {
|
|
1706
|
+
if (!test.stdout || test.stdout.length === 0) return "";
|
|
1707
|
+
// Create a unique ID for the <pre> element to target it for copying
|
|
1708
|
+
const logId = `stdout-log-${test.id || testIndex}`;
|
|
1709
|
+
return `<div class="console-output-section">
|
|
1710
|
+
<h4>Console Output (stdout)
|
|
1711
|
+
<button class="copy-btn" onclick="copyLogContent('${logId}', this)">Copy Console</button>
|
|
1712
|
+
</h4>
|
|
1713
|
+
<div class="log-wrapper">
|
|
1714
|
+
<pre id="${logId}" class="console-log stdout-log" style="background-color: #2d2d2d; color: wheat; padding: 1.25em; border-radius: 0.85em; line-height: 1.2;">${formatPlaywrightError(
|
|
1715
|
+
test.stdout.map((line) => sanitizeHTML(line)).join("\n")
|
|
1716
|
+
)}</pre>
|
|
1717
|
+
</div>
|
|
1718
|
+
</div>`;
|
|
1719
|
+
})()}
|
|
1453
1720
|
${
|
|
1454
1721
|
test.stderr && test.stderr.length > 0
|
|
1455
1722
|
? `<div class="console-output-section"><h4>Console Output (stderr)</h4><pre class="console-log stderr-log" style="background-color: #2d2d2d; color: indianred; padding: 1.25em; border-radius: 0.85em; line-height: 1.2;">${formatPlaywrightError(
|
|
@@ -1571,6 +1838,9 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1571
1838
|
</div>
|
|
1572
1839
|
<div class="attachment-info">
|
|
1573
1840
|
<div class="trace-actions">
|
|
1841
|
+
<a href="${sanitizeHTML(
|
|
1842
|
+
attachment.path
|
|
1843
|
+
)}" target="_blank" class="view-full">View</a>
|
|
1574
1844
|
<a href="${sanitizeHTML(
|
|
1575
1845
|
attachment.path
|
|
1576
1846
|
)}" target="_blank" download="${sanitizeHTML(
|
|
@@ -1605,8 +1875,8 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1605
1875
|
<head>
|
|
1606
1876
|
<meta charset="UTF-8">
|
|
1607
1877
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1608
|
-
<link rel="icon" type="image/png" href="https://i.postimg.cc/
|
|
1609
|
-
<link rel="apple-touch-icon" href="https://i.postimg.cc/
|
|
1878
|
+
<link rel="icon" type="image/png" href="https://i.postimg.cc/v817w4sg/logo.png">
|
|
1879
|
+
<link rel="apple-touch-icon" href="https://i.postimg.cc/v817w4sg/logo.png">
|
|
1610
1880
|
<script src="https://code.highcharts.com/highcharts.js" defer></script>
|
|
1611
1881
|
<title>Playwright Pulse Report</title>
|
|
1612
1882
|
<style>
|
|
@@ -1630,7 +1900,7 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1630
1900
|
.header { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; padding-bottom: 25px; border-bottom: 1px solid var(--border-color); margin-bottom: 25px; }
|
|
1631
1901
|
.header-title { display: flex; align-items: center; gap: 15px; }
|
|
1632
1902
|
.header h1 { margin: 0; font-size: 1.85em; font-weight: 600; color: var(--primary-color); }
|
|
1633
|
-
#report-logo { height: 40px; width:
|
|
1903
|
+
#report-logo { height: 40px; width: 55px; }
|
|
1634
1904
|
.run-info { font-size: 0.9em; text-align: right; color: var(--text-color-secondary); line-height:1.5;}
|
|
1635
1905
|
.run-info strong { color: var(--text-color); }
|
|
1636
1906
|
.tabs { display: flex; border-bottom: 2px solid var(--border-color); margin-bottom: 30px; overflow-x: auto; }
|
|
@@ -1709,8 +1979,8 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1709
1979
|
.step-duration { color: var(--dark-gray-color); font-size: 0.9em; }
|
|
1710
1980
|
.step-details { display: none; padding: 14px; margin-top: 8px; background: #fdfdfd; border-radius: 6px; font-size: 0.95em; border: 1px solid var(--light-gray-color); }
|
|
1711
1981
|
.step-info { margin-bottom: 8px; }
|
|
1712
|
-
.
|
|
1713
|
-
.
|
|
1982
|
+
.test-error-summary { color: var(--danger-color); margin-top: 12px; padding: 14px; background: rgba(244,67,54,0.05); border-radius: 4px; font-size: 0.95em; border-left: 3px solid var(--danger-color); }
|
|
1983
|
+
.test-error-summary pre.stack-trace { margin-top: 10px; padding: 12px; background-color: rgba(0,0,0,0.03); border-radius: 4px; font-size:0.9em; max-height: 280px; overflow-y: auto; white-space: pre-wrap; word-break: break-all; }
|
|
1714
1984
|
.step-hook { background-color: rgba(33,150,243,0.04); border-left: 3px solid var(--info-color) !important; }
|
|
1715
1985
|
.step-hook .step-title { font-style: italic; color: var(--info-color)}
|
|
1716
1986
|
.nested-steps { margin-top: 12px; }
|
|
@@ -1767,17 +2037,18 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1767
2037
|
.download-trace:hover { background: #cbd5e0; }
|
|
1768
2038
|
.filters button.clear-filters-btn { background-color: var(--medium-gray-color); color: var(--text-color); }
|
|
1769
2039
|
.filters button.clear-filters-btn:hover { background-color: var(--dark-gray-color); color: #fff; }
|
|
2040
|
+
.copy-btn {color: var(--primary-color); background: #fefefe; border-radius: 8px; cursor: pointer; border-color: var(--primary-color); font-size: 1em; margin-left: 93%; font-weight: 600;}
|
|
1770
2041
|
@media (max-width: 1200px) { .trend-charts-row { grid-template-columns: 1fr; } }
|
|
1771
2042
|
@media (max-width: 992px) { .dashboard-bottom-row { grid-template-columns: 1fr; } .pie-chart-wrapper div[id^="pieChart-"] { max-width: 350px; margin: 0 auto; } .filters input { min-width: 180px; } .filters select { min-width: 150px; } }
|
|
1772
2043
|
@media (max-width: 768px) { body { font-size: 15px; } .container { margin: 10px; padding: 20px; } .header { flex-direction: column; align-items: flex-start; gap: 15px; } .header h1 { font-size: 1.6em; } .run-info { text-align: left; font-size:0.9em; } .tabs { margin-bottom: 25px;} .tab-button { padding: 12px 20px; font-size: 1.05em;} .dashboard-grid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 18px;} .summary-card .value {font-size: 2em;} .summary-card h3 {font-size: 0.95em;} .filters { flex-direction: column; padding: 18px; gap: 12px;} .filters input, .filters select, .filters button {width: 100%; box-sizing: border-box;} .test-case-header { flex-direction: column; align-items: flex-start; gap: 10px; padding: 14px; } .test-case-summary {gap: 10px;} .test-case-title {font-size: 1.05em;} .test-case-meta { flex-direction: row; flex-wrap: wrap; gap: 8px; margin-top: 8px;} .attachments-grid {grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 18px;} .test-history-grid {grid-template-columns: 1fr;} .pie-chart-wrapper {min-height: auto;} }
|
|
1773
|
-
@media (max-width: 480px) { body {font-size: 14px;} .container {padding: 15px;} .header h1 {font-size: 1.4em;} #report-logo { height: 35px; width:
|
|
2044
|
+
@media (max-width: 480px) { body {font-size: 14px;} .container {padding: 15px;} .header h1 {font-size: 1.4em;} #report-logo { height: 35px; width: 50px; } .tab-button {padding: 10px 15px; font-size: 1em;} .summary-card .value {font-size: 1.8em;} .attachments-grid {grid-template-columns: 1fr;} .step-item {padding-left: calc(var(--depth, 0) * 18px);} .test-case-content, .step-details {padding: 15px;} .trend-charts-row {gap: 20px;} .trend-chart {padding: 20px;} }
|
|
1774
2045
|
</style>
|
|
1775
2046
|
</head>
|
|
1776
2047
|
<body>
|
|
1777
2048
|
<div class="container">
|
|
1778
2049
|
<header class="header">
|
|
1779
2050
|
<div class="header-title">
|
|
1780
|
-
<img id="report-logo" src="
|
|
2051
|
+
<img id="report-logo" src="https://i.postimg.cc/v817w4sg/logo.png" alt="Report Logo">
|
|
1781
2052
|
<h1>Playwright Pulse Report</h1>
|
|
1782
2053
|
</div>
|
|
1783
2054
|
<div class="run-info"><strong>Run Date:</strong> ${formatDate(
|
|
@@ -1870,6 +2141,12 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1870
2141
|
}
|
|
1871
2142
|
</div>
|
|
1872
2143
|
</div>
|
|
2144
|
+
<h2 class="tab-main-title">Test Distribution by Worker ${infoTooltip}</h2>
|
|
2145
|
+
<div class="trend-charts-row">
|
|
2146
|
+
<div class="trend-chart">
|
|
2147
|
+
${generateWorkerDistributionChart(results)}
|
|
2148
|
+
</div>
|
|
2149
|
+
</div>
|
|
1873
2150
|
<h2 class="tab-main-title">Individual Test History</h2>
|
|
1874
2151
|
${
|
|
1875
2152
|
trendData &&
|
|
@@ -1884,7 +2161,6 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1884
2161
|
</div>
|
|
1885
2162
|
<footer style="padding: 0.5rem; box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05); text-align: center; font-family: 'Segoe UI', system-ui, sans-serif;">
|
|
1886
2163
|
<div style="display: inline-flex; align-items: center; gap: 0.5rem; color: #333; font-size: 0.9rem; font-weight: 600; letter-spacing: 0.5px;">
|
|
1887
|
-
<img width="48" height="48" src="https://img.icons8.com/emoji/48/index-pointing-at-the-viewer-light-skin-tone-emoji.png" alt="index-pointing-at-the-viewer-light-skin-tone-emoji"/>
|
|
1888
2164
|
<span>Created by</span>
|
|
1889
2165
|
<a href="https://github.com/Arghajit47" target="_blank" rel="noopener noreferrer" style="color: #7737BF; font-weight: 700; font-style: italic; text-decoration: none; transition: all 0.2s ease;" onmouseover="this.style.color='#BF5C37'" onmouseout="this.style.color='#7737BF'">Arghajit Singha</a>
|
|
1890
2166
|
</div>
|
|
@@ -1899,6 +2175,21 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1899
2175
|
return (ms / 1000).toFixed(1) + "s";
|
|
1900
2176
|
}
|
|
1901
2177
|
}
|
|
2178
|
+
function copyLogContent(elementId, button) {
|
|
2179
|
+
const logElement = document.getElementById(elementId);
|
|
2180
|
+
if (!logElement) {
|
|
2181
|
+
console.error('Could not find log element with ID:', elementId);
|
|
2182
|
+
return;
|
|
2183
|
+
}
|
|
2184
|
+
navigator.clipboard.writeText(logElement.innerText).then(() => {
|
|
2185
|
+
button.textContent = 'Copied!';
|
|
2186
|
+
setTimeout(() => { button.textContent = 'Copy'; }, 2000);
|
|
2187
|
+
}).catch(err => {
|
|
2188
|
+
console.error('Failed to copy log content:', err);
|
|
2189
|
+
button.textContent = 'Failed';
|
|
2190
|
+
setTimeout(() => { button.textContent = 'Copy'; }, 2000);
|
|
2191
|
+
});
|
|
2192
|
+
}
|
|
1902
2193
|
function initializeReportInteractivity() {
|
|
1903
2194
|
const tabButtons = document.querySelectorAll('.tab-button');
|
|
1904
2195
|
const tabContents = document.querySelectorAll('.tab-content');
|
|
@@ -2061,9 +2352,9 @@ function generateHTML(reportData, trendData = null) {
|
|
|
2061
2352
|
|
|
2062
2353
|
function copyErrorToClipboard(button) {
|
|
2063
2354
|
// 1. Find the main error container, which should always be present.
|
|
2064
|
-
const errorContainer = button.closest('.
|
|
2355
|
+
const errorContainer = button.closest('.test-error-summary');
|
|
2065
2356
|
if (!errorContainer) {
|
|
2066
|
-
console.error("Could not find '.
|
|
2357
|
+
console.error("Could not find '.test-error-summary' container. The report's HTML structure might have changed.");
|
|
2067
2358
|
return;
|
|
2068
2359
|
}
|
|
2069
2360
|
|
|
@@ -2338,4 +2629,4 @@ main().catch((err) => {
|
|
|
2338
2629
|
);
|
|
2339
2630
|
console.error(err.stack);
|
|
2340
2631
|
process.exit(1);
|
|
2341
|
-
});
|
|
2632
|
+
});
|
|
@@ -141,7 +141,6 @@ export function ansiToHtml(text) {
|
|
|
141
141
|
}
|
|
142
142
|
return html;
|
|
143
143
|
}
|
|
144
|
-
|
|
145
144
|
function sanitizeHTML(str) {
|
|
146
145
|
if (str === null || str === undefined) return "";
|
|
147
146
|
return String(str).replace(
|
|
@@ -150,7 +149,6 @@ function sanitizeHTML(str) {
|
|
|
150
149
|
({ "&": "&", "<": "<", ">": ">", '"': '"', "'": "'" }[match] || match)
|
|
151
150
|
);
|
|
152
151
|
}
|
|
153
|
-
|
|
154
152
|
function capitalize(str) {
|
|
155
153
|
if (!str) return "";
|
|
156
154
|
return str[0].toUpperCase() + str.slice(1).toLowerCase();
|
|
@@ -1216,6 +1214,19 @@ function getSuitesData(results) {
|
|
|
1216
1214
|
});
|
|
1217
1215
|
return Array.from(suitesMap.values());
|
|
1218
1216
|
}
|
|
1217
|
+
function getAttachmentIcon(contentType) {
|
|
1218
|
+
if (!contentType) return "📎"; // Handle undefined/null
|
|
1219
|
+
|
|
1220
|
+
const normalizedType = contentType.toLowerCase();
|
|
1221
|
+
|
|
1222
|
+
if (normalizedType.includes("pdf")) return "📄";
|
|
1223
|
+
if (normalizedType.includes("json")) return "{ }";
|
|
1224
|
+
if (/html/.test(normalizedType)) return "🌐"; // Fixed: regex for any HTML type
|
|
1225
|
+
if (normalizedType.includes("xml")) return "<>";
|
|
1226
|
+
if (normalizedType.includes("csv")) return "📊";
|
|
1227
|
+
if (normalizedType.startsWith("text/")) return "📝";
|
|
1228
|
+
return "📎";
|
|
1229
|
+
}
|
|
1219
1230
|
function generateSuitesWidget(suitesData) {
|
|
1220
1231
|
if (!suitesData || suitesData.length === 0) {
|
|
1221
1232
|
return `<div class="suites-widget"><div class="suites-header"><h2>Test Suites</h2></div><div class="no-data">No suite data available.</div></div>`;
|
|
@@ -1272,6 +1283,260 @@ function generateSuitesWidget(suitesData) {
|
|
|
1272
1283
|
</div>
|
|
1273
1284
|
</div>`;
|
|
1274
1285
|
}
|
|
1286
|
+
function generateWorkerDistributionChart(results) {
|
|
1287
|
+
if (!results || results.length === 0) {
|
|
1288
|
+
return '<div class="no-data">No test results data available to display worker distribution.</div>';
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
// 1. Sort results by startTime to ensure chronological order
|
|
1292
|
+
const sortedResults = [...results].sort((a, b) => {
|
|
1293
|
+
const timeA = a.startTime ? new Date(a.startTime).getTime() : 0;
|
|
1294
|
+
const timeB = b.startTime ? new Date(b.startTime).getTime() : 0;
|
|
1295
|
+
return timeA - timeB;
|
|
1296
|
+
});
|
|
1297
|
+
|
|
1298
|
+
const workerData = sortedResults.reduce((acc, test) => {
|
|
1299
|
+
const workerId =
|
|
1300
|
+
typeof test.workerId !== "undefined" ? test.workerId : "N/A";
|
|
1301
|
+
if (!acc[workerId]) {
|
|
1302
|
+
acc[workerId] = { passed: 0, failed: 0, skipped: 0, tests: [] };
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
const status = String(test.status).toLowerCase();
|
|
1306
|
+
if (status === "passed" || status === "failed" || status === "skipped") {
|
|
1307
|
+
acc[workerId][status]++;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
const testTitleParts = test.name.split(" > ");
|
|
1311
|
+
const testTitle =
|
|
1312
|
+
testTitleParts[testTitleParts.length - 1] || "Unnamed Test";
|
|
1313
|
+
// Store both name and status for each test
|
|
1314
|
+
acc[workerId].tests.push({ name: testTitle, status: status });
|
|
1315
|
+
|
|
1316
|
+
return acc;
|
|
1317
|
+
}, {});
|
|
1318
|
+
|
|
1319
|
+
const workerIds = Object.keys(workerData).sort((a, b) => {
|
|
1320
|
+
if (a === "N/A") return 1;
|
|
1321
|
+
if (b === "N/A") return -1;
|
|
1322
|
+
return parseInt(a, 10) - parseInt(b, 10);
|
|
1323
|
+
});
|
|
1324
|
+
|
|
1325
|
+
if (workerIds.length === 0) {
|
|
1326
|
+
return '<div class="no-data">Could not determine worker distribution from test data.</div>';
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
const chartId = `workerDistChart-${Date.now()}-${Math.random()
|
|
1330
|
+
.toString(36)
|
|
1331
|
+
.substring(2, 7)}`;
|
|
1332
|
+
const renderFunctionName = `renderWorkerDistChart_${chartId.replace(
|
|
1333
|
+
/-/g,
|
|
1334
|
+
"_"
|
|
1335
|
+
)}`;
|
|
1336
|
+
const modalJsNamespace = `modal_funcs_${chartId.replace(/-/g, "_")}`;
|
|
1337
|
+
|
|
1338
|
+
// The categories now just need the name for the axis labels
|
|
1339
|
+
const categories = workerIds.map((id) => `Worker ${id}`);
|
|
1340
|
+
|
|
1341
|
+
// We pass the full data separately to the script
|
|
1342
|
+
const fullWorkerData = workerIds.map((id) => ({
|
|
1343
|
+
id: id,
|
|
1344
|
+
name: `Worker ${id}`,
|
|
1345
|
+
tests: workerData[id].tests,
|
|
1346
|
+
}));
|
|
1347
|
+
|
|
1348
|
+
const passedData = workerIds.map((id) => workerData[id].passed);
|
|
1349
|
+
const failedData = workerIds.map((id) => workerData[id].failed);
|
|
1350
|
+
const skippedData = workerIds.map((id) => workerData[id].skipped);
|
|
1351
|
+
|
|
1352
|
+
const categoriesString = JSON.stringify(categories);
|
|
1353
|
+
const fullDataString = JSON.stringify(fullWorkerData);
|
|
1354
|
+
const seriesString = JSON.stringify([
|
|
1355
|
+
{ name: "Passed", data: passedData, color: "var(--success-color)" },
|
|
1356
|
+
{ name: "Failed", data: failedData, color: "var(--danger-color)" },
|
|
1357
|
+
{ name: "Skipped", data: skippedData, color: "var(--warning-color)" },
|
|
1358
|
+
]);
|
|
1359
|
+
|
|
1360
|
+
// The HTML now includes the chart container, the modal, and styles for the modal
|
|
1361
|
+
return `
|
|
1362
|
+
<style>
|
|
1363
|
+
.worker-modal-overlay {
|
|
1364
|
+
position: fixed; z-index: 1050; left: 0; top: 0; width: 100%; height: 100%;
|
|
1365
|
+
overflow: auto; background-color: rgba(0,0,0,0.6);
|
|
1366
|
+
display: none; align-items: center; justify-content: center;
|
|
1367
|
+
}
|
|
1368
|
+
.worker-modal-content {
|
|
1369
|
+
background-color: #3d4043;
|
|
1370
|
+
color: var(--card-background-color);
|
|
1371
|
+
margin: auto; padding: 20px; border: 1px solid var(--border-color, #888);
|
|
1372
|
+
width: 80%; max-width: 700px; border-radius: 8px;
|
|
1373
|
+
position: relative; box-shadow: 0 5px 15px rgba(0,0,0,0.5);
|
|
1374
|
+
}
|
|
1375
|
+
.worker-modal-close {
|
|
1376
|
+
position: absolute; top: 10px; right: 20px;
|
|
1377
|
+
font-size: 28px; font-weight: bold; cursor: pointer;
|
|
1378
|
+
line-height: 1;
|
|
1379
|
+
}
|
|
1380
|
+
.worker-modal-close:hover, .worker-modal-close:focus {
|
|
1381
|
+
color: var(--text-color, #000);
|
|
1382
|
+
}
|
|
1383
|
+
#worker-modal-body-${chartId} ul {
|
|
1384
|
+
list-style-type: none; padding-left: 0; margin-top: 15px; max-height: 45vh; overflow-y: auto;
|
|
1385
|
+
}
|
|
1386
|
+
#worker-modal-body-${chartId} li {
|
|
1387
|
+
padding: 8px 5px; border-bottom: 1px solid var(--border-color, #eee);
|
|
1388
|
+
font-size: 0.9em;
|
|
1389
|
+
}
|
|
1390
|
+
#worker-modal-body-${chartId} li:last-child {
|
|
1391
|
+
border-bottom: none;
|
|
1392
|
+
}
|
|
1393
|
+
#worker-modal-body-${chartId} li > span {
|
|
1394
|
+
display: inline-block;
|
|
1395
|
+
width: 70px;
|
|
1396
|
+
font-weight: bold;
|
|
1397
|
+
text-align: right;
|
|
1398
|
+
margin-right: 10px;
|
|
1399
|
+
}
|
|
1400
|
+
</style>
|
|
1401
|
+
|
|
1402
|
+
<div id="${chartId}" class="trend-chart-container lazy-load-chart" data-render-function-name="${renderFunctionName}" style="min-height: 350px;">
|
|
1403
|
+
<div class="no-data">Loading Worker Distribution Chart...</div>
|
|
1404
|
+
</div>
|
|
1405
|
+
|
|
1406
|
+
<div id="worker-modal-${chartId}" class="worker-modal-overlay">
|
|
1407
|
+
<div class="worker-modal-content">
|
|
1408
|
+
<span class="worker-modal-close">×</span>
|
|
1409
|
+
<h3 id="worker-modal-title-${chartId}" style="text-align: center; margin-top: 0; margin-bottom: 25px; font-size: 1.25em; font-weight: 600; color: #fff"></h3>
|
|
1410
|
+
<div id="worker-modal-body-${chartId}"></div>
|
|
1411
|
+
</div>
|
|
1412
|
+
</div>
|
|
1413
|
+
|
|
1414
|
+
<script>
|
|
1415
|
+
// Namespace for modal functions to avoid global scope pollution
|
|
1416
|
+
window.${modalJsNamespace} = {};
|
|
1417
|
+
|
|
1418
|
+
window.${renderFunctionName} = function() {
|
|
1419
|
+
const chartContainer = document.getElementById('${chartId}');
|
|
1420
|
+
if (!chartContainer) { console.error("Chart container ${chartId} not found."); return; }
|
|
1421
|
+
|
|
1422
|
+
// --- Modal Setup ---
|
|
1423
|
+
const modal = document.getElementById('worker-modal-${chartId}');
|
|
1424
|
+
const modalTitle = document.getElementById('worker-modal-title-${chartId}');
|
|
1425
|
+
const modalBody = document.getElementById('worker-modal-body-${chartId}');
|
|
1426
|
+
const closeModalBtn = modal.querySelector('.worker-modal-close');
|
|
1427
|
+
|
|
1428
|
+
window.${modalJsNamespace}.open = function(worker) {
|
|
1429
|
+
if (!worker) return;
|
|
1430
|
+
modalTitle.textContent = 'Test Details for ' + worker.name;
|
|
1431
|
+
|
|
1432
|
+
let testListHtml = '<ul>';
|
|
1433
|
+
if (worker.tests && worker.tests.length > 0) {
|
|
1434
|
+
worker.tests.forEach(test => {
|
|
1435
|
+
let color = 'inherit';
|
|
1436
|
+
if (test.status === 'passed') color = 'var(--success-color)';
|
|
1437
|
+
else if (test.status === 'failed') color = 'var(--danger-color)';
|
|
1438
|
+
else if (test.status === 'skipped') color = 'var(--warning-color)';
|
|
1439
|
+
|
|
1440
|
+
const escapedName = test.name.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
1441
|
+
testListHtml += \`<li style="color: \${color};"><span style="color: \${color}">[\${test.status.toUpperCase()}]</span> \${escapedName}</li>\`;
|
|
1442
|
+
});
|
|
1443
|
+
} else {
|
|
1444
|
+
testListHtml += '<li>No detailed test data available for this worker.</li>';
|
|
1445
|
+
}
|
|
1446
|
+
testListHtml += '</ul>';
|
|
1447
|
+
|
|
1448
|
+
modalBody.innerHTML = testListHtml;
|
|
1449
|
+
modal.style.display = 'flex';
|
|
1450
|
+
};
|
|
1451
|
+
|
|
1452
|
+
const closeModal = function() {
|
|
1453
|
+
modal.style.display = 'none';
|
|
1454
|
+
};
|
|
1455
|
+
|
|
1456
|
+
closeModalBtn.onclick = closeModal;
|
|
1457
|
+
modal.onclick = function(event) {
|
|
1458
|
+
// Close if clicked on the dark overlay background
|
|
1459
|
+
if (event.target == modal) {
|
|
1460
|
+
closeModal();
|
|
1461
|
+
}
|
|
1462
|
+
};
|
|
1463
|
+
|
|
1464
|
+
|
|
1465
|
+
// --- Highcharts Setup ---
|
|
1466
|
+
if (typeof Highcharts !== 'undefined') {
|
|
1467
|
+
try {
|
|
1468
|
+
chartContainer.innerHTML = '';
|
|
1469
|
+
const fullData = ${fullDataString};
|
|
1470
|
+
|
|
1471
|
+
const chartOptions = {
|
|
1472
|
+
chart: { type: 'bar', height: 350, backgroundColor: 'transparent' },
|
|
1473
|
+
title: { text: null },
|
|
1474
|
+
xAxis: {
|
|
1475
|
+
categories: ${categoriesString},
|
|
1476
|
+
title: { text: 'Worker ID' },
|
|
1477
|
+
labels: { style: { color: 'var(--text-color-secondary)' }}
|
|
1478
|
+
},
|
|
1479
|
+
yAxis: {
|
|
1480
|
+
min: 0,
|
|
1481
|
+
title: { text: 'Number of Tests' },
|
|
1482
|
+
labels: { style: { color: 'var(--text-color-secondary)' }},
|
|
1483
|
+
stackLabels: { enabled: true, style: { fontWeight: 'bold', color: 'var(--text-color)' } }
|
|
1484
|
+
},
|
|
1485
|
+
legend: { reversed: true, itemStyle: { fontSize: "12px", color: 'var(--text-color)' } },
|
|
1486
|
+
plotOptions: {
|
|
1487
|
+
series: {
|
|
1488
|
+
stacking: 'normal',
|
|
1489
|
+
cursor: 'pointer',
|
|
1490
|
+
point: {
|
|
1491
|
+
events: {
|
|
1492
|
+
click: function () {
|
|
1493
|
+
// 'this.x' is the index of the category
|
|
1494
|
+
const workerData = fullData[this.x];
|
|
1495
|
+
window.${modalJsNamespace}.open(workerData);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
},
|
|
1501
|
+
tooltip: {
|
|
1502
|
+
shared: true,
|
|
1503
|
+
headerFormat: '<b>{point.key}</b> (Click for details)<br/>',
|
|
1504
|
+
pointFormat: '<span style="color:{series.color}">●</span> {series.name}: <b>{point.y}</b><br/>',
|
|
1505
|
+
footerFormat: 'Total: <b>{point.total}</b>'
|
|
1506
|
+
},
|
|
1507
|
+
series: ${seriesString},
|
|
1508
|
+
credits: { enabled: false }
|
|
1509
|
+
};
|
|
1510
|
+
Highcharts.chart('${chartId}', chartOptions);
|
|
1511
|
+
} catch (e) {
|
|
1512
|
+
console.error("Error rendering chart ${chartId}:", e);
|
|
1513
|
+
chartContainer.innerHTML = '<div class="no-data">Error rendering worker distribution chart.</div>';
|
|
1514
|
+
}
|
|
1515
|
+
} else {
|
|
1516
|
+
chartContainer.innerHTML = '<div class="no-data">Charting library not available for worker distribution.</div>';
|
|
1517
|
+
}
|
|
1518
|
+
};
|
|
1519
|
+
</script>
|
|
1520
|
+
`;
|
|
1521
|
+
}
|
|
1522
|
+
const infoTooltip = `
|
|
1523
|
+
<span class="info-tooltip" style="display: inline-block; margin-left: 8px;">
|
|
1524
|
+
<span class="info-icon"
|
|
1525
|
+
style="cursor: pointer; font-size: 1.25rem;"
|
|
1526
|
+
onclick="window.workerInfoPrompt()">ℹ️</span>
|
|
1527
|
+
</span>
|
|
1528
|
+
<script>
|
|
1529
|
+
window.workerInfoPrompt = function() {
|
|
1530
|
+
const message = 'Why is worker -1 special?\\n\\n' +
|
|
1531
|
+
'Playwright assigns skipped tests to worker -1 because:\\n' +
|
|
1532
|
+
'1. They don\\'t require browser execution\\n' +
|
|
1533
|
+
'2. This keeps real workers focused on actual tests\\n' +
|
|
1534
|
+
'3. Maintains clean reporting\\n\\n' +
|
|
1535
|
+
'This is an intentional optimization by Playwright.';
|
|
1536
|
+
alert(message);
|
|
1537
|
+
}
|
|
1538
|
+
</script>
|
|
1539
|
+
`;
|
|
1275
1540
|
function generateHTML(reportData, trendData = null) {
|
|
1276
1541
|
const { run, results } = reportData;
|
|
1277
1542
|
const suitesData = getSuitesData(reportData.results || []);
|
|
@@ -1322,13 +1587,13 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1322
1587
|
step.duration
|
|
1323
1588
|
)}</span></div><div class="step-details" style="display: none;">${
|
|
1324
1589
|
step.codeLocation
|
|
1325
|
-
? `<div class="step-info"><strong>Location:</strong> ${sanitizeHTML(
|
|
1590
|
+
? `<div class="step-info code-section"><strong>Location:</strong> ${sanitizeHTML(
|
|
1326
1591
|
step.codeLocation
|
|
1327
1592
|
)}</div>`
|
|
1328
1593
|
: ""
|
|
1329
1594
|
}${
|
|
1330
1595
|
step.errorMessage
|
|
1331
|
-
? `<div class="
|
|
1596
|
+
? `<div class="test-error-summary">${
|
|
1332
1597
|
step.stackTrace
|
|
1333
1598
|
? `<div class="stack-trace">${formatPlaywrightError(
|
|
1334
1599
|
step.stackTrace
|
|
@@ -1392,13 +1657,24 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1392
1657
|
<h4>Steps</h4><div class="steps-list">${generateStepsHTML(
|
|
1393
1658
|
test.steps
|
|
1394
1659
|
)}</div>
|
|
1395
|
-
${
|
|
1396
|
-
test.stdout
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1660
|
+
${(() => {
|
|
1661
|
+
if (!test.stdout || test.stdout.length === 0)
|
|
1662
|
+
return "";
|
|
1663
|
+
// Create a unique ID for the <pre> element to target it for copying
|
|
1664
|
+
const logId = `stdout-log-${test.id || testIndex}`;
|
|
1665
|
+
return `<div class="console-output-section">
|
|
1666
|
+
<h4>Console Output (stdout)
|
|
1667
|
+
<button class="copy-btn" onclick="copyLogContent('${logId}', this)">Copy Console</button>
|
|
1668
|
+
</h4>
|
|
1669
|
+
<div class="log-wrapper">
|
|
1670
|
+
<pre id="${logId}" class="console-log stdout-log" style="background-color: #2d2d2d; color: wheat; padding: 1.25em; border-radius: 0.85em; line-height: 1.2;">${formatPlaywrightError(
|
|
1671
|
+
test.stdout
|
|
1672
|
+
.map((line) => sanitizeHTML(line))
|
|
1673
|
+
.join("\n")
|
|
1674
|
+
)}</pre>
|
|
1675
|
+
</div>
|
|
1676
|
+
</div>`;
|
|
1677
|
+
})()}
|
|
1402
1678
|
${
|
|
1403
1679
|
test.stderr && test.stderr.length > 0
|
|
1404
1680
|
? `<div class="console-output-section"><h4>Console Output (stderr)</h4><pre class="console-log stderr-log">${test.stderr
|
|
@@ -1505,6 +1781,7 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1505
1781
|
test.attachments.length === 0
|
|
1506
1782
|
)
|
|
1507
1783
|
return "";
|
|
1784
|
+
|
|
1508
1785
|
return `<div class="attachments-section"><h4>Other Attachments</h4><div class="attachments-grid">${test.attachments
|
|
1509
1786
|
.map((attachment) => {
|
|
1510
1787
|
try {
|
|
@@ -1512,27 +1789,50 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1512
1789
|
DEFAULT_OUTPUT_DIR,
|
|
1513
1790
|
attachment.path
|
|
1514
1791
|
);
|
|
1515
|
-
|
|
1792
|
+
|
|
1793
|
+
if (!fsExistsSync(attachmentPath)) {
|
|
1794
|
+
console.warn(
|
|
1795
|
+
`Attachment not found at: ${attachmentPath}`
|
|
1796
|
+
);
|
|
1516
1797
|
return `<div class="attachment-item error">Attachment not found: ${sanitizeHTML(
|
|
1517
1798
|
attachment.name
|
|
1518
1799
|
)}</div>`;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1519
1802
|
const attachmentBase64 =
|
|
1520
1803
|
readFileSync(attachmentPath).toString(
|
|
1521
1804
|
"base64"
|
|
1522
1805
|
);
|
|
1523
1806
|
const attachmentDataUri = `data:${attachment.contentType};base64,${attachmentBase64}`;
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1807
|
+
|
|
1808
|
+
return `<div class="attachment-item generic-attachment">
|
|
1809
|
+
<div class="attachment-icon">${getAttachmentIcon(
|
|
1810
|
+
attachment.contentType
|
|
1811
|
+
)}</div>
|
|
1812
|
+
<div class="attachment-caption">
|
|
1813
|
+
<span class="attachment-name" title="${sanitizeHTML(
|
|
1814
|
+
attachment.name
|
|
1815
|
+
)}">${sanitizeHTML(
|
|
1529
1816
|
attachment.name
|
|
1530
|
-
)}</span
|
|
1531
|
-
|
|
1532
|
-
|
|
1817
|
+
)}</span>
|
|
1818
|
+
<span class="attachment-type">${sanitizeHTML(
|
|
1819
|
+
attachment.contentType
|
|
1820
|
+
)}</span>
|
|
1821
|
+
</div>
|
|
1822
|
+
<div class="attachment-info">
|
|
1823
|
+
<div class="trace-actions">
|
|
1824
|
+
<a href="${attachmentDataUri}" target="_blank" class="view-full">View</a>
|
|
1825
|
+
<a href="${attachmentDataUri}" download="${sanitizeHTML(
|
|
1533
1826
|
attachment.name
|
|
1534
|
-
)}">Download</a
|
|
1827
|
+
)}">Download</a>
|
|
1828
|
+
</div>
|
|
1829
|
+
</div>
|
|
1830
|
+
</div>`;
|
|
1535
1831
|
} catch (e) {
|
|
1832
|
+
console.error(
|
|
1833
|
+
`Failed to process attachment "${attachment.name}":`,
|
|
1834
|
+
e
|
|
1835
|
+
);
|
|
1536
1836
|
return `<div class="attachment-item error">Failed to load attachment: ${sanitizeHTML(
|
|
1537
1837
|
attachment.name
|
|
1538
1838
|
)}</div>`;
|
|
@@ -1559,8 +1859,8 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1559
1859
|
<head>
|
|
1560
1860
|
<meta charset="UTF-8">
|
|
1561
1861
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1562
|
-
<link rel="icon" type="image/png" href="https://i.postimg.cc/
|
|
1563
|
-
<link rel="apple-touch-icon" href="https://i.postimg.cc/
|
|
1862
|
+
<link rel="icon" type="image/png" href="https://i.postimg.cc/v817w4sg/logo.png">
|
|
1863
|
+
<link rel="apple-touch-icon" href="https://i.postimg.cc/v817w4sg/logo.png">
|
|
1564
1864
|
<script src="https://code.highcharts.com/highcharts.js" defer></script>
|
|
1565
1865
|
<title>Playwright Pulse Report</title>
|
|
1566
1866
|
<style>
|
|
@@ -1586,7 +1886,7 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1586
1886
|
.header { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; padding-bottom: 25px; border-bottom: 1px solid var(--border-color); margin-bottom: 25px; }
|
|
1587
1887
|
.header-title { display: flex; align-items: center; gap: 15px; }
|
|
1588
1888
|
.header h1 { margin: 0; font-size: 1.85em; font-weight: 600; color: var(--primary-color); }
|
|
1589
|
-
#report-logo { height: 40px; width:
|
|
1889
|
+
#report-logo { height: 40px; width: 55px; }
|
|
1590
1890
|
.run-info { font-size: 0.9em; text-align: right; color: var(--text-color-secondary); line-height:1.5;}
|
|
1591
1891
|
.run-info strong { color: var(--text-color); }
|
|
1592
1892
|
.tabs { display: flex; border-bottom: 2px solid var(--border-color); margin-bottom: 30px; overflow-x: auto; }
|
|
@@ -1665,8 +1965,8 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1665
1965
|
.step-duration { color: var(--dark-gray-color); font-size: 0.9em; }
|
|
1666
1966
|
.step-details { display: none; padding: 14px; margin-top: 8px; background: #fdfdfd; border-radius: 6px; font-size: 0.95em; border: 1px solid var(--light-gray-color); }
|
|
1667
1967
|
.step-info { margin-bottom: 8px; }
|
|
1668
|
-
.
|
|
1669
|
-
.
|
|
1968
|
+
.test-error-summary { color: var(--danger-color); margin-top: 12px; padding: 14px; background: rgba(244,67,54,0.05); border-radius: 4px; font-size: 0.95em; border-left: 3px solid var(--danger-color); }
|
|
1969
|
+
.test-error-summary pre.stack-trace { margin-top: 10px; padding: 12px; background-color: rgba(0,0,0,0.03); border-radius: 4px; font-size:0.9em; max-height: 280px; overflow-y: auto; white-space: pre-wrap; word-break: break-all; }
|
|
1670
1970
|
.step-hook { background-color: rgba(33,150,243,0.04); border-left: 3px solid var(--info-color) !important; }
|
|
1671
1971
|
.step-hook .step-title { font-style: italic; color: var(--info-color)}
|
|
1672
1972
|
.nested-steps { margin-top: 12px; }
|
|
@@ -1716,12 +2016,13 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1716
2016
|
.download-trace:hover { background: #cbd5e0; }
|
|
1717
2017
|
.filters button.clear-filters-btn { background-color: var(--medium-gray-color); color: var(--text-color); }
|
|
1718
2018
|
.filters button.clear-filters-btn:hover { background-color: var(--dark-gray-color); color: #fff; }
|
|
2019
|
+
.copy-btn {color: var(--primary-color); background: #fefefe; border-radius: 8px; cursor: pointer; border-color: var(--primary-color); font-size: 1em; margin-left: 93%; font-weight: 600;}
|
|
1719
2020
|
@media (max-width: 1200px) { .trend-charts-row { grid-template-columns: 1fr; } }
|
|
1720
2021
|
@media (max-width: 992px) { .dashboard-bottom-row { grid-template-columns: 1fr; } .pie-chart-wrapper div[id^="pieChart-"] { max-width: 350px; margin: 0 auto; } .filters input { min-width: 180px; } .filters select { min-width: 150px; } }
|
|
1721
2022
|
@media (max-width: 768px) { body { font-size: 15px; } .container { margin: 10px; padding: 20px; } .header { flex-direction: column; align-items: flex-start; gap: 15px; } .header h1 { font-size: 1.6em; } .run-info { text-align: left; font-size:0.9em; } .tabs { margin-bottom: 25px;} .tab-button { padding: 12px 20px; font-size: 1.05em;} .dashboard-grid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 18px;} .summary-card .value {font-size: 2em;} .summary-card h3 {font-size: 0.95em;} .filters { flex-direction: column; padding: 18px; gap: 12px;} .filters input, .filters select, .filters button {width: 100%; box-sizing: border-box;} .test-case-header { flex-direction: column; align-items: flex-start; gap: 10px; padding: 14px; } .test-case-summary {gap: 10px;} .test-case-title {font-size: 1.05em;} .test-case-meta { flex-direction: row; flex-wrap: wrap; gap: 8px; margin-top: 8px;} .attachments-grid {grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 18px;} .test-history-grid {grid-template-columns: 1fr;} .pie-chart-wrapper {min-height: auto;} }
|
|
1722
|
-
@media (max-width: 480px) { body {font-size: 14px;} .container {padding: 15px;} .header h1 {font-size: 1.4em;} #report-logo { height: 35px; width:
|
|
2023
|
+
@media (max-width: 480px) { body {font-size: 14px;} .container {padding: 15px;} .header h1 {font-size: 1.4em;} #report-logo { height: 35px; width: 45px; } .tab-button {padding: 10px 15px; font-size: 1em;} .summary-card .value {font-size: 1.8em;} .attachments-grid {grid-template-columns: 1fr;} .step-item {padding-left: calc(var(--depth, 0) * 18px);} .test-case-content, .step-details {padding: 15px;} .trend-charts-row {gap: 20px;} .trend-chart {padding: 20px;} }
|
|
1723
2024
|
.trace-actions a { text-decoration: none; color: var(--primary-color); font-weight: 500; font-size: 0.9em; }
|
|
1724
|
-
.generic-attachment { text-align: center; padding: 1rem; justify-content: center;
|
|
2025
|
+
.generic-attachment { text-align: center; padding: 1rem; justify-content: center; }
|
|
1725
2026
|
.attachment-icon { font-size: 2.5rem; display: block; margin-bottom: 0.75rem; }
|
|
1726
2027
|
.attachment-caption { display: flex; flex-direction: column; align-items: center; justify-content: center; flex-grow: 1; }
|
|
1727
2028
|
.attachment-name { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
|
|
@@ -1732,7 +2033,7 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1732
2033
|
<div class="container">
|
|
1733
2034
|
<header class="header">
|
|
1734
2035
|
<div class="header-title">
|
|
1735
|
-
<img id="report-logo" src="
|
|
2036
|
+
<img id="report-logo" src="https://i.postimg.cc/v817w4sg/logo.png" alt="Report Logo">
|
|
1736
2037
|
<h1>Playwright Pulse Report</h1>
|
|
1737
2038
|
</div>
|
|
1738
2039
|
<div class="run-info"><strong>Run Date:</strong> ${formatDate(
|
|
@@ -1823,6 +2124,12 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1823
2124
|
? generateDurationTrendChart(trendData)
|
|
1824
2125
|
: '<div class="no-data">Overall trend data not available for durations.</div>'
|
|
1825
2126
|
}
|
|
2127
|
+
</div>
|
|
2128
|
+
</div>
|
|
2129
|
+
<h2 class="tab-main-title">Test Distribution by Worker ${infoTooltip}</h2>
|
|
2130
|
+
<div class="trend-charts-row">
|
|
2131
|
+
<div class="trend-chart">
|
|
2132
|
+
${generateWorkerDistributionChart(results)}
|
|
1826
2133
|
</div>
|
|
1827
2134
|
</div>
|
|
1828
2135
|
<h2 class="tab-main-title">Individual Test History</h2>
|
|
@@ -1839,7 +2146,6 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1839
2146
|
</div>
|
|
1840
2147
|
<footer style="padding: 0.5rem; box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05); text-align: center; font-family: 'Segoe UI', system-ui, sans-serif;">
|
|
1841
2148
|
<div style="display: inline-flex; align-items: center; gap: 0.5rem; color: #333; font-size: 0.9rem; font-weight: 600; letter-spacing: 0.5px;">
|
|
1842
|
-
<img width="48" height="48" src="https://img.icons8.com/emoji/48/index-pointing-at-the-viewer-light-skin-tone-emoji.png" alt="index-pointing-at-the-viewer-light-skin-tone-emoji"/>
|
|
1843
2149
|
<span>Created by</span>
|
|
1844
2150
|
<a href="https://github.com/Arghajit47" target="_blank" rel="noopener noreferrer" style="color: #7737BF; font-weight: 700; font-style: italic; text-decoration: none; transition: all 0.2s ease;" onmouseover="this.style.color='#BF5C37'" onmouseout="this.style.color='#7737BF'">Arghajit Singha</a>
|
|
1845
2151
|
</div>
|
|
@@ -1854,6 +2160,21 @@ function generateHTML(reportData, trendData = null) {
|
|
|
1854
2160
|
return (ms / 1000).toFixed(1) + "s";
|
|
1855
2161
|
}
|
|
1856
2162
|
}
|
|
2163
|
+
function copyLogContent(elementId, button) {
|
|
2164
|
+
const logElement = document.getElementById(elementId);
|
|
2165
|
+
if (!logElement) {
|
|
2166
|
+
console.error('Could not find log element with ID:', elementId);
|
|
2167
|
+
return;
|
|
2168
|
+
}
|
|
2169
|
+
navigator.clipboard.writeText(logElement.innerText).then(() => {
|
|
2170
|
+
button.textContent = 'Copied!';
|
|
2171
|
+
setTimeout(() => { button.textContent = 'Copy'; }, 2000);
|
|
2172
|
+
}).catch(err => {
|
|
2173
|
+
console.error('Failed to copy log content:', err);
|
|
2174
|
+
button.textContent = 'Failed';
|
|
2175
|
+
setTimeout(() => { button.textContent = 'Copy'; }, 2000);
|
|
2176
|
+
});
|
|
2177
|
+
}
|
|
1857
2178
|
function initializeReportInteractivity() {
|
|
1858
2179
|
const tabButtons = document.querySelectorAll('.tab-button');
|
|
1859
2180
|
const tabContents = document.querySelectorAll('.tab-content');
|
|
@@ -2007,9 +2328,9 @@ function generateHTML(reportData, trendData = null) {
|
|
|
2007
2328
|
|
|
2008
2329
|
function copyErrorToClipboard(button) {
|
|
2009
2330
|
// 1. Find the main error container, which should always be present.
|
|
2010
|
-
const errorContainer = button.closest('.
|
|
2331
|
+
const errorContainer = button.closest('.test-error-summary');
|
|
2011
2332
|
if (!errorContainer) {
|
|
2012
|
-
console.error("Could not find '.
|
|
2333
|
+
console.error("Could not find '.test-error-summary' container. The report's HTML structure might have changed.");
|
|
2013
2334
|
return;
|
|
2014
2335
|
}
|
|
2015
2336
|
|