plum-e2e 2.4.1 → 2.4.2

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/app.js CHANGED
@@ -47,4 +47,11 @@ if (process.env.PLUM_MODE !== 'node') {
47
47
  app.use('/trigger', require('./routes/trigger.routes'));
48
48
  }
49
49
 
50
+ // Global JSON error handler — Express's default sends HTML, which breaks JSON clients
51
+ // eslint-disable-next-line no-unused-vars
52
+ app.use((err, req, res, next) => {
53
+ console.error(err);
54
+ res.status(err.status || 500).json({ error: err.message || 'Internal server error' });
55
+ });
56
+
50
57
  module.exports = app;
@@ -57,10 +57,10 @@ function resolveNodeUrl(url) {
57
57
  const u = new URL(url);
58
58
  if (u.hostname === 'localhost' || u.hostname === '127.0.0.1') {
59
59
  u.hostname = 'host.docker.internal';
60
- return u.toString();
61
60
  }
61
+ return u.toString().replace(/\/+$/, '');
62
62
  } catch {}
63
- return url;
63
+ return url.replace(/\/+$/, '');
64
64
  }
65
65
 
66
66
  async function fetchRunners() {
@@ -297,10 +297,12 @@ const saveReport = async ({
297
297
  browser,
298
298
  runnerName,
299
299
  runnerId,
300
- testRunId
300
+ testRunId,
301
+ forceFail = false
301
302
  }) => {
302
303
  const normTrigger = normaliseTrigger(triggerType);
303
- const { features, status } = processCucumberJson(rawCucumberJson);
304
+ const { features, status: derivedStatus } = processCucumberJson(rawCucumberJson);
305
+ const status = forceFail ? 'FAIL' : derivedStatus;
304
306
  const cronJobId = await resolveCronJobId(normTrigger);
305
307
 
306
308
  const report = await prisma.report.create({
@@ -374,7 +376,8 @@ const saveCombinedReport = async ({
374
376
  browser,
375
377
  runnerName: runners.map((r) => r.name).join(', '),
376
378
  runnerId: null,
377
- testRunId: testRunId ?? null
379
+ testRunId: testRunId ?? null,
380
+ forceFail: reports.some((r) => r === null)
378
381
  });
379
382
  };
380
383
 
@@ -25,8 +25,10 @@ const prisma = require('./prisma');
25
25
 
26
26
  const getAll = () => prisma.runner.findMany({ orderBy: { createdAt: 'asc' } });
27
27
 
28
+ const normaliseUrl = (url) => (url ?? '').replace(/\/+$/, '');
29
+
28
30
  const create = ({ name, url, token, browser = 'chromium' }) =>
29
- prisma.runner.create({ data: { name, url, token, browser } });
31
+ prisma.runner.create({ data: { name, url: normaliseUrl(url), token, browser } });
30
32
 
31
33
  async function remove(id) {
32
34
  // Scrub the deleted runner from any cron job's runnerIds string before
@@ -45,7 +47,11 @@ async function remove(id) {
45
47
  return prisma.runner.delete({ where: { id } });
46
48
  }
47
49
 
48
- const update = (id, data) => prisma.runner.update({ where: { id }, data });
50
+ const update = (id, data) =>
51
+ prisma.runner.update({
52
+ where: { id },
53
+ data: { ...data, ...(data.url && { url: normaliseUrl(data.url) }) }
54
+ });
49
55
 
50
56
  const getById = (id) => prisma.runner.findUnique({ where: { id } });
51
57
 
@@ -61,7 +67,12 @@ async function probe({ url, token }) {
61
67
  headers: { Authorization: `Bearer ${token}` },
62
68
  signal: AbortSignal.timeout(5000)
63
69
  });
64
- return { ok: res.ok, latency: Date.now() - start };
70
+ if (!res.ok) return { ok: false, error: `HTTP ${res.status}` };
71
+ const body = await res.json();
72
+ if (!body.ok || body.mode !== 'node') {
73
+ return { ok: false, error: 'URL does not point to a Plum runner node' };
74
+ }
75
+ return { ok: true, latency: Date.now() - start };
65
76
  } catch (e) {
66
77
  return { ok: false, error: e.message };
67
78
  }
@@ -714,14 +714,30 @@
714
714
  {/if}
715
715
 
716
716
  {#each cronJobs as name}
717
- <div class="run-card cron-run" transition:fly={{ x: -4, duration: 160 }}>
717
+ <a
718
+ href="/scheduled-tests"
719
+ class="run-card cron-run"
720
+ transition:fly={{ x: -4, duration: 160 }}
721
+ >
718
722
  <span class="run-card-dot pulse-pass"></span>
719
723
  <div class="run-card-info">
720
724
  <span class="run-card-label">{name}</span>
721
725
  <span class="run-card-meta">Scheduled run</span>
722
726
  </div>
723
727
  <span class="run-card-badge cron-badge">Scheduled</span>
724
- </div>
728
+ <svg
729
+ width="13"
730
+ height="13"
731
+ viewBox="0 0 24 24"
732
+ fill="none"
733
+ stroke="currentColor"
734
+ stroke-width="2"
735
+ stroke-linecap="round"
736
+ class="run-card-arrow"
737
+ >
738
+ <line x1="5" y1="12" x2="19" y2="12" /><polyline points="12 5 19 12 12 19" />
739
+ </svg>
740
+ </a>
725
741
  {/each}
726
742
 
727
743
  {#if !anyRunning}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plum-e2e",
3
- "version": "2.4.1",
3
+ "version": "2.4.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/silverlunah/plum.git"