@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
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import type { Notification } from '@jupyterlab/apputils';
|
|
5
|
+
import type { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
6
|
+
import type { ElementHandle, Page, Response } from '@playwright/test';
|
|
7
|
+
import { ContentsHelper } from './contents';
|
|
8
|
+
import type { IPluginNameToInterfaceMap } from './extension';
|
|
9
|
+
import {
|
|
10
|
+
ActivityHelper,
|
|
11
|
+
DebuggerHelper,
|
|
12
|
+
FileBrowserHelper,
|
|
13
|
+
KernelHelper,
|
|
14
|
+
LogConsoleHelper,
|
|
15
|
+
MenuHelper,
|
|
16
|
+
NotebookHelper,
|
|
17
|
+
PerformanceHelper,
|
|
18
|
+
SidebarHelper,
|
|
19
|
+
StatusBarHelper,
|
|
20
|
+
StyleHelper,
|
|
21
|
+
ThemeHelper
|
|
22
|
+
} from './helpers';
|
|
23
|
+
import * as Utils from './utils';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* JupyterLab page interface
|
|
27
|
+
*/
|
|
28
|
+
export interface IJupyterLabPageFixture
|
|
29
|
+
extends Omit<Page, 'goto'>,
|
|
30
|
+
IJupyterLabPage {}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* JupyterLab specific helpers interface
|
|
34
|
+
*/
|
|
35
|
+
export interface IJupyterLabPage {
|
|
36
|
+
/**
|
|
37
|
+
* Application URL path fragment
|
|
38
|
+
*/
|
|
39
|
+
readonly appPath: string;
|
|
40
|
+
/**
|
|
41
|
+
* JupyterLab activity helpers
|
|
42
|
+
*/
|
|
43
|
+
readonly activity: ActivityHelper;
|
|
44
|
+
/**
|
|
45
|
+
* JupyterLab contents helpers
|
|
46
|
+
*/
|
|
47
|
+
readonly contents: ContentsHelper;
|
|
48
|
+
/**
|
|
49
|
+
* JupyterLab filebrowser helpers
|
|
50
|
+
*/
|
|
51
|
+
readonly filebrowser: FileBrowserHelper;
|
|
52
|
+
/**
|
|
53
|
+
* JupyterLab kernel helpers
|
|
54
|
+
*/
|
|
55
|
+
readonly kernel: KernelHelper;
|
|
56
|
+
/**
|
|
57
|
+
* JupyterLab log console helpers
|
|
58
|
+
*/
|
|
59
|
+
readonly logconsole: LogConsoleHelper;
|
|
60
|
+
/**
|
|
61
|
+
* JupyterLab menu helpers
|
|
62
|
+
*/
|
|
63
|
+
readonly menu: MenuHelper;
|
|
64
|
+
/**
|
|
65
|
+
* JupyterLab notebook helpers
|
|
66
|
+
*/
|
|
67
|
+
readonly notebook: NotebookHelper;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* JupyterLab notifications
|
|
71
|
+
*/
|
|
72
|
+
readonly notifications: Promise<Notification.INotification[]>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Webbrowser performance helpers
|
|
76
|
+
*/
|
|
77
|
+
readonly performance: PerformanceHelper;
|
|
78
|
+
/**
|
|
79
|
+
* JupyterLab status bar helpers
|
|
80
|
+
*/
|
|
81
|
+
readonly statusbar: StatusBarHelper;
|
|
82
|
+
/**
|
|
83
|
+
* JupyterLab sidebar helpers
|
|
84
|
+
*/
|
|
85
|
+
readonly sidebar: SidebarHelper;
|
|
86
|
+
/**
|
|
87
|
+
* JupyterLab style helpers
|
|
88
|
+
*/
|
|
89
|
+
readonly style: StyleHelper;
|
|
90
|
+
/**
|
|
91
|
+
* JupyterLab theme helpers
|
|
92
|
+
*/
|
|
93
|
+
readonly theme: ThemeHelper;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Selector for launcher tab
|
|
97
|
+
*/
|
|
98
|
+
readonly launcherSelector: string;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Debugger helper
|
|
102
|
+
*/
|
|
103
|
+
readonly debugger: DebuggerHelper;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Getter for JupyterLab base URL
|
|
107
|
+
*/
|
|
108
|
+
getBaseUrl(): Promise<string>;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Getter for JupyterLab page configuration property
|
|
112
|
+
*
|
|
113
|
+
* @param name Option name
|
|
114
|
+
* @returns The property value
|
|
115
|
+
*/
|
|
116
|
+
getOption(name: string): Promise<string>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Getter for JupyterLab server root folder
|
|
120
|
+
*/
|
|
121
|
+
getServerRoot(): Promise<string | null>;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Getter for JupyterLab token
|
|
125
|
+
*/
|
|
126
|
+
getToken(): Promise<string>;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
|
|
130
|
+
* last redirect.
|
|
131
|
+
*
|
|
132
|
+
* This overrides the standard Playwright `page.goto` method by waiting for:
|
|
133
|
+
* - the application to be started (plugins are loaded)
|
|
134
|
+
* - the galata in page code to be injected
|
|
135
|
+
* - the splash screen to have disappeared
|
|
136
|
+
* - the launcher to be visible
|
|
137
|
+
*
|
|
138
|
+
* `page.goto` will throw an error if:
|
|
139
|
+
* - there's an SSL error (e.g. in case of self-signed certificates).
|
|
140
|
+
* - target URL is invalid.
|
|
141
|
+
* - the `timeout` is exceeded during navigation.
|
|
142
|
+
* - the remote server does not respond or is unreachable.
|
|
143
|
+
* - the main resource failed to load.
|
|
144
|
+
*
|
|
145
|
+
* `page.goto` will not throw an error when any valid HTTP status code is returned by the remote server, including 404 "Not
|
|
146
|
+
* Found" and 500 "Internal Server Error". The status code for such responses can be retrieved by calling
|
|
147
|
+
* [response.status()](https://playwright.dev/docs/api/class-response#response-status).
|
|
148
|
+
*
|
|
149
|
+
* > NOTE: `page.goto` either throws an error or returns a main resource response. The only exceptions are navigation to
|
|
150
|
+
* `about:blank` or navigation to the same URL with a different hash, which would succeed and return `null`.
|
|
151
|
+
* > NOTE: Headless mode doesn't support navigation to a PDF document. See the
|
|
152
|
+
* [upstream issue](https://bugs.chromium.org/p/chromium/issues/detail?id=761295).
|
|
153
|
+
*
|
|
154
|
+
* Shortcut for main frame's [frame.goto(url[, options])](https://playwright.dev/docs/api/class-frame#frame-goto)
|
|
155
|
+
* @param url URL to navigate page to. The url should include scheme, e.g. `https://`. When a `baseURL` via the context options was provided and the passed URL is a path, it gets merged via the
|
|
156
|
+
* [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor.
|
|
157
|
+
* @param options
|
|
158
|
+
*/
|
|
159
|
+
goto(
|
|
160
|
+
url?: string,
|
|
161
|
+
options?: {
|
|
162
|
+
/**
|
|
163
|
+
* Referer header value. If provided it will take preference over the referer header value set by
|
|
164
|
+
* [page.setExtraHTTPHeaders(headers)](https://playwright.dev/docs/api/class-page#page-set-extra-http-headers).
|
|
165
|
+
*/
|
|
166
|
+
referer?: string;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be
|
|
170
|
+
* changed by using the
|
|
171
|
+
* [browserContext.setDefaultNavigationTimeout(timeout)](https://playwright.dev/docs/api/class-browsercontext#browser-context-set-default-navigation-timeout),
|
|
172
|
+
* [browserContext.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-browsercontext#browser-context-set-default-timeout),
|
|
173
|
+
* [page.setDefaultNavigationTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-navigation-timeout)
|
|
174
|
+
* or [page.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-timeout) methods.
|
|
175
|
+
*/
|
|
176
|
+
timeout?: number;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* When to consider operation succeeded, defaults to `load`. Events can be either:
|
|
180
|
+
* - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired.
|
|
181
|
+
* - `'load'` - consider operation to be finished when the `load` event is fired.
|
|
182
|
+
* - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms.
|
|
183
|
+
* - `'commit'` - consider operation to be finished when network response is received and the document started loading.
|
|
184
|
+
*/
|
|
185
|
+
waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' | 'commit';
|
|
186
|
+
}
|
|
187
|
+
): Promise<Response | null>;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Whether JupyterLab is in simple mode or not
|
|
191
|
+
*/
|
|
192
|
+
isInSimpleMode(): Promise<boolean>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Reset the User Interface
|
|
196
|
+
*/
|
|
197
|
+
resetUI(): Promise<void>;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Set JupyterLab simple mode
|
|
201
|
+
*
|
|
202
|
+
* @param simple Simple mode value
|
|
203
|
+
* @returns Whether this operation succeeds or not
|
|
204
|
+
*/
|
|
205
|
+
setSimpleMode(simple: boolean): Promise<boolean>;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Wait for a condition to be fulfilled
|
|
209
|
+
*
|
|
210
|
+
* @param condition Condition to fulfill
|
|
211
|
+
* @param timeout Maximal time to wait for the condition to be true
|
|
212
|
+
*/
|
|
213
|
+
waitForCondition(
|
|
214
|
+
condition: () => Promise<boolean> | boolean,
|
|
215
|
+
timeout?: number
|
|
216
|
+
): Promise<void>;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Wait for an element to emit 'transitionend' event.
|
|
220
|
+
*
|
|
221
|
+
* @param element Element or selector to watch
|
|
222
|
+
*/
|
|
223
|
+
waitForTransition(element: ElementHandle<Element> | string): Promise<void>;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Factory for active activity tab xpath
|
|
227
|
+
*
|
|
228
|
+
* @returns The selector
|
|
229
|
+
*/
|
|
230
|
+
xpBuildActiveActivityTabSelector(): string;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Factory for activity panel xpath by id
|
|
234
|
+
* @param id Panel id
|
|
235
|
+
* @returns The selector
|
|
236
|
+
*/
|
|
237
|
+
xpBuildActivityPanelSelector(id: string): string;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Factory for activity tab xpath by name
|
|
241
|
+
*
|
|
242
|
+
* @param name Activity name
|
|
243
|
+
* @returns The selector
|
|
244
|
+
*/
|
|
245
|
+
xpBuildActivityTabSelector(name: string): string;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Factory for element containing a given class xpath
|
|
249
|
+
*
|
|
250
|
+
* @param className Class name
|
|
251
|
+
* @returns The selector
|
|
252
|
+
*/
|
|
253
|
+
xpContainsClass(className: string): string;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Wrapper class around Playwright Page object.
|
|
258
|
+
*/
|
|
259
|
+
export class JupyterLabPage implements IJupyterLabPage {
|
|
260
|
+
/**
|
|
261
|
+
* Page object model for JupyterLab
|
|
262
|
+
*
|
|
263
|
+
* @param page Playwright page object
|
|
264
|
+
* @param baseURL Server base URL
|
|
265
|
+
* @param waitForApplication Callback that resolved when the application page is ready
|
|
266
|
+
* @param appPath Application URL path fragment
|
|
267
|
+
*/
|
|
268
|
+
constructor(
|
|
269
|
+
readonly page: Page,
|
|
270
|
+
readonly baseURL: string,
|
|
271
|
+
waitForApplication: (page: Page, helpers: IJupyterLabPage) => Promise<void>,
|
|
272
|
+
readonly appPath: string = '/lab'
|
|
273
|
+
) {
|
|
274
|
+
this.waitIsReady = waitForApplication;
|
|
275
|
+
this.activity = new ActivityHelper(page);
|
|
276
|
+
this.contents = new ContentsHelper(page.context().request, page);
|
|
277
|
+
this.filebrowser = new FileBrowserHelper(page, this.contents);
|
|
278
|
+
this.kernel = new KernelHelper(page);
|
|
279
|
+
this.logconsole = new LogConsoleHelper(page);
|
|
280
|
+
this.menu = new MenuHelper(page);
|
|
281
|
+
this.notebook = new NotebookHelper(
|
|
282
|
+
page,
|
|
283
|
+
this.activity,
|
|
284
|
+
this.contents,
|
|
285
|
+
this.filebrowser,
|
|
286
|
+
this.menu
|
|
287
|
+
);
|
|
288
|
+
this.performance = new PerformanceHelper(page);
|
|
289
|
+
this.statusbar = new StatusBarHelper(page, this.menu);
|
|
290
|
+
this.sidebar = new SidebarHelper(page, this.menu);
|
|
291
|
+
this.style = new StyleHelper(page);
|
|
292
|
+
this.theme = new ThemeHelper(page);
|
|
293
|
+
this.debugger = new DebuggerHelper(page, this.sidebar, this.notebook);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* JupyterLab activity helpers
|
|
298
|
+
*/
|
|
299
|
+
readonly activity: ActivityHelper;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* JupyterLab contents helpers
|
|
303
|
+
*/
|
|
304
|
+
readonly contents: ContentsHelper;
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* JupyterLab filebrowser helpers
|
|
308
|
+
*/
|
|
309
|
+
readonly filebrowser: FileBrowserHelper;
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* JupyterLab kernel helpers
|
|
313
|
+
*/
|
|
314
|
+
readonly kernel: KernelHelper;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* JupyterLab log console helpers
|
|
318
|
+
*/
|
|
319
|
+
readonly logconsole: LogConsoleHelper;
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* JupyterLab menu helpers
|
|
323
|
+
*/
|
|
324
|
+
readonly menu: MenuHelper;
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* JupyterLab notebook helpers
|
|
328
|
+
*/
|
|
329
|
+
readonly notebook: NotebookHelper;
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* JupyterLab notifications
|
|
333
|
+
*/
|
|
334
|
+
get notifications(): Promise<Notification.INotification[]> {
|
|
335
|
+
return this.page.evaluate(async () => window.galata.getNotifications());
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Webbrowser performance helpers
|
|
340
|
+
*/
|
|
341
|
+
readonly performance: PerformanceHelper;
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* JupyterLab status bar helpers
|
|
345
|
+
*/
|
|
346
|
+
readonly statusbar: StatusBarHelper;
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* JupyterLab sidebar helpers
|
|
350
|
+
*/
|
|
351
|
+
readonly sidebar: SidebarHelper;
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* JupyterLab style helpers
|
|
355
|
+
*/
|
|
356
|
+
readonly style: StyleHelper;
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* JupyterLab theme helpers
|
|
360
|
+
*/
|
|
361
|
+
readonly theme: ThemeHelper;
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* JupyterLab debugger helper
|
|
365
|
+
*/
|
|
366
|
+
readonly debugger: DebuggerHelper;
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Selector for launcher tab
|
|
370
|
+
*/
|
|
371
|
+
get launcherSelector(): string {
|
|
372
|
+
return this.activity.launcherSelector;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Getter for JupyterLab base URL
|
|
377
|
+
*/
|
|
378
|
+
async getBaseUrl(): Promise<string> {
|
|
379
|
+
return Utils.getBaseUrl(this.page);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Getter for JupyterLab page configuration property
|
|
384
|
+
*
|
|
385
|
+
* @param name Option name
|
|
386
|
+
* @returns The property value
|
|
387
|
+
*/
|
|
388
|
+
async getOption(name: string): Promise<string> {
|
|
389
|
+
return Utils.getOption(this.page, name);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Getter for JupyterLab server root folder
|
|
394
|
+
*/
|
|
395
|
+
async getServerRoot(): Promise<string | null> {
|
|
396
|
+
return (await Utils.getOption(this.page, 'serverRoot')) ?? null;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Getter for JupyterLab token
|
|
401
|
+
*/
|
|
402
|
+
async getToken(): Promise<string> {
|
|
403
|
+
return Utils.getToken(this.page);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
|
|
408
|
+
* last redirect.
|
|
409
|
+
*
|
|
410
|
+
* This overrides the standard Playwright `page.goto` method by waiting for:
|
|
411
|
+
* - the application to be started (plugins are loaded)
|
|
412
|
+
* - the galata in page code to be injected
|
|
413
|
+
* - the splash screen to have disappeared
|
|
414
|
+
* - the launcher to be visible
|
|
415
|
+
*
|
|
416
|
+
* `page.goto` will throw an error if:
|
|
417
|
+
* - there's an SSL error (e.g. in case of self-signed certificates).
|
|
418
|
+
* - target URL is invalid.
|
|
419
|
+
* - the `timeout` is exceeded during navigation.
|
|
420
|
+
* - the remote server does not respond or is unreachable.
|
|
421
|
+
* - the main resource failed to load.
|
|
422
|
+
*
|
|
423
|
+
* `page.goto` will not throw an error when any valid HTTP status code is returned by the remote server, including 404 "Not
|
|
424
|
+
* Found" and 500 "Internal Server Error". The status code for such responses can be retrieved by calling
|
|
425
|
+
* [response.status()](https://playwright.dev/docs/api/class-response#response-status).
|
|
426
|
+
*
|
|
427
|
+
* > NOTE: `page.goto` either throws an error or returns a main resource response. The only exceptions are navigation to
|
|
428
|
+
* `about:blank` or navigation to the same URL with a different hash, which would succeed and return `null`.
|
|
429
|
+
* > NOTE: Headless mode doesn't support navigation to a PDF document. See the
|
|
430
|
+
* [upstream issue](https://bugs.chromium.org/p/chromium/issues/detail?id=761295).
|
|
431
|
+
*
|
|
432
|
+
* Shortcut for main frame's [frame.goto(url[, options])](https://playwright.dev/docs/api/class-frame#frame-goto)
|
|
433
|
+
* @param url URL to navigate page to. The url should include scheme, e.g. `https://`. When a `baseURL` via the context options was provided and the passed URL is a path, it gets merged via the
|
|
434
|
+
* [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) constructor.
|
|
435
|
+
* @param options
|
|
436
|
+
*/
|
|
437
|
+
async goto(
|
|
438
|
+
url?: string,
|
|
439
|
+
options?: {
|
|
440
|
+
/**
|
|
441
|
+
* Referer header value. If provided it will take preference over the referer header value set by
|
|
442
|
+
* [page.setExtraHTTPHeaders(headers)](https://playwright.dev/docs/api/class-page#page-set-extra-http-headers).
|
|
443
|
+
*/
|
|
444
|
+
referer?: string;
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be
|
|
448
|
+
* changed by using the
|
|
449
|
+
* [browserContext.setDefaultNavigationTimeout(timeout)](https://playwright.dev/docs/api/class-browsercontext#browser-context-set-default-navigation-timeout),
|
|
450
|
+
* [browserContext.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-browsercontext#browser-context-set-default-timeout),
|
|
451
|
+
* [page.setDefaultNavigationTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-navigation-timeout)
|
|
452
|
+
* or [page.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-timeout) methods.
|
|
453
|
+
*/
|
|
454
|
+
timeout?: number;
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* When to consider operation succeeded, defaults to `load`. Events can be either:
|
|
458
|
+
* - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired.
|
|
459
|
+
* - `'load'` - consider operation to be finished when the `load` event is fired.
|
|
460
|
+
* - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms.
|
|
461
|
+
*/
|
|
462
|
+
waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';
|
|
463
|
+
}
|
|
464
|
+
): Promise<Response | null> {
|
|
465
|
+
const target = url?.startsWith('http')
|
|
466
|
+
? url
|
|
467
|
+
: `${this.baseURL}${this.appPath}/${url ?? ''}`;
|
|
468
|
+
|
|
469
|
+
const response = await this.page.goto(target, {
|
|
470
|
+
...(options ?? {}),
|
|
471
|
+
waitUntil: options?.waitUntil ?? 'domcontentloaded'
|
|
472
|
+
});
|
|
473
|
+
await this.waitForAppStarted();
|
|
474
|
+
await this.hookHelpersUp();
|
|
475
|
+
await this.waitIsReady(this.page, this);
|
|
476
|
+
|
|
477
|
+
return response;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Whether JupyterLab is in simple mode or not
|
|
482
|
+
*/
|
|
483
|
+
isInSimpleMode = async (): Promise<boolean> => {
|
|
484
|
+
const toggle = await this.page.$(
|
|
485
|
+
'#jp-single-document-mode button.jp-switch'
|
|
486
|
+
);
|
|
487
|
+
const checked = (await toggle?.getAttribute('aria-checked')) === 'true';
|
|
488
|
+
|
|
489
|
+
return checked;
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
|
|
494
|
+
* last redirect.
|
|
495
|
+
*
|
|
496
|
+
* This overrides the standard Playwright `page.reload` method by waiting for:
|
|
497
|
+
* - the application to be started (plugins are loaded)
|
|
498
|
+
* - the galata in page code to be injected
|
|
499
|
+
* - the splash screen to have disappeared
|
|
500
|
+
* - the launcher to be visible
|
|
501
|
+
*
|
|
502
|
+
* @param options
|
|
503
|
+
*/
|
|
504
|
+
async reload(options?: {
|
|
505
|
+
/**
|
|
506
|
+
* Maximum operation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be
|
|
507
|
+
* changed by using the
|
|
508
|
+
* [browserContext.setDefaultNavigationTimeout(timeout)](https://playwright.dev/docs/api/class-browsercontext#browser-context-set-default-navigation-timeout),
|
|
509
|
+
* [browserContext.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-browsercontext#browser-context-set-default-timeout),
|
|
510
|
+
* [page.setDefaultNavigationTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-navigation-timeout)
|
|
511
|
+
* or [page.setDefaultTimeout(timeout)](https://playwright.dev/docs/api/class-page#page-set-default-timeout) methods.
|
|
512
|
+
*/
|
|
513
|
+
timeout?: number;
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* When to consider operation succeeded, defaults to `load`. Events can be either:
|
|
517
|
+
* - `'domcontentloaded'` - consider operation to be finished when the `DOMContentLoaded` event is fired.
|
|
518
|
+
* - `'load'` - consider operation to be finished when the `load` event is fired.
|
|
519
|
+
* - `'networkidle'` - consider operation to be finished when there are no network connections for at least `500` ms.
|
|
520
|
+
* - `'commit'` - consider operation to be finished when network response is received and the document started loading.
|
|
521
|
+
*/
|
|
522
|
+
waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' | 'commit';
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Whether to wait for fixture `waitIsReady` or not when reloading.
|
|
526
|
+
*
|
|
527
|
+
* Default is true.
|
|
528
|
+
*/
|
|
529
|
+
waitForIsReady?: boolean;
|
|
530
|
+
}): Promise<Response | null> {
|
|
531
|
+
const response = await this.page.reload({
|
|
532
|
+
timeout: options?.timeout,
|
|
533
|
+
waitUntil: options?.waitUntil ?? 'domcontentloaded'
|
|
534
|
+
});
|
|
535
|
+
await this.waitForAppStarted();
|
|
536
|
+
await this.hookHelpersUp();
|
|
537
|
+
if (options?.waitForIsReady ?? true) {
|
|
538
|
+
await this.waitIsReady(this.page, this);
|
|
539
|
+
}
|
|
540
|
+
return response;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Reset the User Interface
|
|
545
|
+
*/
|
|
546
|
+
async resetUI(): Promise<void> {
|
|
547
|
+
// close menus
|
|
548
|
+
await this.menu.closeAll();
|
|
549
|
+
// close all panels
|
|
550
|
+
await this.activity.closeAll();
|
|
551
|
+
// shutdown kernels
|
|
552
|
+
await this.kernel.shutdownAll();
|
|
553
|
+
// show status bar
|
|
554
|
+
await this.statusbar.show();
|
|
555
|
+
// Reset the layout
|
|
556
|
+
await this.page.evaluate(
|
|
557
|
+
async ({ pluginId }) => {
|
|
558
|
+
const settingRegistry = (await window.galata.getPlugin(
|
|
559
|
+
pluginId
|
|
560
|
+
)) as ISettingRegistry;
|
|
561
|
+
const SHELL_ID = '@jupyterlab/application-extension:shell';
|
|
562
|
+
await settingRegistry.remove(SHELL_ID, 'layout');
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
pluginId:
|
|
566
|
+
'@jupyterlab/apputils-extension:settings' as keyof IPluginNameToInterfaceMap
|
|
567
|
+
}
|
|
568
|
+
);
|
|
569
|
+
// show Files tab on sidebar
|
|
570
|
+
await this.sidebar.openTab('filebrowser');
|
|
571
|
+
// go to home folder
|
|
572
|
+
await this.filebrowser.openHomeDirectory();
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Set JupyterLab simple mode
|
|
577
|
+
*
|
|
578
|
+
* @param simple Simple mode value
|
|
579
|
+
* @returns Whether this operation succeeds or not
|
|
580
|
+
*/
|
|
581
|
+
async setSimpleMode(simple: boolean): Promise<boolean> {
|
|
582
|
+
const toggle = await this.page.$(
|
|
583
|
+
'#jp-single-document-mode button.jp-switch'
|
|
584
|
+
);
|
|
585
|
+
if (toggle) {
|
|
586
|
+
const checked = (await toggle.getAttribute('aria-checked')) === 'true';
|
|
587
|
+
|
|
588
|
+
if ((checked && !simple) || (!checked && simple)) {
|
|
589
|
+
await Promise.all([
|
|
590
|
+
Utils.waitForTransition(this.page, toggle),
|
|
591
|
+
toggle.click()
|
|
592
|
+
]);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
await Utils.waitForCondition(async () => {
|
|
596
|
+
return (await this.isInSimpleMode()) === simple;
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
return true;
|
|
600
|
+
}
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Wait for a condition to be fulfilled
|
|
606
|
+
*
|
|
607
|
+
* @param condition Condition to fulfill
|
|
608
|
+
* @param timeout Maximal time to wait for the condition to be true
|
|
609
|
+
*/
|
|
610
|
+
async waitForCondition(
|
|
611
|
+
condition: () => Promise<boolean> | boolean,
|
|
612
|
+
timeout?: number
|
|
613
|
+
): Promise<void> {
|
|
614
|
+
return Utils.waitForCondition(condition, timeout);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Wait for an element to emit 'transitionend' event.
|
|
619
|
+
*
|
|
620
|
+
* @param element Element or selector to watch
|
|
621
|
+
*/
|
|
622
|
+
async waitForTransition(
|
|
623
|
+
element: ElementHandle<Element> | string
|
|
624
|
+
): Promise<void> {
|
|
625
|
+
return Utils.waitForTransition(this.page, element);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Factory for active activity tab xpath
|
|
630
|
+
*/
|
|
631
|
+
xpBuildActiveActivityTabSelector(): string {
|
|
632
|
+
return Utils.xpBuildActiveActivityTabSelector();
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Factory for activity panel xpath by id
|
|
637
|
+
* @param id Panel id
|
|
638
|
+
*/
|
|
639
|
+
xpBuildActivityPanelSelector(id: string): string {
|
|
640
|
+
return Utils.xpBuildActivityPanelSelector(id);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Factory for activity tab xpath by name
|
|
645
|
+
* @param name Activity name
|
|
646
|
+
*/
|
|
647
|
+
xpBuildActivityTabSelector(name: string): string {
|
|
648
|
+
return Utils.xpBuildActivityTabSelector(name);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Factory for element containing a given class xpath
|
|
653
|
+
* @param className Class name
|
|
654
|
+
*/
|
|
655
|
+
xpContainsClass(className: string): string {
|
|
656
|
+
return Utils.xpContainsClass(className);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Inject the galata in-page helpers
|
|
661
|
+
*/
|
|
662
|
+
protected async hookHelpersUp(): Promise<void> {
|
|
663
|
+
// Check galata helpers are loaded
|
|
664
|
+
const galataipDefined = await this.page.evaluate(() => {
|
|
665
|
+
return Promise.resolve(typeof window.galata === 'object');
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
if (!galataipDefined) {
|
|
669
|
+
throw new Error('Failed to activate galata extension');
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
const jlabAccessible = await this.page.evaluate(() => {
|
|
673
|
+
return Promise.resolve(typeof window.galata.app === 'object');
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
if (!jlabAccessible) {
|
|
677
|
+
throw new Error('Failed to access JupyterLab object in browser context');
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Wait for the application to be started
|
|
683
|
+
*/
|
|
684
|
+
protected waitForAppStarted = async (): Promise<void> => {
|
|
685
|
+
return this.waitForCondition(() =>
|
|
686
|
+
this.page.evaluate(async () => {
|
|
687
|
+
if (typeof window.jupyterapp === 'object') {
|
|
688
|
+
// Wait for plugins to be loaded
|
|
689
|
+
await window.jupyterapp.started;
|
|
690
|
+
return true;
|
|
691
|
+
}
|
|
692
|
+
return false;
|
|
693
|
+
})
|
|
694
|
+
);
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Wait for the splash screen to be hidden and the launcher to be the active tab.
|
|
699
|
+
*/
|
|
700
|
+
protected waitIsReady: (
|
|
701
|
+
page: Page,
|
|
702
|
+
helpers: IJupyterLabPage
|
|
703
|
+
) => Promise<void>;
|
|
704
|
+
}
|