Skip to content

Commit 6a30bcf

Browse files
committed
test(cli): wait for the serve banner's last line before reading its plugin list
Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU Co-Authored-By: Claude <noreply@anthropic.com>
1 parent b440182 commit 6a30bcf

1 file changed

Lines changed: 10 additions & 7 deletions

File tree

‎packages/cli/test/serve-package-declared-capabilities.test.ts‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,12 @@ import { join } from 'node:path';
4747
import { randomPort, runServe } from './helpers/serve-process.js';
4848
import { linkSpec } from './helpers/define-stack-fixture.js';
4949

50+
/** The ready line. The banner it opens (`Plugins: N loaded`, `Flows:`) prints AFTER it. */
5051
const READY = /Server is ready/;
51-
/** A boot that ends either way: the banner, or a fatal `✗` line before the child exits. */
52-
const READY_OR_FATAL = /Server is ready|✗ [^\n]+\n/;
52+
/** The banner's LAST line: wait for it, or the plugin list and the flow line are not printed yet. */
53+
const BANNER_END = /Press Ctrl\+C to stop/;
54+
/** A boot that ends either way: the whole banner, or a fatal `✗` line before the child exits. */
55+
const BANNER_END_OR_FATAL = /Press Ctrl\+C to stop|✗ [^\n]+\n/;
5356

5457
/** The definitions every fixture shares, as module source. */
5558
const PIECES = `
@@ -117,27 +120,27 @@ const boot = async (name: string, waitFor: RegExp, extra: string[] = []) => {
117120

118121
describe('#22288 — `requires` a package declares mounts its provider at boot', () => {
119122
it('two packages: the service package\'s `automation` is mounted', async () => {
120-
const out = await boot('automationTwo', READY);
123+
const out = await boot('automationTwo', BANNER_END);
121124
expect(out).toMatch(READY);
122125
expect(bannerPlugins(out)).toContain('AutomationServicePlugin');
123126
}, 180_000);
124127

125128
it('control, one package: the same `requires` mounts the same provider', async () => {
126-
const out = await boot('automationOne', READY);
129+
const out = await boot('automationOne', BANNER_END);
127130
expect(out).toMatch(READY);
128131
expect(bannerPlugins(out)).toContain('AutomationServicePlugin');
129132
}, 180_000);
130133

131134
it('two packages, a declared capability with no provider: the boot refuses, as one package always has', async () => {
132-
const out = await boot('aiTwo', READY_OR_FATAL);
135+
const out = await boot('aiTwo', BANNER_END_OR_FATAL);
133136
expect(out).not.toMatch(READY);
134137
expect(out).toMatch(/✗ Capability "ai"/);
135138
}, 180_000);
136139
});
137140

138141
describe('#22288 — the other package-owned keys `os serve` reads', () => {
139142
it('two packages: a package\'s cubes reach the analytics provider, and its flow is counted', async () => {
140-
const out = await boot('cubesAndFlowTwo', READY, ['--log-level', 'info']);
143+
const out = await boot('cubesAndFlowTwo', BANNER_END, ['--log-level', 'info']);
141144
expect(out).toMatch(READY);
142145
const started = out.split('\n').find((line) => line.includes('[Analytics] Service started'));
143146
expect(started, out).toBeDefined();
@@ -146,7 +149,7 @@ describe('#22288 — the other package-owned keys `os serve` reads', () => {
146149
}, 180_000);
147150

148151
it('two packages: a package\'s `tiers` are honoured, so a stack without `auth` is refused', async () => {
149-
const out = await boot('tiersTwo', READY_OR_FATAL);
152+
const out = await boot('tiersTwo', BANNER_END_OR_FATAL);
150153
expect(out).not.toMatch(READY);
151154
expect(out).toMatch(/✗ [^\n]*mounts no auth/);
152155
}, 180_000);

0 commit comments

Comments
 (0)