Files
TREK/server/tests/unit/systemNotices/registry.test.ts
T
Maurice e9090fa33c fix(notices): confine the 4.0.0 release modal to the 4.0.x line
Without an upper bound it would greet somebody who jumped 3.x straight to
4.2 with a summary of a release they skipped, and it would run alongside
the next release's own notice.

maxVersion is exclusive, so 4.1.0 covers every 4.0.x patch. Pinned in the
registry test, together with the handover from the thank-you notice: at no
version may both be active.
2026-08-22 15:48:13 +02:00

98 lines
4.2 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import semver from 'semver';
import { SYSTEM_NOTICES } from '../../../src/systemNotices/registry.js';
import { isNoticeVersionActive } from '../../../src/systemNotices/service.js';
/** Collect all actionIds registered via registerNoticeAction() in client source files. */
function collectRegisteredActionIds(): Set<string> {
const clientSrc = path.resolve(__dirname, '../../../../client/src');
const ids = new Set<string>();
const queue = [clientSrc];
while (queue.length) {
const dir = queue.pop()!;
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) { queue.push(full); continue; }
if (!entry.name.endsWith('noticeActions.ts') && !entry.name.endsWith('noticeActions.js')) continue;
const src = fs.readFileSync(full, 'utf8');
for (const m of src.matchAll(/registerNoticeAction\(\s*['"]([^'"]+)['"]/g)) {
ids.add(m[1]);
}
}
}
return ids;
}
describe('registry integrity', () => {
it('has no duplicate ids', () => {
const ids = SYSTEM_NOTICES.map(n => n.id);
expect(new Set(ids).size).toBe(ids.length);
});
it('all action CTAs reference a registered actionId', () => {
const registeredActionIds = collectRegisteredActionIds();
const actionCtaIds = SYSTEM_NOTICES
.filter(n => n.cta?.kind === 'action')
.map(n => (n.cta as { actionId: string }).actionId);
for (const id of actionCtaIds) {
expect(registeredActionIds, `actionId "${id}" not found in any client noticeActions.ts`).toContain(id);
}
});
it('all publishedAt are valid ISO dates', () => {
for (const n of SYSTEM_NOTICES) {
expect(() => new Date(n.publishedAt).toISOString()).not.toThrow();
}
});
it('minVersion and maxVersion are valid semver when set, and minVersion <= maxVersion when both set', () => {
for (const n of SYSTEM_NOTICES) {
if (n.minVersion !== undefined) {
expect(semver.valid(n.minVersion), `notice "${n.id}" has invalid minVersion "${n.minVersion}"`).not.toBeNull();
}
if (n.maxVersion !== undefined) {
expect(semver.valid(n.maxVersion), `notice "${n.id}" has invalid maxVersion "${n.maxVersion}"`).not.toBeNull();
}
if (n.minVersion && n.maxVersion) {
expect(
semver.lte(n.minVersion, n.maxVersion),
`notice "${n.id}": minVersion ${n.minVersion} > maxVersion ${n.maxVersion}`
).toBe(true);
}
}
});
it('the 4.0.0 release notice is confined to the 4.0.x line', () => {
const release = SYSTEM_NOTICES.find(n => n.id === 'release-4-0-0');
expect(release).toBeDefined();
// Its copy is about this release, so it must not greet somebody who skipped
// straight past it, and it must not run alongside the next release's notice.
expect(isNoticeVersionActive(release!, '3.4.1')).toBe(false);
expect(isNoticeVersionActive(release!, '4.0.0')).toBe(true);
expect(isNoticeVersionActive(release!, '4.0.7')).toBe(true);
// The upper bound is exclusive, so every 4.0.x patch still gets it.
expect(isNoticeVersionActive(release!, '4.0.9')).toBe(true);
expect(isNoticeVersionActive(release!, '4.0.12')).toBe(true);
expect(isNoticeVersionActive(release!, '4.1.0')).toBe(false);
expect(isNoticeVersionActive(release!, '4.2.0')).toBe(false);
});
it('the thank-you notice hands over to the release modal at 4.0.0', () => {
const thankYou = SYSTEM_NOTICES.find(n => n.id === 'thank-you-support');
expect(thankYou).toBeDefined();
// Both carry the same thank-you and the same two support links, so exactly
// one of them may be active at any version.
expect(isNoticeVersionActive(thankYou!, '3.4.1')).toBe(true);
expect(isNoticeVersionActive(thankYou!, '4.0.0')).toBe(false);
const release = SYSTEM_NOTICES.find(n => n.id === 'release-4-0-0')!;
for (const version of ['3.4.1', '4.0.0', '4.0.7', '4.1.0', '5.0.0']) {
const active = [thankYou!, release].filter(n => isNoticeVersionActive(n, version));
expect(active.length, `both thank-you notices active at ${version}`).toBeLessThanOrEqual(1);
}
});
});