@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.
Files changed (100) hide show
  1. package/README.md +192 -31
  2. package/lib/benchmarkReporter.d.ts +1 -0
  3. package/lib/benchmarkReporter.js +34 -39
  4. package/lib/benchmarkReporter.js.map +1 -1
  5. package/lib/benchmarkVLTpl.js +19 -5
  6. package/lib/benchmarkVLTpl.js.map +1 -1
  7. package/lib/contents.d.ts +5 -5
  8. package/lib/contents.js +32 -36
  9. package/lib/contents.js.map +1 -1
  10. package/lib/extension/global.d.ts +197 -0
  11. package/lib/extension/global.js +601 -0
  12. package/lib/extension/global.js.map +1 -0
  13. package/lib/extension/index.d.ts +6 -0
  14. package/lib/extension/index.js +27 -0
  15. package/lib/extension/index.js.map +1 -0
  16. package/lib/extension/tokens.d.ts +232 -0
  17. package/lib/extension/tokens.js +13 -0
  18. package/lib/extension/tokens.js.map +1 -0
  19. package/lib/extension.d.ts +223 -0
  20. package/lib/{global.js → extension.js} +1 -2
  21. package/lib/extension.js.map +1 -0
  22. package/lib/fixtures.d.ts +32 -10
  23. package/lib/fixtures.js +64 -17
  24. package/lib/fixtures.js.map +1 -1
  25. package/lib/galata.d.ts +140 -19
  26. package/lib/galata.js +272 -87
  27. package/lib/galata.js.map +1 -1
  28. package/lib/helpers/activity.d.ts +6 -0
  29. package/lib/helpers/activity.js +19 -5
  30. package/lib/helpers/activity.js.map +1 -1
  31. package/lib/helpers/debuggerpanel.d.ts +4 -0
  32. package/lib/helpers/debuggerpanel.js +16 -0
  33. package/lib/helpers/debuggerpanel.js.map +1 -1
  34. package/lib/helpers/filebrowser.js +8 -2
  35. package/lib/helpers/filebrowser.js.map +1 -1
  36. package/lib/helpers/index.d.ts +1 -0
  37. package/lib/helpers/index.js +6 -1
  38. package/lib/helpers/index.js.map +1 -1
  39. package/lib/helpers/kernel.js +7 -7
  40. package/lib/helpers/kernel.js.map +1 -1
  41. package/lib/helpers/menu.d.ts +7 -0
  42. package/lib/helpers/menu.js +17 -1
  43. package/lib/helpers/menu.js.map +1 -1
  44. package/lib/helpers/notebook.d.ts +6 -4
  45. package/lib/helpers/notebook.js +127 -31
  46. package/lib/helpers/notebook.js.map +1 -1
  47. package/lib/helpers/sidebar.d.ts +8 -1
  48. package/lib/helpers/sidebar.js +33 -15
  49. package/lib/helpers/sidebar.js.map +1 -1
  50. package/lib/helpers/statusbar.js +1 -1
  51. package/lib/helpers/statusbar.js.map +1 -1
  52. package/lib/helpers/style.d.ts +42 -0
  53. package/lib/helpers/style.js +50 -0
  54. package/lib/helpers/style.js.map +1 -0
  55. package/lib/helpers/theme.js +1 -1
  56. package/lib/helpers/theme.js.map +1 -1
  57. package/lib/index.d.ts +5 -2
  58. package/lib/index.js +12 -3
  59. package/lib/index.js.map +1 -1
  60. package/lib/jupyterlabpage.d.ts +29 -4
  61. package/lib/jupyterlabpage.js +38 -22
  62. package/lib/jupyterlabpage.js.map +1 -1
  63. package/lib/playwright-config.js +5 -1
  64. package/lib/playwright-config.js.map +1 -1
  65. package/lib/utils.js +5 -1
  66. package/lib/utils.js.map +1 -1
  67. package/package.json +31 -47
  68. package/src/benchmarkReporter.ts +756 -0
  69. package/src/benchmarkVLTpl.ts +91 -0
  70. package/src/contents.ts +472 -0
  71. package/src/extension.ts +281 -0
  72. package/src/fixtures.ts +387 -0
  73. package/src/galata.ts +1035 -0
  74. package/src/helpers/activity.ts +115 -0
  75. package/src/helpers/debuggerpanel.ts +159 -0
  76. package/src/helpers/filebrowser.ts +228 -0
  77. package/src/helpers/index.ts +15 -0
  78. package/src/helpers/kernel.ts +39 -0
  79. package/src/helpers/logconsole.ts +32 -0
  80. package/src/helpers/menu.ts +228 -0
  81. package/src/helpers/notebook.ts +1217 -0
  82. package/src/helpers/performance.ts +57 -0
  83. package/src/helpers/sidebar.ts +289 -0
  84. package/src/helpers/statusbar.ts +56 -0
  85. package/src/helpers/style.ts +100 -0
  86. package/src/helpers/theme.ts +50 -0
  87. package/src/index.ts +19 -0
  88. package/src/jupyterlabpage.ts +704 -0
  89. package/src/playwright-config.ts +26 -0
  90. package/src/utils.ts +264 -0
  91. package/src/vega-statistics.d.ts +15 -0
  92. package/lib/global.d.ts +0 -23
  93. package/lib/global.js.map +0 -1
  94. package/lib/inpage/tokens.d.ts +0 -135
  95. package/lib/inpage/tokens.js +0 -9
  96. package/lib/inpage/tokens.js.map +0 -1
  97. package/lib/lib-inpage/inpage.js +0 -3957
  98. package/lib/lib-inpage/inpage.js.map +0 -1
  99. package/style/index.css +0 -10
  100. 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
+ }