Skip to content

Commit a68d9cb

Browse files
committed
feat: integration tests with worker
1 parent 33eb39f commit a68d9cb

File tree

8 files changed

+1104
-93
lines changed

8 files changed

+1104
-93
lines changed
Lines changed: 56 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { describe, expect, it } from 'bun:test';
2-
3-
// Native WebSocket is available in Node.js 22+, Bun, and browsers
4-
import { PhasicClient } from '../../src/index';
2+
import { testAuth, testFullBuild, type FullTestResult } from './test-flow';
53

64
function getEnv(name: string, fallback?: string): string | undefined {
75
return process.env[name] ?? fallback;
@@ -11,109 +9,74 @@ function requireEnv(name: string, altName?: string): string {
119
const v = process.env[name] ?? (altName ? process.env[altName] : undefined);
1210
if (!v) {
1311
throw new Error(
14-
`Missing ${name}. Create an API key in Settings API Keys and run: ${name}=<key> bun run test:integration`,
12+
`Missing ${name}. Create an API key in Settings -> API Keys and run: ${name}=<key> bun run test:integration`
1513
);
1614
}
1715
return v;
1816
}
1917

20-
// Support both VIBESDK_API_KEY (from .env) and VIBESDK_INTEGRATION_API_KEY
2118
const apiKeyAvailable = !!(process.env.VIBESDK_API_KEY || process.env.VIBESDK_INTEGRATION_API_KEY);
2219
const runIntegration = process.env.VIBESDK_RUN_INTEGRATION_TESTS === '1' || apiKeyAvailable;
23-
2420
const describeIntegration = runIntegration ? describe : describe.skip;
2521

26-
function previewUrlFromState(state: { previewUrl?: string; preview?: { status: string; previewURL?: string } }): string | undefined {
27-
if (state.preview?.status === 'complete' && state.preview.previewURL) return state.preview.previewURL;
28-
return state.previewUrl;
22+
const FULL_BUILD_TIMEOUT = 10 * 60 * 1000;
23+
24+
function logStepResults(result: FullTestResult, prefix: string): void {
25+
for (const step of result.steps) {
26+
const status = step.success ? 'OK' : 'FAIL';
27+
const details = step.details ? ` ${JSON.stringify(step.details)}` : '';
28+
const error = step.error ? ` ERROR: ${step.error}` : '';
29+
console.log(`${prefix} [${status}] ${step.step} (${step.duration}ms)${details}${error}`);
30+
}
2931
}
3032

31-
describeIntegration('SDK integration (local platform)', () => {
33+
describeIntegration('SDK integration', () => {
3234
const apiKey = requireEnv('VIBESDK_API_KEY', 'VIBESDK_INTEGRATION_API_KEY');
33-
const baseUrl = getEnv('VIBESDK_BASE_URL', getEnv('VIBESDK_INTEGRATION_BASE_URL', 'http://localhost:5173')) as string;
34-
35-
const fetchFn: typeof fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
36-
return await fetch(input, init);
37-
};
38-
39-
function safeWsType(m: unknown): string {
40-
const t = (m as { type?: unknown })?.type;
41-
if (typeof t === 'string') return t.length > 120 ? `${t.slice(0, 120)}…` : t;
42-
try {
43-
const s = JSON.stringify(t);
44-
return s.length > 120 ? `${s.slice(0, 120)}…` : s;
45-
} catch {
46-
return String(t);
47-
}
48-
}
35+
const baseUrl = getEnv(
36+
'VIBESDK_BASE_URL',
37+
getEnv('VIBESDK_INTEGRATION_BASE_URL', 'https://build.cloudflare.dev')
38+
) as string;
4939

50-
it('sanity: dev server reachable', async () => {
51-
console.log(`[integration] baseUrl=${baseUrl}`);
52-
const checkResp = await fetch(`${baseUrl}/api/auth/check`, { method: 'GET' });
53-
console.log(`[integration] GET /api/auth/check -> ${checkResp.status}`);
54-
expect(checkResp.ok).toBe(true);
55-
});
40+
const log = (msg: string) => console.log(`[bun] ${msg}`);
41+
42+
it('auth: client creation and token exchange', async () => {
43+
console.log(`[bun] Testing against: ${baseUrl}`);
5644

57-
it('build: generation started -> deployable -> preview deployed -> generation complete', async () => {
58-
const client = new PhasicClient({
59-
baseUrl,
60-
apiKey,
61-
fetchFn,
62-
});
63-
64-
console.log('[integration] build: creating agent');
65-
const session = await client.build('Build a simple hello world page.', {
66-
projectType: 'app',
67-
autoGenerate: true,
68-
credentials: {},
69-
});
70-
71-
// Log every WS message type for debugging.
72-
session.on('ws:message', (m) => {
73-
console.log(`[integration] ws: ${safeWsType(m)}`);
74-
});
75-
session.on('ws:reconnecting', (e) => {
76-
console.log(
77-
`[integration] ws: reconnecting attempt=${e.attempt} delayMs=${e.delayMs} reason=${e.reason}`,
78-
);
79-
});
80-
session.on('ws:close', (e) => {
81-
console.log(`[integration] ws: close code=${e.code} reason=${e.reason}`);
82-
});
83-
session.on('ws:error', (e) => {
84-
console.log('[integration] ws: error', e.error);
85-
});
86-
87-
console.log(`[integration] agentId=${session.agentId}`);
88-
expect(typeof session.agentId).toBe('string');
89-
90-
// 1) Generation begins (SDK primitive)
91-
if (session.state.get().generation.status === 'idle') {
92-
await session.wait.generationStarted();
93-
}
94-
95-
// 2) Deployable (SDK primitive; phasic currently maps to phase_validated internally)
96-
await session.wait.deployable();
97-
98-
// 3) Preview deployment completed
99-
const previewWait = session.wait.previewDeployed();
100-
session.deployPreview();
101-
const deployed = await previewWait;
102-
expect(deployed.previewURL.startsWith('http')).toBe(true);
103-
104-
// 4) Generation complete (if not already)
105-
if (session.state.get().generation.status !== 'complete') {
106-
await session.wait.generationComplete();
107-
}
108-
109-
// Basic workspace sync sanity
110-
const paths = session.files.listPaths();
111-
console.log(`[integration] workspace files=${paths.length}`);
112-
expect(paths.length).toBeGreaterThan(0);
113-
114-
const statePreviewUrl = previewUrlFromState(session.state.get() as any);
115-
console.log(`[integration] previewUrl=${statePreviewUrl ?? deployed.previewURL}`);
116-
117-
session.close();
45+
const result = await testAuth({ baseUrl, apiKey, log });
46+
logStepResults(result, '[bun]');
47+
48+
expect(result.ok).toBe(true);
11849
});
50+
51+
it(
52+
'build: full flow with step-by-step verification',
53+
async () => {
54+
console.log(`[bun] Starting full build test against: ${baseUrl}`);
55+
56+
const result = await testFullBuild({ baseUrl, apiKey, log });
57+
logStepResults(result, '[bun]');
58+
59+
if (result.agentId) {
60+
console.log(`[bun] Agent ID: ${result.agentId}`);
61+
}
62+
if (result.previewUrl) {
63+
console.log(`[bun] Preview URL: ${result.previewUrl}`);
64+
}
65+
66+
// Check for rate limit
67+
if (result.error?.includes('429') || result.error?.includes('rate limit')) {
68+
console.log('[bun] Rate limited - skipping assertion');
69+
return;
70+
}
71+
72+
expect(result.ok).toBe(true);
73+
expect(result.agentId).toBeDefined();
74+
expect(result.previewUrl).toBeDefined();
75+
expect(result.previewUrl!.startsWith('http')).toBe(true);
76+
77+
const failedSteps = result.steps.filter((s) => !s.success);
78+
expect(failedSteps.length).toBe(0);
79+
},
80+
FULL_BUILD_TIMEOUT
81+
);
11982
});

0 commit comments

Comments
 (0)