11import { test as base , expect , type Page } from "@playwright/test"
2+ import { ManagedRuntime } from "effect"
23import type { E2EWindow } from "../src/testing/terminal"
4+ import type { Item , Reply , Usage } from "../../opencode/test/lib/llm-server"
5+ import { TestLLMServer } from "../../opencode/test/lib/llm-server"
36import {
47 healthPhase ,
58 cleanupSession ,
@@ -13,6 +16,24 @@ import {
1316} from "./actions"
1417import { createSdk , dirSlug , getWorktree , sessionPath } from "./utils"
1518
19+ type LLMFixture = {
20+ url : string
21+ push : ( ...input : ( Item | Reply ) [ ] ) => Promise < void >
22+ text : ( value : string , opts ?: { usage ?: Usage } ) => Promise < void >
23+ tool : ( name : string , input : unknown ) => Promise < void >
24+ toolHang : ( name : string , input : unknown ) => Promise < void >
25+ reason : ( value : string , opts ?: { text ?: string ; usage ?: Usage } ) => Promise < void >
26+ fail : ( message ?: unknown ) => Promise < void >
27+ error : ( status : number , body : unknown ) => Promise < void >
28+ hang : ( ) => Promise < void >
29+ hold : ( value : string , wait : PromiseLike < unknown > ) => Promise < void >
30+ hits : ( ) => Promise < Array < { url : URL ; body : Record < string , unknown > } > >
31+ calls : ( ) => Promise < number >
32+ wait : ( count : number ) => Promise < void >
33+ inputs : ( ) => Promise < Record < string , unknown > [ ] >
34+ pending : ( ) => Promise < number >
35+ }
36+
1637export const settingsKey = "settings.v3"
1738
1839const seedModel = ( ( ) => {
@@ -26,6 +47,7 @@ const seedModel = (() => {
2647} ) ( )
2748
2849type TestFixtures = {
50+ llm : LLMFixture
2951 sdk : ReturnType < typeof createSdk >
3052 gotoSession : ( sessionID ?: string ) => Promise < void >
3153 withProject : < T > (
@@ -36,7 +58,11 @@ type TestFixtures = {
3658 trackSession : ( sessionID : string , directory ?: string ) => void
3759 trackDirectory : ( directory : string ) => void
3860 } ) => Promise < T > ,
39- options ?: { extra ?: string [ ] } ,
61+ options ?: {
62+ extra ?: string [ ]
63+ model ?: { providerID : string ; modelID : string }
64+ setup ?: ( directory : string ) => Promise < void >
65+ } ,
4066 ) => Promise < T >
4167}
4268
@@ -46,6 +72,31 @@ type WorkerFixtures = {
4672}
4773
4874export const test = base . extend < TestFixtures , WorkerFixtures > ( {
75+ llm : async ( { } , use ) => {
76+ const rt = ManagedRuntime . make ( TestLLMServer . layer )
77+ try {
78+ const svc = await rt . runPromise ( TestLLMServer . asEffect ( ) )
79+ await use ( {
80+ url : svc . url ,
81+ push : ( ...input ) => rt . runPromise ( svc . push ( ...input ) ) ,
82+ text : ( value , opts ) => rt . runPromise ( svc . text ( value , opts ) ) ,
83+ tool : ( name , input ) => rt . runPromise ( svc . tool ( name , input ) ) ,
84+ toolHang : ( name , input ) => rt . runPromise ( svc . toolHang ( name , input ) ) ,
85+ reason : ( value , opts ) => rt . runPromise ( svc . reason ( value , opts ) ) ,
86+ fail : ( message ) => rt . runPromise ( svc . fail ( message ) ) ,
87+ error : ( status , body ) => rt . runPromise ( svc . error ( status , body ) ) ,
88+ hang : ( ) => rt . runPromise ( svc . hang ) ,
89+ hold : ( value , wait ) => rt . runPromise ( svc . hold ( value , wait ) ) ,
90+ hits : ( ) => rt . runPromise ( svc . hits ) ,
91+ calls : ( ) => rt . runPromise ( svc . calls ) ,
92+ wait : ( count ) => rt . runPromise ( svc . wait ( count ) ) ,
93+ inputs : ( ) => rt . runPromise ( svc . inputs ) ,
94+ pending : ( ) => rt . runPromise ( svc . pending ) ,
95+ } )
96+ } finally {
97+ await rt . dispose ( )
98+ }
99+ } ,
49100 page : async ( { page } , use ) => {
50101 let boundary : string | undefined
51102 setHealthPhase ( page , "test" )
@@ -99,7 +150,8 @@ export const test = base.extend<TestFixtures, WorkerFixtures>({
99150 const root = await createTestProject ( )
100151 const sessions = new Map < string , string > ( )
101152 const dirs = new Set < string > ( )
102- await seedStorage ( page , { directory : root , extra : options ?. extra } )
153+ await options ?. setup ?.( root )
154+ await seedStorage ( page , { directory : root , extra : options ?. extra , model : options ?. model } )
103155
104156 const gotoSession = async ( sessionID ?: string ) => {
105157 await page . goto ( sessionPath ( root , sessionID ) )
@@ -133,7 +185,14 @@ export const test = base.extend<TestFixtures, WorkerFixtures>({
133185 } ,
134186} )
135187
136- async function seedStorage ( page : Page , input : { directory : string ; extra ?: string [ ] } ) {
188+ async function seedStorage (
189+ page : Page ,
190+ input : {
191+ directory : string
192+ extra ?: string [ ]
193+ model ?: { providerID : string ; modelID : string }
194+ } ,
195+ ) {
137196 await seedProjects ( page , input )
138197 await page . addInitScript ( ( model : { providerID : string ; modelID : string } ) => {
139198 const win = window as E2EWindow
@@ -158,7 +217,7 @@ async function seedStorage(page: Page, input: { directory: string; extra?: strin
158217 variant : { } ,
159218 } ) ,
160219 )
161- } , seedModel )
220+ } , input . model ?? seedModel )
162221}
163222
164223export { expect }
0 commit comments