@jupyterlab/galata 5.0.0-alpha.2 → 5.0.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +192 -31
- package/lib/benchmarkReporter.d.ts +1 -0
- package/lib/benchmarkReporter.js +34 -39
- package/lib/benchmarkReporter.js.map +1 -1
- package/lib/benchmarkVLTpl.js +19 -5
- package/lib/benchmarkVLTpl.js.map +1 -1
- package/lib/contents.d.ts +5 -5
- package/lib/contents.js +32 -36
- package/lib/contents.js.map +1 -1
- package/lib/extension/global.d.ts +197 -0
- package/lib/extension/global.js +601 -0
- package/lib/extension/global.js.map +1 -0
- package/lib/extension/index.d.ts +6 -0
- package/lib/extension/index.js +27 -0
- package/lib/extension/index.js.map +1 -0
- package/lib/extension/tokens.d.ts +232 -0
- package/lib/extension/tokens.js +13 -0
- package/lib/extension/tokens.js.map +1 -0
- package/lib/extension.d.ts +223 -0
- package/lib/{global.js → extension.js} +1 -2
- package/lib/extension.js.map +1 -0
- package/lib/fixtures.d.ts +32 -10
- package/lib/fixtures.js +64 -17
- package/lib/fixtures.js.map +1 -1
- package/lib/galata.d.ts +140 -19
- package/lib/galata.js +272 -87
- package/lib/galata.js.map +1 -1
- package/lib/helpers/activity.d.ts +6 -0
- package/lib/helpers/activity.js +19 -5
- package/lib/helpers/activity.js.map +1 -1
- package/lib/helpers/debuggerpanel.d.ts +4 -0
- package/lib/helpers/debuggerpanel.js +16 -0
- package/lib/helpers/debuggerpanel.js.map +1 -1
- package/lib/helpers/filebrowser.js +8 -2
- package/lib/helpers/filebrowser.js.map +1 -1
- package/lib/helpers/index.d.ts +1 -0
- package/lib/helpers/index.js +6 -1
- package/lib/helpers/index.js.map +1 -1
- package/lib/helpers/kernel.js +7 -7
- package/lib/helpers/kernel.js.map +1 -1
- package/lib/helpers/menu.d.ts +7 -0
- package/lib/helpers/menu.js +17 -1
- package/lib/helpers/menu.js.map +1 -1
- package/lib/helpers/notebook.d.ts +6 -4
- package/lib/helpers/notebook.js +127 -31
- package/lib/helpers/notebook.js.map +1 -1
- package/lib/helpers/sidebar.d.ts +8 -1
- package/lib/helpers/sidebar.js +33 -15
- package/lib/helpers/sidebar.js.map +1 -1
- package/lib/helpers/statusbar.js +1 -1
- package/lib/helpers/statusbar.js.map +1 -1
- package/lib/helpers/style.d.ts +42 -0
- package/lib/helpers/style.js +50 -0
- package/lib/helpers/style.js.map +1 -0
- package/lib/helpers/theme.js +1 -1
- package/lib/helpers/theme.js.map +1 -1
- package/lib/index.d.ts +5 -2
- package/lib/index.js +12 -3
- package/lib/index.js.map +1 -1
- package/lib/jupyterlabpage.d.ts +29 -4
- package/lib/jupyterlabpage.js +38 -22
- package/lib/jupyterlabpage.js.map +1 -1
- package/lib/playwright-config.js +5 -1
- package/lib/playwright-config.js.map +1 -1
- package/lib/utils.js +5 -1
- package/lib/utils.js.map +1 -1
- package/package.json +31 -47
- package/src/benchmarkReporter.ts +756 -0
- package/src/benchmarkVLTpl.ts +91 -0
- package/src/contents.ts +472 -0
- package/src/extension.ts +281 -0
- package/src/fixtures.ts +387 -0
- package/src/galata.ts +1035 -0
- package/src/helpers/activity.ts +115 -0
- package/src/helpers/debuggerpanel.ts +159 -0
- package/src/helpers/filebrowser.ts +228 -0
- package/src/helpers/index.ts +15 -0
- package/src/helpers/kernel.ts +39 -0
- package/src/helpers/logconsole.ts +32 -0
- package/src/helpers/menu.ts +228 -0
- package/src/helpers/notebook.ts +1217 -0
- package/src/helpers/performance.ts +57 -0
- package/src/helpers/sidebar.ts +289 -0
- package/src/helpers/statusbar.ts +56 -0
- package/src/helpers/style.ts +100 -0
- package/src/helpers/theme.ts +50 -0
- package/src/index.ts +19 -0
- package/src/jupyterlabpage.ts +704 -0
- package/src/playwright-config.ts +26 -0
- package/src/utils.ts +264 -0
- package/src/vega-statistics.d.ts +15 -0
- package/lib/global.d.ts +0 -23
- package/lib/global.js.map +0 -1
- package/lib/inpage/tokens.d.ts +0 -135
- package/lib/inpage/tokens.js +0 -9
- package/lib/inpage/tokens.js.map +0 -1
- package/lib/lib-inpage/inpage.js +0 -3957
- package/lib/lib-inpage/inpage.js.map +0 -1
- package/style/index.css +0 -10
- package/style/index.js +0 -10
package/src/extension.ts
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Copyright (c) Bloomberg Finance LP.
|
|
3
|
+
// Distributed under the terms of the Modified BSD License.
|
|
4
|
+
|
|
5
|
+
// This export the types (and only the types) from extension/token.ts
|
|
6
|
+
// Required for typedoc to be happy otherwise we could have used `from '@jupyterlab/extension/lib/token';`
|
|
7
|
+
|
|
8
|
+
import type { JupyterFrontEnd } from '@jupyterlab/application';
|
|
9
|
+
import type { IRouter } from '@jupyterlab/application';
|
|
10
|
+
import type {
|
|
11
|
+
Dialog,
|
|
12
|
+
Notification,
|
|
13
|
+
NotificationManager,
|
|
14
|
+
WidgetTracker
|
|
15
|
+
} from '@jupyterlab/apputils';
|
|
16
|
+
import type { IDocumentManager } from '@jupyterlab/docmanager';
|
|
17
|
+
import type { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
18
|
+
|
|
19
|
+
declare global {
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
21
|
+
interface Window {
|
|
22
|
+
/**
|
|
23
|
+
* Access Jupyter Application object
|
|
24
|
+
*/
|
|
25
|
+
jupyterapp: JupyterFrontEnd;
|
|
26
|
+
/**
|
|
27
|
+
* Access to Galata In-Page helpers
|
|
28
|
+
*
|
|
29
|
+
* Those helpers are injected through a JupyterLab extension
|
|
30
|
+
*/
|
|
31
|
+
galata: IGalataInpage;
|
|
32
|
+
/**
|
|
33
|
+
* Access to Galata In-Page helpers
|
|
34
|
+
*
|
|
35
|
+
* @deprecated since v4
|
|
36
|
+
* Those helpers are injected through a JupyterLab extension
|
|
37
|
+
*/
|
|
38
|
+
galataip: IGalataInpage;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Static objects exposed.
|
|
44
|
+
*/
|
|
45
|
+
export interface IGalataHelpers {
|
|
46
|
+
/**
|
|
47
|
+
* JupyterLab dialogs tracker.
|
|
48
|
+
*/
|
|
49
|
+
readonly dialogs: WidgetTracker<Dialog<any>>;
|
|
50
|
+
/**
|
|
51
|
+
* JupyterLab notifications manager.
|
|
52
|
+
*/
|
|
53
|
+
readonly notifications: NotificationManager;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Cell execution callbacks interface
|
|
58
|
+
*/
|
|
59
|
+
export interface INotebookRunCallback {
|
|
60
|
+
/**
|
|
61
|
+
* Callback before scrolling to the cell
|
|
62
|
+
*/
|
|
63
|
+
onBeforeScroll?: () => Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Callback after scrolling to the cell
|
|
66
|
+
*/
|
|
67
|
+
onAfterScroll?: () => Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Callback after cell execution
|
|
70
|
+
*/
|
|
71
|
+
onAfterCellRun?: (cellIndex: number) => Promise<void>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* waitForSelector options
|
|
76
|
+
*/
|
|
77
|
+
export interface IWaitForSelectorOptions {
|
|
78
|
+
/**
|
|
79
|
+
* Test for the element to be hidden.
|
|
80
|
+
*/
|
|
81
|
+
hidden?: boolean;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface IPluginNameToInterfaceMap {
|
|
85
|
+
'@jupyterlab/galata-extension:helpers': IGalataHelpers;
|
|
86
|
+
'@jupyterlab/application-extension:router': IRouter;
|
|
87
|
+
'@jupyterlab/docmanager-extension:manager': IDocumentManager;
|
|
88
|
+
'@jupyterlab/apputils-extension:settings': ISettingRegistry;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Galata In-Page interface
|
|
93
|
+
*/
|
|
94
|
+
export interface IGalataInpage {
|
|
95
|
+
/**
|
|
96
|
+
* Delete all cells of the active notebook
|
|
97
|
+
*/
|
|
98
|
+
deleteNotebookCells(): Promise<void>;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get the index of a toolbar item
|
|
102
|
+
*
|
|
103
|
+
* @param itemName Item name
|
|
104
|
+
* @returns Index
|
|
105
|
+
*/
|
|
106
|
+
getNotebookToolbarItemIndex(itemName: string): number;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Get an application plugin
|
|
110
|
+
*
|
|
111
|
+
* @param pluginId Plugin ID
|
|
112
|
+
* @returns Application plugin
|
|
113
|
+
*/
|
|
114
|
+
getPlugin<K extends keyof IPluginNameToInterfaceMap>(
|
|
115
|
+
pluginId: K
|
|
116
|
+
): Promise<IPluginNameToInterfaceMap[K] | undefined>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get the Jupyter notifications.
|
|
120
|
+
*
|
|
121
|
+
* @returns Jupyter Notifications
|
|
122
|
+
*/
|
|
123
|
+
getNotifications(): Promise<Notification.INotification[]>;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Test if one or all cells have an execution number.
|
|
127
|
+
*
|
|
128
|
+
* @param cellIndex Cell index
|
|
129
|
+
* @returns Whether the cell was executed or not
|
|
130
|
+
*
|
|
131
|
+
* ### Notes
|
|
132
|
+
* It checks that no cells have a `null` execution count.
|
|
133
|
+
*/
|
|
134
|
+
haveBeenExecuted(cellIndex?: number): boolean;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Test if a cell is selected in the active notebook
|
|
138
|
+
*
|
|
139
|
+
* @param cellIndex Cell index
|
|
140
|
+
* @returns Whether the cell is selected or not
|
|
141
|
+
*/
|
|
142
|
+
isNotebookCellSelected(cellIndex: number): boolean;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Test if a element is visible or not
|
|
146
|
+
*
|
|
147
|
+
* @param el Element
|
|
148
|
+
* @returns Test result
|
|
149
|
+
*/
|
|
150
|
+
isElementVisible(el: HTMLElement): boolean;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Disconnect a listener to new Jupyter dialog events.
|
|
154
|
+
*
|
|
155
|
+
* @param event Event type
|
|
156
|
+
* @param listener Event listener
|
|
157
|
+
*/
|
|
158
|
+
off(event: 'dialog', listener: (dialog: Dialog<any> | null) => void): void;
|
|
159
|
+
/**
|
|
160
|
+
* Disconnect a listener to new or updated Jupyter notification events.
|
|
161
|
+
*
|
|
162
|
+
* @param event Event type
|
|
163
|
+
* @param listener Event listener
|
|
164
|
+
*/
|
|
165
|
+
off(
|
|
166
|
+
event: 'notification',
|
|
167
|
+
listener: (notification: Notification.INotification) => void
|
|
168
|
+
): void;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Connect a listener to new Jupyter dialog events.
|
|
172
|
+
*
|
|
173
|
+
* @param event Event type
|
|
174
|
+
* @param listener Event listener
|
|
175
|
+
*/
|
|
176
|
+
on(event: 'dialog', listener: (dialog: Dialog<any> | null) => void): void;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Connect a listener to new or updated Jupyter notification events.
|
|
180
|
+
*
|
|
181
|
+
* @param event Event type
|
|
182
|
+
* @param listener Event listener
|
|
183
|
+
*/
|
|
184
|
+
on(
|
|
185
|
+
event: 'notification',
|
|
186
|
+
listener: (notification: Notification.INotification) => void
|
|
187
|
+
): void;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Connect a listener to the next new Jupyter dialog event.
|
|
191
|
+
*
|
|
192
|
+
* @param event Event type
|
|
193
|
+
* @param listener Event listener
|
|
194
|
+
*/
|
|
195
|
+
once(event: 'dialog', listener: (dialog: Dialog<any> | null) => void): void;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Connect a listener to the next new or updated Jupyter notification event.
|
|
199
|
+
*
|
|
200
|
+
* @param event Event type
|
|
201
|
+
* @param listener Event listener
|
|
202
|
+
*/
|
|
203
|
+
once(
|
|
204
|
+
event: 'notification',
|
|
205
|
+
listener: (notification: Notification.INotification) => void
|
|
206
|
+
): void;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Save the active notebook
|
|
210
|
+
*/
|
|
211
|
+
saveActiveNotebook(): Promise<void>;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Set the application theme
|
|
215
|
+
*
|
|
216
|
+
* @param themeName Theme name
|
|
217
|
+
*/
|
|
218
|
+
setTheme(themeName: string): Promise<void>;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Reset execution count of one or all cells.
|
|
222
|
+
*
|
|
223
|
+
* @param cellIndex Cell index
|
|
224
|
+
*/
|
|
225
|
+
resetExecutionCount(cellIndex?: number): void;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Run the active notebook cell by cell
|
|
229
|
+
* and execute the callback after each cell execution
|
|
230
|
+
*
|
|
231
|
+
* @param callback Callback
|
|
232
|
+
*/
|
|
233
|
+
runActiveNotebookCellByCell(callback?: INotebookRunCallback): Promise<void>;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Wait for the route to be on path and close all documents
|
|
237
|
+
*
|
|
238
|
+
* @param path Path to monitor
|
|
239
|
+
*/
|
|
240
|
+
waitForLaunch(path?: string): Promise<void>;
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Wait for an element to be found from a CSS selector
|
|
244
|
+
*
|
|
245
|
+
* @param selector CSS selector
|
|
246
|
+
* @param node Element
|
|
247
|
+
* @param options Options
|
|
248
|
+
* @returns Selected element
|
|
249
|
+
*/
|
|
250
|
+
waitForSelector(
|
|
251
|
+
selector: string,
|
|
252
|
+
node?: Element,
|
|
253
|
+
options?: IWaitForSelectorOptions
|
|
254
|
+
): Promise<Node | null>;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Waits for the given `timeout` in milliseconds.
|
|
258
|
+
*
|
|
259
|
+
* @param timeout A timeout to wait for
|
|
260
|
+
*/
|
|
261
|
+
waitForTimeout(duration: number): Promise<void>;
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Wait for an element to be found from a XPath
|
|
265
|
+
*
|
|
266
|
+
* @param selector CSS selector
|
|
267
|
+
* @param node Element
|
|
268
|
+
* @param options Options
|
|
269
|
+
* @returns Selected element
|
|
270
|
+
*/
|
|
271
|
+
waitForXPath(
|
|
272
|
+
selector: string,
|
|
273
|
+
node?: Element,
|
|
274
|
+
options?: IWaitForSelectorOptions
|
|
275
|
+
): Promise<Node | null>;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Application object
|
|
279
|
+
*/
|
|
280
|
+
readonly app: JupyterFrontEnd;
|
|
281
|
+
}
|
package/src/fixtures.ts
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
|
+
// Copyright (c) Jupyter Development Team.
|
|
3
|
+
// Distributed under the terms of the Modified BSD License.
|
|
4
|
+
|
|
5
|
+
import type { Session, TerminalAPI, User } from '@jupyterlab/services';
|
|
6
|
+
import {
|
|
7
|
+
test as base,
|
|
8
|
+
Page,
|
|
9
|
+
PlaywrightTestArgs,
|
|
10
|
+
PlaywrightTestOptions,
|
|
11
|
+
PlaywrightWorkerArgs,
|
|
12
|
+
PlaywrightWorkerOptions,
|
|
13
|
+
TestType
|
|
14
|
+
} from '@playwright/test';
|
|
15
|
+
import * as path from 'path';
|
|
16
|
+
import { ContentsHelper } from './contents';
|
|
17
|
+
import { galata } from './galata';
|
|
18
|
+
import { IJupyterLabPage, IJupyterLabPageFixture } from './jupyterlabpage';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Galata test arguments
|
|
22
|
+
*/
|
|
23
|
+
export interface IGalataTestArgs extends PlaywrightTestArgs {
|
|
24
|
+
/**
|
|
25
|
+
* JupyterLab test page.
|
|
26
|
+
*
|
|
27
|
+
* It brings the following feature on top of Playwright Page object:
|
|
28
|
+
* - Goto to JupyterLab URL and wait for the application to be ready
|
|
29
|
+
* - Helpers for JupyterLab
|
|
30
|
+
* - Settings mock-up
|
|
31
|
+
* - State mock-up
|
|
32
|
+
* - Track sessions and terminals opened during a test to close them at the end
|
|
33
|
+
*
|
|
34
|
+
* Note: If autoGoto is true, the filebrowser will be set inside tmpPath.
|
|
35
|
+
* Nothing is preventing you to navigate to some other folders.
|
|
36
|
+
* So you must avoid creating files outside that directory to avoid
|
|
37
|
+
* coupling effects between tests.
|
|
38
|
+
*
|
|
39
|
+
*/
|
|
40
|
+
page: IJupyterLabPageFixture;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Galata test configuration
|
|
45
|
+
*/
|
|
46
|
+
export type GalataOptions = {
|
|
47
|
+
/**
|
|
48
|
+
* Application URL path fragment.
|
|
49
|
+
*
|
|
50
|
+
* Default: /lab
|
|
51
|
+
*/
|
|
52
|
+
appPath: string;
|
|
53
|
+
/**
|
|
54
|
+
* Whether to go to JupyterLab page within the fixture or not.
|
|
55
|
+
*
|
|
56
|
+
* Default: true
|
|
57
|
+
*/
|
|
58
|
+
autoGoto: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Mock JupyterLab config in-memory or not.
|
|
61
|
+
*
|
|
62
|
+
* Possible values are:
|
|
63
|
+
* - true (default): JupyterLab config will be mocked on a per test basis
|
|
64
|
+
* - false: JupyterLab config won't be mocked (Be careful it will write config in local files)
|
|
65
|
+
* - Record<string, JSONObject>: Initial JupyterLab data config - Mapping (config section, value).
|
|
66
|
+
*
|
|
67
|
+
* By default the config is stored in-memory.
|
|
68
|
+
*/
|
|
69
|
+
mockConfig: boolean | Record<string, unknown>;
|
|
70
|
+
/**
|
|
71
|
+
* Mock JupyterLab state in-memory or not.
|
|
72
|
+
*
|
|
73
|
+
* Possible values are:
|
|
74
|
+
* - true (default): JupyterLab state will be mocked on a per test basis
|
|
75
|
+
* - false: JupyterLab state won't be mocked (Be careful it will write state in local files)
|
|
76
|
+
* - Record<string, unknown>: Initial JupyterLab data state - Mapping (state key, value).
|
|
77
|
+
*
|
|
78
|
+
* By default the state is stored in-memory.
|
|
79
|
+
*/
|
|
80
|
+
mockState: boolean | Record<string, unknown>;
|
|
81
|
+
/**
|
|
82
|
+
* Mock JupyterLab settings in-memory or not.
|
|
83
|
+
*
|
|
84
|
+
* Possible values are:
|
|
85
|
+
* - true: JupyterLab settings will be mocked on a per test basis
|
|
86
|
+
* - false: JupyterLab settings won't be mocked (Be careful it will read & write settings local files)
|
|
87
|
+
* - Record<string, unknown>: Mapping {pluginId: settings} that will be default user settings
|
|
88
|
+
*
|
|
89
|
+
* The default value is `galata.DEFAULT_SETTINGS`
|
|
90
|
+
*
|
|
91
|
+
* By default the settings are stored in-memory. However the
|
|
92
|
+
* they are still initialized with the hard drive values.
|
|
93
|
+
*/
|
|
94
|
+
mockSettings: boolean | Record<string, unknown>;
|
|
95
|
+
/**
|
|
96
|
+
* Mock JupyterLab user in-memory or not.
|
|
97
|
+
*
|
|
98
|
+
* Possible values are:
|
|
99
|
+
* - true (default): JupyterLab user will be mocked on a per test basis
|
|
100
|
+
* - false: JupyterLab user won't be mocked (It will be a random user so snapshots won't match)
|
|
101
|
+
* - Record<string, unknown>: Initial JupyterLab user - Mapping (user attribute, value).
|
|
102
|
+
*
|
|
103
|
+
* By default the user is stored in-memory.
|
|
104
|
+
*/
|
|
105
|
+
mockUser: boolean | Partial<User.IUser>;
|
|
106
|
+
/**
|
|
107
|
+
* Galata can keep the uploaded and created files in ``tmpPath`` on
|
|
108
|
+
* the server root for debugging purpose. By default the files are
|
|
109
|
+
* always deleted
|
|
110
|
+
*
|
|
111
|
+
* - 'off' - ``tmpPath`` is deleted after each tests
|
|
112
|
+
* - 'on' - ``tmpPath`` is never deleted
|
|
113
|
+
* - 'only-on-failure' - ``tmpPath`` is deleted except if a test failed or timed out.
|
|
114
|
+
*/
|
|
115
|
+
serverFiles: 'on' | 'off' | 'only-on-failure';
|
|
116
|
+
/**
|
|
117
|
+
* Sessions created during the test.
|
|
118
|
+
*
|
|
119
|
+
* Possible values are:
|
|
120
|
+
* - null: The sessions API won't be mocked
|
|
121
|
+
* - Map<string, Session.IModel>: The sessions created during a test.
|
|
122
|
+
*
|
|
123
|
+
* By default the sessions created during a test will be tracked and disposed at the end.
|
|
124
|
+
*/
|
|
125
|
+
sessions: Map<string, Session.IModel> | null;
|
|
126
|
+
/**
|
|
127
|
+
* Terminals created during the test.
|
|
128
|
+
*
|
|
129
|
+
* Possible values are:
|
|
130
|
+
* - null: The Terminals API won't be mocked
|
|
131
|
+
* - Map<string, TerminalsAPI.IModel>: The Terminals created during a test.
|
|
132
|
+
*
|
|
133
|
+
* By default the Terminals created during a test will be tracked and disposed at the end.
|
|
134
|
+
*/
|
|
135
|
+
terminals: Map<string, TerminalAPI.IModel> | null;
|
|
136
|
+
/**
|
|
137
|
+
* Unique test temporary path created on the server.
|
|
138
|
+
*
|
|
139
|
+
* Note: if you override this string, you will need to take care of creating the
|
|
140
|
+
* folder and cleaning it.
|
|
141
|
+
*/
|
|
142
|
+
tmpPath: string;
|
|
143
|
+
/**
|
|
144
|
+
* Wait for the application page to be ready.
|
|
145
|
+
*
|
|
146
|
+
* @param page Playwright Page model
|
|
147
|
+
* @param helpers JupyterLab helpers
|
|
148
|
+
*/
|
|
149
|
+
waitForApplication: (page: Page, helpers: IJupyterLabPage) => Promise<void>;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* JupyterLab customized test.
|
|
154
|
+
*/
|
|
155
|
+
// @ts-ignore
|
|
156
|
+
export const test: TestType<
|
|
157
|
+
IGalataTestArgs & GalataOptions & PlaywrightTestOptions,
|
|
158
|
+
PlaywrightWorkerArgs & PlaywrightWorkerOptions
|
|
159
|
+
> = base.extend<GalataOptions>({
|
|
160
|
+
/**
|
|
161
|
+
* `baseURL` used for all pages in the test. Takes priority over `contextOptions`.
|
|
162
|
+
* @see BrowserContextOptions
|
|
163
|
+
*
|
|
164
|
+
* It can also be set with `TARGET_URL` environment variable and default to `http://localhost:8888`.
|
|
165
|
+
*/
|
|
166
|
+
baseURL: async ({ baseURL }, use) => {
|
|
167
|
+
await use(baseURL ?? process.env.TARGET_URL ?? 'http://localhost:8888');
|
|
168
|
+
},
|
|
169
|
+
/**
|
|
170
|
+
* Application URL path fragment.
|
|
171
|
+
*
|
|
172
|
+
* Default: /lab
|
|
173
|
+
*/
|
|
174
|
+
appPath: ['/lab', { option: true }],
|
|
175
|
+
/**
|
|
176
|
+
* Whether to go to JupyterLab page within the fixture or not.
|
|
177
|
+
*
|
|
178
|
+
* Default: true.
|
|
179
|
+
*
|
|
180
|
+
* Note: Setting it to false allows to register new route mock-ups for example.
|
|
181
|
+
*/
|
|
182
|
+
autoGoto: [true, { option: true }],
|
|
183
|
+
/**
|
|
184
|
+
* Mock JupyterLab config in-memory or not.
|
|
185
|
+
*
|
|
186
|
+
* Possible values are:
|
|
187
|
+
* - true (default): JupyterLab config will be mocked on a per test basis
|
|
188
|
+
* - false: JupyterLab config won't be mocked (Be careful it will write config in local files)
|
|
189
|
+
* - Record<string, JSONObject>: Initial JupyterLab data config - Mapping (config section, value).
|
|
190
|
+
*
|
|
191
|
+
* By default the config is stored in-memory.
|
|
192
|
+
*/
|
|
193
|
+
mockConfig: [true, { option: true }],
|
|
194
|
+
/**
|
|
195
|
+
* Mock JupyterLab state in-memory or not.
|
|
196
|
+
*
|
|
197
|
+
* Possible values are:
|
|
198
|
+
* - true (default): JupyterLab state will be mocked on a per test basis
|
|
199
|
+
* - false: JupyterLab state won't be mocked (Be careful it will write state in local files)
|
|
200
|
+
* - Record<string, unknown>: Initial JupyterLab data state - Mapping (state key, value).
|
|
201
|
+
*
|
|
202
|
+
* By default the state is stored in-memory
|
|
203
|
+
*/
|
|
204
|
+
mockState: [true, { option: true }],
|
|
205
|
+
/**
|
|
206
|
+
* Mock JupyterLab settings in-memory or not.
|
|
207
|
+
*
|
|
208
|
+
* Possible values are:
|
|
209
|
+
* - true: JupyterLab settings will be mocked on a per test basis
|
|
210
|
+
* - false: JupyterLab settings won't be mocked (Be careful it may write settings local files)
|
|
211
|
+
* - Record<string, unknown>: Mapping {pluginId: settings} that will be default user settings
|
|
212
|
+
*
|
|
213
|
+
* The default value is `galata.DEFAULT_SETTINGS`
|
|
214
|
+
*
|
|
215
|
+
* By default the settings are stored in-memory. However the
|
|
216
|
+
* they are still initialized with the hard drive values.
|
|
217
|
+
*/
|
|
218
|
+
mockSettings: [galata.DEFAULT_SETTINGS, { option: true }],
|
|
219
|
+
/**
|
|
220
|
+
* Mock JupyterLab user in-memory or not.
|
|
221
|
+
*
|
|
222
|
+
* Possible values are:
|
|
223
|
+
* - true (default): JupyterLab user will be mocked on a per test basis
|
|
224
|
+
* - false: JupyterLab user won't be mocked (It will be a random user so snapshots won't match)
|
|
225
|
+
* - Record<string, unknown>: Initial JupyterLab user - Mapping (user attribute, value).
|
|
226
|
+
*
|
|
227
|
+
* By default the user is stored in-memory.
|
|
228
|
+
*/
|
|
229
|
+
mockUser: [true, { option: true }],
|
|
230
|
+
/**
|
|
231
|
+
* Galata can keep the uploaded and created files in ``tmpPath`` on
|
|
232
|
+
* the server root for debugging purpose. By default the files are
|
|
233
|
+
* always deleted.
|
|
234
|
+
*
|
|
235
|
+
* - 'off' - ``tmpPath`` is deleted after each tests
|
|
236
|
+
* - 'on' - ``tmpPath`` is never deleted
|
|
237
|
+
* - 'only-on-failure' - ``tmpPath`` is deleted except if a test failed or timed out.
|
|
238
|
+
*/
|
|
239
|
+
serverFiles: ['off', { option: true }],
|
|
240
|
+
/**
|
|
241
|
+
* Sessions created during the test.
|
|
242
|
+
*
|
|
243
|
+
* Possible values are:
|
|
244
|
+
* - null: The sessions API won't be mocked
|
|
245
|
+
* - Map<string, Session.IModel>: The sessions created during a test.
|
|
246
|
+
*
|
|
247
|
+
* By default the sessions created during a test will be tracked and disposed at the end.
|
|
248
|
+
*/
|
|
249
|
+
sessions: async ({ request }, use) => {
|
|
250
|
+
const sessions = new Map<string, Session.IModel>();
|
|
251
|
+
|
|
252
|
+
await use(sessions);
|
|
253
|
+
|
|
254
|
+
if (sessions.size > 0) {
|
|
255
|
+
await galata.Mock.clearRunners(request, [...sessions.keys()], 'sessions');
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
/**
|
|
259
|
+
* Terminals created during the test.
|
|
260
|
+
*
|
|
261
|
+
* Possible values are:
|
|
262
|
+
* - null: The Terminals API won't be mocked
|
|
263
|
+
* - Map<string, TerminalAPI.IModel>: The Terminals created during a test.
|
|
264
|
+
*
|
|
265
|
+
* By default the Terminals created during a test will be tracked and disposed at the end.
|
|
266
|
+
*/
|
|
267
|
+
terminals: async ({ request }, use) => {
|
|
268
|
+
const terminals = new Map<string, TerminalAPI.IModel>();
|
|
269
|
+
|
|
270
|
+
await use(terminals);
|
|
271
|
+
|
|
272
|
+
if (terminals.size > 0) {
|
|
273
|
+
await galata.Mock.clearRunners(
|
|
274
|
+
request,
|
|
275
|
+
[...terminals.keys()],
|
|
276
|
+
'terminals'
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
/**
|
|
281
|
+
* Unique test temporary path created on the server.
|
|
282
|
+
*
|
|
283
|
+
* Note: if you override this string, you will need to take care of creating the
|
|
284
|
+
* folder and cleaning it.
|
|
285
|
+
*/
|
|
286
|
+
tmpPath: async ({ request, serverFiles }, use, testInfo) => {
|
|
287
|
+
// Remove appended retry part for reproducibility
|
|
288
|
+
const testFolder = path
|
|
289
|
+
.basename(testInfo.outputDir)
|
|
290
|
+
.replace(/-retry\d+$/i, '');
|
|
291
|
+
|
|
292
|
+
const contents = new ContentsHelper(request);
|
|
293
|
+
|
|
294
|
+
if (await contents.directoryExists(testFolder)) {
|
|
295
|
+
await contents.deleteDirectory(testFolder);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Create the test folder on the server
|
|
299
|
+
await contents.createDirectory(testFolder);
|
|
300
|
+
|
|
301
|
+
await use(testFolder);
|
|
302
|
+
|
|
303
|
+
// Delete the test folder on the server
|
|
304
|
+
// If serverFiles is 'on' or 'only-on-failure', keep the server files for the test
|
|
305
|
+
if (
|
|
306
|
+
serverFiles === 'off' ||
|
|
307
|
+
(serverFiles === 'only-on-failure' &&
|
|
308
|
+
(testInfo.status === 'passed' || testInfo.status === 'skipped'))
|
|
309
|
+
) {
|
|
310
|
+
await contents.deleteDirectory(testFolder);
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
/**
|
|
314
|
+
* Wait for the application page to be ready
|
|
315
|
+
*
|
|
316
|
+
* @param page Playwright Page model
|
|
317
|
+
* @param helpers JupyterLab helpers
|
|
318
|
+
*/
|
|
319
|
+
waitForApplication: async ({ baseURL }, use) => {
|
|
320
|
+
const waitIsReady = async (
|
|
321
|
+
page: Page,
|
|
322
|
+
helpers: IJupyterLabPage
|
|
323
|
+
): Promise<void> => {
|
|
324
|
+
await page.waitForSelector('#jupyterlab-splash', {
|
|
325
|
+
state: 'detached'
|
|
326
|
+
});
|
|
327
|
+
await helpers.waitForCondition(() => {
|
|
328
|
+
return helpers.activity.isTabActive('Launcher');
|
|
329
|
+
});
|
|
330
|
+
// Oddly current tab is not always set to active
|
|
331
|
+
if (!(await helpers.isInSimpleMode())) {
|
|
332
|
+
await helpers.activity.activateTab('Launcher');
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
await use(waitIsReady);
|
|
336
|
+
},
|
|
337
|
+
/**
|
|
338
|
+
* JupyterLab test page.
|
|
339
|
+
*
|
|
340
|
+
* It brings the following feature on top of Playwright Page object:
|
|
341
|
+
* - Goto to JupyterLab URL and wait for the application to be ready (autoGoto == true)
|
|
342
|
+
* - Helpers for JupyterLab
|
|
343
|
+
* - Settings mock-up
|
|
344
|
+
* - State mock-up
|
|
345
|
+
* - Track sessions and terminals opened during a test to close them at the end
|
|
346
|
+
*
|
|
347
|
+
* Note: If autoGoto is true, the filebrowser will be set inside tmpPath.
|
|
348
|
+
* Nothing is preventing you to navigate to some other folders.
|
|
349
|
+
* So you must avoid creating files outside that directory to avoid
|
|
350
|
+
* coupling effects between tests.
|
|
351
|
+
*/
|
|
352
|
+
// @ts-ignore
|
|
353
|
+
page: async (
|
|
354
|
+
{
|
|
355
|
+
appPath,
|
|
356
|
+
autoGoto,
|
|
357
|
+
baseURL,
|
|
358
|
+
mockConfig,
|
|
359
|
+
mockSettings,
|
|
360
|
+
mockState,
|
|
361
|
+
mockUser,
|
|
362
|
+
page,
|
|
363
|
+
sessions,
|
|
364
|
+
terminals,
|
|
365
|
+
tmpPath,
|
|
366
|
+
waitForApplication
|
|
367
|
+
},
|
|
368
|
+
use
|
|
369
|
+
) => {
|
|
370
|
+
await use(
|
|
371
|
+
await galata.initTestPage(
|
|
372
|
+
appPath,
|
|
373
|
+
autoGoto,
|
|
374
|
+
baseURL!,
|
|
375
|
+
mockConfig,
|
|
376
|
+
mockSettings,
|
|
377
|
+
mockState,
|
|
378
|
+
mockUser,
|
|
379
|
+
page,
|
|
380
|
+
sessions,
|
|
381
|
+
terminals,
|
|
382
|
+
tmpPath,
|
|
383
|
+
waitForApplication
|
|
384
|
+
)
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
});
|