plum-e2e 2.5.5 → 2.5.7
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.
|
@@ -159,7 +159,15 @@ function prepareEnv() {
|
|
|
159
159
|
fs.writeFileSync(markerPath, currentVersion, 'utf8');
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
|
|
162
|
+
// --with-deps also installs the OS-level shared libraries (libnss3, libatk,
|
|
163
|
+
// etc.) Chromium/Firefox need to actually launch — without it, a fresh
|
|
164
|
+
// Linux host has the browser binaries but fails at launch time with
|
|
165
|
+
// "Host system is missing dependencies to run browsers."
|
|
166
|
+
execSync('npx playwright install --with-deps chromium firefox', {
|
|
167
|
+
cwd: BACKEND_DIR,
|
|
168
|
+
stdio,
|
|
169
|
+
shell: true
|
|
170
|
+
});
|
|
163
171
|
}
|
|
164
172
|
|
|
165
173
|
/**
|
package/bin/plum.js
CHANGED
|
@@ -460,10 +460,41 @@ async function serverRestart() {
|
|
|
460
460
|
clack.outro(pc.green('Server restarted.'));
|
|
461
461
|
}
|
|
462
462
|
|
|
463
|
+
// A fresh `npm publish` can take a minute or two to fully propagate across
|
|
464
|
+
// npm's CDN edges — hitting a stale one right after publishing produces an
|
|
465
|
+
// ETARGET error even though the version genuinely exists. Retry a few times
|
|
466
|
+
// with a short delay instead of crashing outright on what's usually transient.
|
|
467
|
+
const NPM_INSTALL_RETRIES = 3;
|
|
468
|
+
const NPM_INSTALL_RETRY_DELAY_MS = 5000;
|
|
469
|
+
|
|
470
|
+
function npmInstallLatestWithRetry() {
|
|
471
|
+
for (let attempt = 1; attempt <= NPM_INSTALL_RETRIES; attempt++) {
|
|
472
|
+
try {
|
|
473
|
+
execSync('npm install -g plum-e2e@latest', { stdio: 'inherit' });
|
|
474
|
+
return true;
|
|
475
|
+
} catch {
|
|
476
|
+
if (attempt < NPM_INSTALL_RETRIES) {
|
|
477
|
+
clack.log.warn(
|
|
478
|
+
`npm install failed (attempt ${attempt}/${NPM_INSTALL_RETRIES}) — this is often a transient registry propagation delay right after a new release. Retrying in ${NPM_INSTALL_RETRY_DELAY_MS / 1000}s…`
|
|
479
|
+
);
|
|
480
|
+
execSync(`sleep ${NPM_INSTALL_RETRY_DELAY_MS / 1000}`);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
|
|
463
487
|
async function serverUpdate() {
|
|
464
488
|
clack.intro(pc.bgMagenta(pc.white(' 🟣 Plum — Update ')));
|
|
465
489
|
clack.log.step('Fetching latest Plum version…');
|
|
466
|
-
|
|
490
|
+
if (!npmInstallLatestWithRetry()) {
|
|
491
|
+
clack.log.error(
|
|
492
|
+
`Failed to install the latest version after ${NPM_INSTALL_RETRIES} attempts. Try again shortly, or run "npm install -g plum-e2e@latest" manually to see the full error.`
|
|
493
|
+
);
|
|
494
|
+
clack.outro(pc.red('Update failed.'));
|
|
495
|
+
process.exitCode = 1;
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
467
498
|
clack.log.success('Plum CLI updated.');
|
|
468
499
|
|
|
469
500
|
const serverCfgPath = path.join(process.cwd(), '.plum-server.json');
|
|
@@ -123,7 +123,9 @@
|
|
|
123
123
|
runnerConfig.update((c) => {
|
|
124
124
|
if (!v && c.selectedRunners.includes(BUILTIN_RUNNER_ID)) {
|
|
125
125
|
const others = c.selectedRunners.filter((r) => r !== BUILTIN_RUNNER_ID);
|
|
126
|
-
|
|
126
|
+
const fallback =
|
|
127
|
+
others.length > 0 ? others : availableRunners[0] ? [availableRunners[0].id] : [];
|
|
128
|
+
return { ...c, selectedRunners: fallback };
|
|
127
129
|
}
|
|
128
130
|
return c;
|
|
129
131
|
});
|
|
@@ -601,7 +603,7 @@
|
|
|
601
603
|
</button>
|
|
602
604
|
{#if runnersOpen}
|
|
603
605
|
<div class="dropdown-menu runners-menu" transition:fly={{ y: 6, duration: 130 }}>
|
|
604
|
-
{#if $builtInEnabled}
|
|
606
|
+
{#if $builtInEnabled || isRunnerSelected(BUILTIN_RUNNER_ID)}
|
|
605
607
|
<label class="runner-option">
|
|
606
608
|
<input
|
|
607
609
|
type="checkbox"
|
|
@@ -73,13 +73,24 @@ export function keywordClass(kw) {
|
|
|
73
73
|
return 'kw-and';
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
// Matches both verbose tags (@test-login-1, @suite-login) and the TC-/TS-
|
|
77
|
+
// displayId convention (@TC-001, @TS-001) used by default throughout the rest
|
|
78
|
+
// of the app (test case/suite prefixes, configurable in Settings).
|
|
79
|
+
function isSuiteTag(tag) {
|
|
80
|
+
return /suite/i.test(tag) || /^@ts-?\d+/i.test(tag);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isTestCaseTag(tag) {
|
|
84
|
+
return /^@test[\w-]*/i.test(tag) || /^@tc-?\d+/i.test(tag);
|
|
85
|
+
}
|
|
86
|
+
|
|
76
87
|
export function scenarioTestTag(scenario) {
|
|
77
|
-
return scenario.tags?.find(
|
|
88
|
+
return scenario.tags?.find(isTestCaseTag) ?? null;
|
|
78
89
|
}
|
|
79
90
|
|
|
80
91
|
export function featureSuiteTag(feature) {
|
|
81
92
|
for (const scenario of feature.scenarios ?? []) {
|
|
82
|
-
const suiteTag = scenario.tags?.find(
|
|
93
|
+
const suiteTag = scenario.tags?.find(isSuiteTag);
|
|
83
94
|
if (suiteTag) return suiteTag;
|
|
84
95
|
}
|
|
85
96
|
return null;
|
|
@@ -88,7 +99,7 @@ export function featureSuiteTag(feature) {
|
|
|
88
99
|
export function visibleTags(scenario) {
|
|
89
100
|
const testTag = scenarioTestTag(scenario);
|
|
90
101
|
if (testTag) return [testTag];
|
|
91
|
-
return (scenario.tags ?? []).filter((tag) =>
|
|
102
|
+
return (scenario.tags ?? []).filter((tag) => !isSuiteTag(tag));
|
|
92
103
|
}
|
|
93
104
|
|
|
94
105
|
const STATUS_RANK = { failed: 3, pending: 2, skipped: 1, passed: 0 };
|