plum-e2e 2.8.6 → 2.9.0
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/backend/_scaffold/utils/browser.ts +184 -30
- package/backend/_scaffold/utils/hooks.ts +37 -8
- package/backend/app.js +0 -5
- package/backend/config/scripts/generate-report.js +2 -2
- package/backend/constants/socketEvents.js +7 -4
- package/backend/lib/reportFilename.js +1 -2
- package/backend/lib/{screenshotPoller.js → rrwebPoller.js} +7 -4
- package/backend/lib/serverBootstrap.js +14 -0
- package/backend/logs/runner-cmtbz5b1l0000mr0110b27w5k.log +8 -0
- package/backend/mcp/server.js +3 -47
- package/backend/package-lock.json +199 -1
- package/backend/package.json +3 -1
- package/backend/prisma/migrations/20260828120000_add_recording_and_split_runner_worker_count/migration.sql +39 -0
- package/backend/prisma/migrations/20260828140000_add_recording_started_ended_at/migration.sql +5 -0
- package/backend/prisma/migrations/20260828150000_strip_screenshot_refs_from_reports/migration.sql +34 -0
- package/backend/prisma/migrations/20260828160000_add_backup_include_reports/migration.sql +4 -0
- package/backend/prisma/schema.prisma +97 -70
- package/backend/routes/backup.routes.js +47 -1
- package/backend/routes/reports.routes.js +23 -0
- package/backend/server.js +1 -1
- package/backend/services/backupCronService.js +1 -1
- package/backend/services/backupService.js +134 -44
- package/backend/services/cronService.js +23 -15
- package/backend/services/nodeExecutionService.js +41 -15
- package/backend/services/nodeStreamRegistry.js +24 -0
- package/backend/services/reportService.js +167 -83
- package/backend/services/runnerService.js +19 -7
- package/backend/services/settingsService.js +6 -3
- package/backend/services/triggerService.js +20 -13
- package/backend/websockets/nodeSocketHandler.js +40 -0
- package/backend/websockets/socketHandler.js +9 -7
- package/frontend/.svelte-kit/generated/server/internal.js +1 -1
- package/frontend/package-lock.json +121 -32
- package/frontend/package.json +1 -0
- package/frontend/src/lib/api/reports.js +13 -4
- package/frontend/src/lib/api/settings.js +16 -1
- package/frontend/src/lib/components/layout/RunnerPanel.svelte +9 -24
- package/frontend/src/lib/components/reports/ElementInspector.svelte +141 -0
- package/frontend/src/lib/components/reports/LiveReplayer.svelte +110 -0
- package/frontend/src/lib/components/reports/MultiTabTimeline.svelte +115 -0
- package/frontend/src/lib/components/reports/RecordingPlayer.svelte +786 -0
- package/frontend/src/lib/components/reports/StepsRail.svelte +109 -0
- package/frontend/src/lib/components/ui/CodeViewer.svelte +61 -0
- package/frontend/src/lib/constants.js +0 -1
- package/frontend/src/lib/copy/reports.js +18 -8
- package/frontend/src/lib/copy/settings.js +25 -4
- package/frontend/src/lib/socketEvents.js +7 -4
- package/frontend/src/lib/stores/runner.js +26 -3
- package/frontend/src/lib/styles/tokens.css +7 -0
- package/frontend/src/lib/utils/format.js +108 -2
- package/frontend/src/lib/utils/inspectElement.js +34 -0
- package/frontend/src/routes/reports/+page.svelte +79 -1
- package/frontend/src/routes/reports/[id]/+page.svelte +304 -495
- package/frontend/src/routes/reports/live/+page.svelte +236 -260
- package/frontend/src/routes/settings/+page.svelte +246 -8
- package/package.json +1 -1
- package/backend/playwright.config.js +0 -85
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
saveBackupConfig,
|
|
19
19
|
testBackupS3,
|
|
20
20
|
runBackupNow,
|
|
21
|
+
fetchS3Backups,
|
|
22
|
+
restoreFromS3,
|
|
21
23
|
fetchMcpConfig,
|
|
22
24
|
generateMcpKey as generateMcpKeyApi
|
|
23
25
|
} from '$lib/api/settings';
|
|
@@ -214,8 +216,10 @@
|
|
|
214
216
|
IMPORT_BLOCK_TITLE,
|
|
215
217
|
IMPORT_BLOCK_DESC,
|
|
216
218
|
CHOOSE_FILE_LABEL,
|
|
217
|
-
|
|
218
|
-
|
|
219
|
+
INCLUDE_REPORTS_LABEL,
|
|
220
|
+
INCLUDE_REPORTS_HINT,
|
|
221
|
+
includeReportsDisclaimer,
|
|
222
|
+
saveIncludeReportsLabel,
|
|
219
223
|
S3_STORAGE_CARD_TITLE,
|
|
220
224
|
S3_STORAGE_DESC_PREFIX,
|
|
221
225
|
ENDPOINT_URL_LABEL,
|
|
@@ -240,6 +244,15 @@
|
|
|
240
244
|
S3_CONNECTION_FAILED,
|
|
241
245
|
BACKUP_CONFIG_SAVED_TOAST,
|
|
242
246
|
BACKUP_CONFIG_SAVE_FAILED,
|
|
247
|
+
RESTORE_FROM_S3_CARD_TITLE,
|
|
248
|
+
RESTORE_FROM_S3_DESC,
|
|
249
|
+
CONFIGURE_S3_FIRST_RESTORE_MESSAGE,
|
|
250
|
+
NO_S3_BACKUPS_MESSAGE,
|
|
251
|
+
RESTORE_CONFIRM_TITLE,
|
|
252
|
+
restoreConfirmBody,
|
|
253
|
+
RESTORE_SUCCESS_TOAST,
|
|
254
|
+
RESTORE_FAILED_FALLBACK,
|
|
255
|
+
LIST_S3_BACKUPS_FAILED,
|
|
243
256
|
SCHEDULED_BACKUP_CARD_TITLE,
|
|
244
257
|
CONFIGURE_S3_FIRST_MESSAGE,
|
|
245
258
|
ENABLE_SCHEDULED_BACKUP_LABEL,
|
|
@@ -264,7 +277,10 @@
|
|
|
264
277
|
saveS3ConfigLabel,
|
|
265
278
|
uploadedToLabel,
|
|
266
279
|
uploadS3NowLabel,
|
|
267
|
-
saveScheduleLabel
|
|
280
|
+
saveScheduleLabel,
|
|
281
|
+
restoreLabel,
|
|
282
|
+
refreshingLabel,
|
|
283
|
+
backupSizeLabel
|
|
268
284
|
} from '$lib/copy/settings';
|
|
269
285
|
|
|
270
286
|
/** @type {'project' | 'runners' | 'repository' | 'integrations' | 'mcp' | 'account' | 'users' | 'backup'} */
|
|
@@ -335,9 +351,11 @@
|
|
|
335
351
|
backupS3Bucket: '',
|
|
336
352
|
backupS3AccessKey: '',
|
|
337
353
|
backupS3SecretKey: '',
|
|
338
|
-
backupS3Prefix: ''
|
|
354
|
+
backupS3Prefix: '',
|
|
355
|
+
backupIncludeReports: false
|
|
339
356
|
};
|
|
340
357
|
let backupConfigSaving = false;
|
|
358
|
+
let includeReportsSaving = false;
|
|
341
359
|
let backupS3SecretKeySet = false;
|
|
342
360
|
let backupTestingS3 = false;
|
|
343
361
|
let backupRunningNow = false;
|
|
@@ -346,6 +364,13 @@
|
|
|
346
364
|
let backupLastRunAt = null;
|
|
347
365
|
let backupLastStatus = '';
|
|
348
366
|
|
|
367
|
+
let s3Backups = [];
|
|
368
|
+
let s3BackupsLoaded = false;
|
|
369
|
+
let loadingS3Backups = false;
|
|
370
|
+
let restoringKey = null;
|
|
371
|
+
let restoreConfirmOpen = false;
|
|
372
|
+
let restoreTarget = null;
|
|
373
|
+
|
|
349
374
|
let runners = [];
|
|
350
375
|
let runnerForm = { name: '', url: '', token: '', browser: 'chromium' };
|
|
351
376
|
let runnerFormError = '';
|
|
@@ -406,7 +431,8 @@
|
|
|
406
431
|
backupS3Bucket: bc.backupS3Bucket,
|
|
407
432
|
backupS3AccessKey: bc.backupS3AccessKey,
|
|
408
433
|
backupS3SecretKey: '',
|
|
409
|
-
backupS3Prefix: bc.backupS3Prefix
|
|
434
|
+
backupS3Prefix: bc.backupS3Prefix,
|
|
435
|
+
backupIncludeReports: bc.backupIncludeReports
|
|
410
436
|
};
|
|
411
437
|
} catch {}
|
|
412
438
|
if ($auth.user) {
|
|
@@ -802,6 +828,23 @@
|
|
|
802
828
|
}
|
|
803
829
|
}
|
|
804
830
|
|
|
831
|
+
async function handleSaveIncludeReports() {
|
|
832
|
+
includeReportsSaving = true;
|
|
833
|
+
try {
|
|
834
|
+
const payload = { ...backupConfig };
|
|
835
|
+
if (!payload.backupS3SecretKey) delete payload.backupS3SecretKey;
|
|
836
|
+
const result = await saveBackupConfig(payload);
|
|
837
|
+
if (result.error) throw new Error(result.error);
|
|
838
|
+
if (backupConfig.backupS3SecretKey) backupS3SecretKeySet = true;
|
|
839
|
+
backupConfig = { ...backupConfig, backupS3SecretKey: '' };
|
|
840
|
+
showToast('success', BACKUP_CONFIG_SAVED_TOAST);
|
|
841
|
+
} catch (e) {
|
|
842
|
+
showToast('error', e.message || BACKUP_CONFIG_SAVE_FAILED);
|
|
843
|
+
} finally {
|
|
844
|
+
includeReportsSaving = false;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
805
848
|
async function handleTestS3() {
|
|
806
849
|
backupTestingS3 = true;
|
|
807
850
|
backupS3TestResult = null;
|
|
@@ -845,6 +888,48 @@
|
|
|
845
888
|
backupS3SecretKeySet
|
|
846
889
|
);
|
|
847
890
|
|
|
891
|
+
// Fetch the list once, the first time S3 looks configured — the Refresh
|
|
892
|
+
// button covers reloading after a new upload or a bucket/prefix change.
|
|
893
|
+
$: if (s3Configured && !s3BackupsLoaded) {
|
|
894
|
+
s3BackupsLoaded = true;
|
|
895
|
+
loadS3Backups();
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
async function loadS3Backups() {
|
|
899
|
+
loadingS3Backups = true;
|
|
900
|
+
try {
|
|
901
|
+
const result = await fetchS3Backups();
|
|
902
|
+
if (result.error) throw new Error(result.error);
|
|
903
|
+
s3Backups = result.backups ?? [];
|
|
904
|
+
} catch (e) {
|
|
905
|
+
showToast('error', e.message || LIST_S3_BACKUPS_FAILED);
|
|
906
|
+
} finally {
|
|
907
|
+
loadingS3Backups = false;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
function openRestoreConfirm(backup) {
|
|
912
|
+
restoreTarget = backup;
|
|
913
|
+
restoreConfirmOpen = true;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
async function handleRestoreFromS3() {
|
|
917
|
+
if (!restoreTarget) return;
|
|
918
|
+
restoringKey = restoreTarget.key;
|
|
919
|
+
try {
|
|
920
|
+
const result = await restoreFromS3(restoreTarget.key);
|
|
921
|
+
if (result.error) throw new Error(result.error);
|
|
922
|
+
showToast('success', RESTORE_SUCCESS_TOAST);
|
|
923
|
+
project = await fetchProject();
|
|
924
|
+
restoreConfirmOpen = false;
|
|
925
|
+
restoreTarget = null;
|
|
926
|
+
} catch (e) {
|
|
927
|
+
showToast('error', e.message || RESTORE_FAILED_FALLBACK);
|
|
928
|
+
} finally {
|
|
929
|
+
restoringKey = null;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
848
933
|
$: mcpConfigSnippet = JSON.stringify(
|
|
849
934
|
{
|
|
850
935
|
mcpServers: {
|
|
@@ -1822,10 +1907,36 @@
|
|
|
1822
1907
|
</div>
|
|
1823
1908
|
</div>
|
|
1824
1909
|
</div>
|
|
1910
|
+
|
|
1911
|
+
<div class="include-reports-row">
|
|
1912
|
+
<label class="field-label backup-toggle-label" for="include-reports">
|
|
1913
|
+
<span>
|
|
1914
|
+
{INCLUDE_REPORTS_LABEL}
|
|
1915
|
+
<span class="field-hint">{INCLUDE_REPORTS_HINT}</span>
|
|
1916
|
+
</span>
|
|
1917
|
+
<button
|
|
1918
|
+
id="include-reports"
|
|
1919
|
+
class="toggle-btn"
|
|
1920
|
+
class:active={backupConfig.backupIncludeReports}
|
|
1921
|
+
on:click={() =>
|
|
1922
|
+
(backupConfig.backupIncludeReports = !backupConfig.backupIncludeReports)}
|
|
1923
|
+
role="switch"
|
|
1924
|
+
aria-checked={backupConfig.backupIncludeReports}
|
|
1925
|
+
>
|
|
1926
|
+
<span class="toggle-thumb"></span>
|
|
1927
|
+
</button>
|
|
1928
|
+
</label>
|
|
1929
|
+
<Button
|
|
1930
|
+
variant="ghost"
|
|
1931
|
+
on:click={handleSaveIncludeReports}
|
|
1932
|
+
disabled={includeReportsSaving}
|
|
1933
|
+
>
|
|
1934
|
+
{saveIncludeReportsLabel(includeReportsSaving)}
|
|
1935
|
+
</Button>
|
|
1936
|
+
</div>
|
|
1937
|
+
|
|
1825
1938
|
<p class="backup-disclaimer">
|
|
1826
|
-
{
|
|
1827
|
-
<code>pg_dump</code>
|
|
1828
|
-
{BACKUP_DISCLAIMER_SUFFIX}
|
|
1939
|
+
{includeReportsDisclaimer(backupConfig.backupIncludeReports)}
|
|
1829
1940
|
</p>
|
|
1830
1941
|
</div>
|
|
1831
1942
|
|
|
@@ -1947,6 +2058,64 @@
|
|
|
1947
2058
|
{/if}
|
|
1948
2059
|
</div>
|
|
1949
2060
|
|
|
2061
|
+
<!-- Restore from S3 -->
|
|
2062
|
+
<ConfirmModal
|
|
2063
|
+
bind:open={restoreConfirmOpen}
|
|
2064
|
+
title={RESTORE_CONFIRM_TITLE}
|
|
2065
|
+
confirmLabel={restoreLabel(false)}
|
|
2066
|
+
loading={!!restoringKey}
|
|
2067
|
+
on:confirm={handleRestoreFromS3}
|
|
2068
|
+
>
|
|
2069
|
+
{#if restoreTarget}
|
|
2070
|
+
{restoreConfirmBody(restoreTarget.key)}
|
|
2071
|
+
{/if}
|
|
2072
|
+
</ConfirmModal>
|
|
2073
|
+
|
|
2074
|
+
<div class="card settings-card" class:card-disabled={!s3Configured}>
|
|
2075
|
+
<div class="card-title-row">
|
|
2076
|
+
<p class="card-title">{RESTORE_FROM_S3_CARD_TITLE}</p>
|
|
2077
|
+
{#if s3Configured}
|
|
2078
|
+
<Button variant="ghost" on:click={loadS3Backups} disabled={loadingS3Backups}>
|
|
2079
|
+
{refreshingLabel(loadingS3Backups)}
|
|
2080
|
+
</Button>
|
|
2081
|
+
{/if}
|
|
2082
|
+
</div>
|
|
2083
|
+
|
|
2084
|
+
{#if !s3Configured}
|
|
2085
|
+
<p class="backup-block-desc">{CONFIGURE_S3_FIRST_RESTORE_MESSAGE}</p>
|
|
2086
|
+
{:else}
|
|
2087
|
+
<p class="backup-block-desc" style="margin-bottom: 1rem;">{RESTORE_FROM_S3_DESC}</p>
|
|
2088
|
+
|
|
2089
|
+
{#if s3Backups.length === 0}
|
|
2090
|
+
<p class="backup-block-desc">
|
|
2091
|
+
{loadingS3Backups ? refreshingLabel(true) : NO_S3_BACKUPS_MESSAGE}
|
|
2092
|
+
</p>
|
|
2093
|
+
{:else}
|
|
2094
|
+
<ul class="s3-backup-list">
|
|
2095
|
+
{#each s3Backups as backup (backup.key)}
|
|
2096
|
+
<li class="s3-backup-row">
|
|
2097
|
+
<div class="s3-backup-info">
|
|
2098
|
+
<span class="s3-backup-key">{backup.key}</span>
|
|
2099
|
+
<span class="s3-backup-meta">
|
|
2100
|
+
{new Date(backup.lastModified).toLocaleString()} · {backupSizeLabel(
|
|
2101
|
+
backup.size
|
|
2102
|
+
)}
|
|
2103
|
+
</span>
|
|
2104
|
+
</div>
|
|
2105
|
+
<Button
|
|
2106
|
+
variant="ghost"
|
|
2107
|
+
on:click={() => openRestoreConfirm(backup)}
|
|
2108
|
+
disabled={restoringKey === backup.key}
|
|
2109
|
+
>
|
|
2110
|
+
{restoreLabel(restoringKey === backup.key)}
|
|
2111
|
+
</Button>
|
|
2112
|
+
</li>
|
|
2113
|
+
{/each}
|
|
2114
|
+
</ul>
|
|
2115
|
+
{/if}
|
|
2116
|
+
{/if}
|
|
2117
|
+
</div>
|
|
2118
|
+
|
|
1950
2119
|
<!-- Scheduled backup -->
|
|
1951
2120
|
<div class="card settings-card" class:card-disabled={!s3Configured}>
|
|
1952
2121
|
<p class="card-title">{SCHEDULED_BACKUP_CARD_TITLE}</p>
|
|
@@ -2390,6 +2559,23 @@
|
|
|
2390
2559
|
border-radius: 3px;
|
|
2391
2560
|
}
|
|
2392
2561
|
|
|
2562
|
+
.include-reports-row {
|
|
2563
|
+
display: flex;
|
|
2564
|
+
align-items: center;
|
|
2565
|
+
gap: 1.25rem;
|
|
2566
|
+
margin-top: 1.25rem;
|
|
2567
|
+
padding-top: 1.25rem;
|
|
2568
|
+
border-top: 1px solid var(--border);
|
|
2569
|
+
}
|
|
2570
|
+
.include-reports-row .backup-toggle-label {
|
|
2571
|
+
flex: 1;
|
|
2572
|
+
}
|
|
2573
|
+
.include-reports-row .field-label > span {
|
|
2574
|
+
display: flex;
|
|
2575
|
+
flex-direction: column;
|
|
2576
|
+
gap: 0.15rem;
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2393
2579
|
.backup-disclaimer {
|
|
2394
2580
|
margin-top: 1rem;
|
|
2395
2581
|
padding: 0.625rem 0.875rem;
|
|
@@ -2422,6 +2608,58 @@
|
|
|
2422
2608
|
color: var(--fail);
|
|
2423
2609
|
}
|
|
2424
2610
|
|
|
2611
|
+
.card-title-row {
|
|
2612
|
+
display: flex;
|
|
2613
|
+
align-items: center;
|
|
2614
|
+
justify-content: space-between;
|
|
2615
|
+
gap: 1rem;
|
|
2616
|
+
margin-bottom: 0.75rem;
|
|
2617
|
+
}
|
|
2618
|
+
.card-title-row .card-title {
|
|
2619
|
+
margin-bottom: 0;
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2622
|
+
.s3-backup-list {
|
|
2623
|
+
display: flex;
|
|
2624
|
+
flex-direction: column;
|
|
2625
|
+
gap: 0.5rem;
|
|
2626
|
+
list-style: none;
|
|
2627
|
+
margin: 0;
|
|
2628
|
+
padding: 0;
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2631
|
+
.s3-backup-row {
|
|
2632
|
+
display: flex;
|
|
2633
|
+
align-items: center;
|
|
2634
|
+
justify-content: space-between;
|
|
2635
|
+
gap: 1rem;
|
|
2636
|
+
padding: 0.625rem 0.875rem;
|
|
2637
|
+
background: var(--bg-subtle);
|
|
2638
|
+
border: 1px solid var(--border);
|
|
2639
|
+
border-radius: var(--radius-sm);
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
.s3-backup-info {
|
|
2643
|
+
display: flex;
|
|
2644
|
+
flex-direction: column;
|
|
2645
|
+
gap: 0.2rem;
|
|
2646
|
+
min-width: 0;
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
.s3-backup-key {
|
|
2650
|
+
font-family: 'JetBrains Mono', monospace;
|
|
2651
|
+
font-size: 0.8125rem;
|
|
2652
|
+
color: var(--text);
|
|
2653
|
+
overflow: hidden;
|
|
2654
|
+
text-overflow: ellipsis;
|
|
2655
|
+
white-space: nowrap;
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
.s3-backup-meta {
|
|
2659
|
+
font-size: 0.75rem;
|
|
2660
|
+
color: var(--text-muted);
|
|
2661
|
+
}
|
|
2662
|
+
|
|
2425
2663
|
.backup-last-run {
|
|
2426
2664
|
font-size: 0.8125rem;
|
|
2427
2665
|
color: var(--text-muted);
|
package/package.json
CHANGED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This file is part of Plum.
|
|
3
|
-
* Licensed under the MIT License. See LICENSE file in the project root for details.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// @ts-check
|
|
7
|
-
import { defineConfig, devices } from '@playwright/test';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Read environment variables from file.
|
|
11
|
-
* https://github.com/motdotla/dotenv
|
|
12
|
-
*/
|
|
13
|
-
import dotenv from 'dotenv';
|
|
14
|
-
import path from 'path';
|
|
15
|
-
dotenv.config({ path: path.resolve(__dirname, '.env') });
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @see https://playwright.dev/docs/test-configuration
|
|
19
|
-
*/
|
|
20
|
-
export default defineConfig({
|
|
21
|
-
testDir: './tests',
|
|
22
|
-
/* Run tests in files in parallel */
|
|
23
|
-
fullyParallel: true,
|
|
24
|
-
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
|
25
|
-
forbidOnly: !!process.env.CI,
|
|
26
|
-
/* Retry on CI only */
|
|
27
|
-
retries: process.env.CI ? 2 : 0,
|
|
28
|
-
/* Opt out of parallel tests on CI. */
|
|
29
|
-
workers: process.env.CI ? 1 : undefined,
|
|
30
|
-
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
31
|
-
reporter: 'html',
|
|
32
|
-
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
33
|
-
use: {
|
|
34
|
-
/* Base URL to use in actions like `await page.goto('/')`. */
|
|
35
|
-
// baseURL: 'http://127.0.0.1:3000',
|
|
36
|
-
|
|
37
|
-
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
|
38
|
-
trace: 'on-first-retry'
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
/* Configure projects for major browsers */
|
|
42
|
-
projects: [
|
|
43
|
-
{
|
|
44
|
-
name: 'chromium',
|
|
45
|
-
use: { ...devices['Desktop Chrome'] }
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
{
|
|
49
|
-
name: 'firefox',
|
|
50
|
-
use: { ...devices['Desktop Firefox'] }
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
{
|
|
54
|
-
name: 'webkit',
|
|
55
|
-
use: { ...devices['Desktop Safari'] }
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/* Test against mobile viewports. */
|
|
59
|
-
// {
|
|
60
|
-
// name: 'Mobile Chrome',
|
|
61
|
-
// use: { ...devices['Pixel 5'] },
|
|
62
|
-
// },
|
|
63
|
-
// {
|
|
64
|
-
// name: 'Mobile Safari',
|
|
65
|
-
// use: { ...devices['iPhone 12'] },
|
|
66
|
-
// },
|
|
67
|
-
|
|
68
|
-
/* Test against branded browsers. */
|
|
69
|
-
// {
|
|
70
|
-
// name: 'Microsoft Edge',
|
|
71
|
-
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
|
72
|
-
// },
|
|
73
|
-
// {
|
|
74
|
-
// name: 'Google Chrome',
|
|
75
|
-
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
|
76
|
-
// },
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
/* Run your local dev server before starting the tests */
|
|
80
|
-
// webServer: {
|
|
81
|
-
// command: 'npm run start',
|
|
82
|
-
// url: 'http://127.0.0.1:3000',
|
|
83
|
-
// reuseExistingServer: !process.env.CI,
|
|
84
|
-
// },
|
|
85
|
-
});
|