@@ -3,7 +3,7 @@ import * as cp from "child_process"
3
3
import { promises as fs } from "fs"
4
4
import * as path from "path"
5
5
import { Page } from "playwright"
6
- import util from "util"
6
+ import * as util from "util"
7
7
import { logError , plural } from "../../../src/common/util"
8
8
import { onLine } from "../../../src/node/util"
9
9
import { PASSWORD , workspaceDir } from "../../utils/constants"
@@ -38,12 +38,13 @@ export class CodeServer {
38
38
private process : Promise < CodeServerProcess > | undefined
39
39
public readonly logger : Logger
40
40
private closed = false
41
- private _workspaceDir : Promise < string > | undefined
42
41
43
42
constructor (
44
43
name : string ,
45
- private readonly codeServerArgs : string [ ] ,
46
- private readonly codeServerEnv : NodeJS . ProcessEnv ,
44
+ private readonly args : string [ ] ,
45
+ private readonly env : NodeJS . ProcessEnv ,
46
+ private readonly _workspaceDir : Promise < string > | string | undefined ,
47
+ private readonly entry = process . env . CODE_SERVER_TEST_ENTRY || "." ,
47
48
) {
48
49
this . logger = logger . named ( name )
49
50
}
@@ -75,7 +76,7 @@ export class CodeServer {
75
76
*/
76
77
private async createWorkspace ( ) : Promise < string > {
77
78
const dir = await this . workspaceDir
78
- await fs . mkdir ( path . join ( dir , "User" ) )
79
+ await fs . mkdir ( path . join ( dir , "User" ) , { recursive : true } )
79
80
await fs . writeFile (
80
81
path . join ( dir , "User/settings.json" ) ,
81
82
JSON . stringify ( {
@@ -96,36 +97,33 @@ export class CodeServer {
96
97
const dir = await this . createWorkspace ( )
97
98
98
99
return new Promise ( ( resolve , reject ) => {
99
- this . logger . debug ( "spawning" )
100
- const proc = cp . spawn (
101
- "node" ,
102
- [
103
- process . env . CODE_SERVER_TEST_ENTRY || "." ,
104
- "--extensions-dir" ,
105
- path . join ( dir , "extensions" ) ,
106
- ...this . codeServerArgs ,
107
- // Using port zero will spawn on a random port.
108
- "--bind-addr" ,
109
- "127.0.0.1:0" ,
110
- // Setting the XDG variables would be easier and more thorough but the
111
- // modules we import ignores those variables for non-Linux operating
112
- // systems so use these flags instead.
113
- "--config" ,
114
- path . join ( dir , "config.yaml" ) ,
115
- "--user-data-dir" ,
116
- dir ,
117
- // The last argument is the workspace to open.
118
- dir ,
119
- ] ,
120
- {
121
- cwd : path . join ( __dirname , "../../.." ) ,
122
- env : {
123
- ...process . env ,
124
- ...this . codeServerEnv ,
125
- PASSWORD ,
126
- } ,
100
+ const args = [
101
+ this . entry ,
102
+ "--extensions-dir" ,
103
+ path . join ( dir , "extensions" ) ,
104
+ ...this . args ,
105
+ // Using port zero will spawn on a random port.
106
+ "--bind-addr" ,
107
+ "127.0.0.1:0" ,
108
+ // Setting the XDG variables would be easier and more thorough but the
109
+ // modules we import ignores those variables for non-Linux operating
110
+ // systems so use these flags instead.
111
+ "--config" ,
112
+ path . join ( dir , "config.yaml" ) ,
113
+ "--user-data-dir" ,
114
+ dir ,
115
+ // The last argument is the workspace to open.
116
+ dir ,
117
+ ]
118
+ this . logger . debug ( "spawning `node " + args . join ( " " ) + "`" )
119
+ const proc = cp . spawn ( "node" , args , {
120
+ cwd : path . join ( __dirname , "../../.." ) ,
121
+ env : {
122
+ ...process . env ,
123
+ ...this . env ,
124
+ PASSWORD ,
127
125
} ,
128
- )
126
+ } )
129
127
130
128
const timer = idleTimer ( "Failed to extract address; did the format change?" , reject )
131
129
@@ -136,7 +134,7 @@ export class CodeServer {
136
134
} )
137
135
138
136
proc . on ( "close" , ( code ) => {
139
- const error = new Error ( "closed unexpectedly" )
137
+ const error = new Error ( "code-server closed unexpectedly" )
140
138
if ( ! this . closed ) {
141
139
this . logger . error ( error . message , field ( "code" , code ) )
142
140
}
@@ -153,7 +151,7 @@ export class CodeServer {
153
151
timer . reset ( )
154
152
155
153
// Log the line without the timestamp.
156
- this . logger . trace ( line . replace ( / \[ .+ \] / , "" ) )
154
+ this . logger . debug ( line . replace ( / \[ .+ \] / , "" ) )
157
155
if ( resolved ) {
158
156
return
159
157
}
@@ -194,7 +192,11 @@ export class CodeServer {
194
192
export class CodeServerPage {
195
193
private readonly editorSelector = "div.monaco-workbench"
196
194
197
- constructor ( private readonly codeServer : CodeServer , public readonly page : Page ) {
195
+ constructor (
196
+ private readonly codeServer : CodeServer ,
197
+ public readonly page : Page ,
198
+ private readonly authenticated : boolean ,
199
+ ) {
198
200
this . page . on ( "console" , ( message ) => {
199
201
this . codeServer . logger . debug ( message )
200
202
} )
@@ -215,11 +217,18 @@ export class CodeServerPage {
215
217
}
216
218
217
219
/**
218
- * Navigate to a code-server endpoint. By default go to the root.
220
+ * Navigate to a code-server endpoint (root by default). Then wait for the
221
+ * editor to become available.
219
222
*/
220
223
async navigate ( endpoint = "/" ) {
221
224
const to = new URL ( endpoint , await this . codeServer . address ( ) )
222
225
await this . page . goto ( to . toString ( ) , { waitUntil : "networkidle" } )
226
+
227
+ // Only reload editor if authenticated. Otherwise we'll get stuck
228
+ // reloading the login page.
229
+ if ( this . authenticated ) {
230
+ await this . reloadUntilEditorIsReady ( )
231
+ }
223
232
}
224
233
225
234
/**
@@ -456,21 +465,7 @@ export class CodeServerPage {
456
465
}
457
466
458
467
/**
459
- * Navigates to code-server then reloads until the editor is ready.
460
- *
461
- * It is recommended to run setup before using this model in any tests.
462
- */
463
- async setup ( authenticated : boolean , endpoint = "/" ) {
464
- await this . navigate ( endpoint )
465
- // If we aren't authenticated we'll see a login page so we can't wait until
466
- // the editor is ready.
467
- if ( authenticated ) {
468
- await this . reloadUntilEditorIsReady ( )
469
- }
470
- }
471
-
472
- /**
473
- * Execute a command in t root of the instance's workspace directory.
468
+ * Execute a command in the root of the instance's workspace directory.
474
469
*/
475
470
async exec ( command : string ) : Promise < void > {
476
471
await util . promisify ( cp . exec ) ( command , {
@@ -488,4 +483,15 @@ export class CodeServerPage {
488
483
cwd : path . join ( __dirname , "../../.." ) ,
489
484
} )
490
485
}
486
+
487
+ /**
488
+ * Wait for state to be flushed to the database.
489
+ */
490
+ async stateFlush ( ) : Promise < void > {
491
+ // If we reload too quickly VS Code will be unable to save the state changes
492
+ // so wait until those have been written to the database. It flushes every
493
+ // five seconds so we need to wait at least that long.
494
+ // TODO@asher : There must be a better way.
495
+ await this . page . waitForTimeout ( 5500 )
496
+ }
491
497
}
0 commit comments