11import { 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
64function 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
2118const apiKeyAvailable = ! ! ( process . env . VIBESDK_API_KEY || process . env . VIBESDK_INTEGRATION_API_KEY ) ;
2219const runIntegration = process . env . VIBESDK_RUN_INTEGRATION_TESTS === '1' || apiKeyAvailable ;
23-
2420const 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