Skip to content

Commit

Permalink
[GSoC 2024] Use toolkit tree view for all tree view: table of content…
Browse files Browse the repository at this point in the history
…, debugger variables and running tabs (jupyterlab#16488)

* Use Jupyter toolkit treeview

Co-authored-by: Mehak261124 <145124929+Mehak261124@users.noreply.github.com>

* Fix snapshots

* Fix buttons styling

* Fix integration tests

* Reduce left margin for flat list

* Fix integration tests

* Ask explicitly the type of sessions view

* Update snapshots

* Bump toolkit to 0.16.5

Fix styling of first-level tree items

* Bump toolkit to 0.16.6

* Reduce spacing between icon and label

* Avoid horizontal position change when switching from flat to hierarchical tree view

* Update snapshots

* Improve positioning for flat tree

* Fix typescript

* Update snapshots

* Make the workspace panel integration test more robust

* Mock the kernels API for robuster running panel integration tests

* Fix kernels mock

* Update snapshots

---------

Co-authored-by: Frédéric Collonval <fcollonval@users.noreply.github.com>
  • Loading branch information
Mehak261124 and fcollonval authored Jul 23, 2024
1 parent ef5a055 commit 450e8fc
Show file tree
Hide file tree
Showing 54 changed files with 725 additions and 734 deletions.
4 changes: 2 additions & 2 deletions dev_mode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.2.0",
"@codemirror/view": "^6.9.6",
"@jupyter/react-components": "^0.16.3",
"@jupyter/web-components": "^0.16.3",
"@jupyter/react-components": "^0.16.6",
"@jupyter/web-components": "^0.16.6",
"@jupyter/ydoc": "^2.0.1",
"@jupyterlab/application": "~4.3.0-alpha.2",
"@jupyterlab/application-extension": "~4.3.0-alpha.2",
Expand Down
2 changes: 1 addition & 1 deletion examples/cell/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"clean": "rimraf build"
},
"dependencies": {
"@jupyter/web-components": "^0.16.3",
"@jupyter/web-components": "^0.16.6",
"@jupyter/ydoc": "^2.0.1",
"@jupyterlab/application": "^4.3.0-alpha.2",
"@jupyterlab/apputils": "^4.4.0-alpha.2",
Expand Down
2 changes: 1 addition & 1 deletion examples/console/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"clean": "rimraf build"
},
"dependencies": {
"@jupyter/web-components": "^0.16.3",
"@jupyter/web-components": "^0.16.6",
"@jupyter/ydoc": "^2.0.1",
"@jupyterlab/application": "^4.3.0-alpha.2",
"@jupyterlab/codemirror": "^4.3.0-alpha.2",
Expand Down
2 changes: 1 addition & 1 deletion examples/filebrowser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"clean": "rimraf build"
},
"dependencies": {
"@jupyter/web-components": "^0.16.3",
"@jupyter/web-components": "^0.16.6",
"@jupyterlab/application": "^4.3.0-alpha.2",
"@jupyterlab/apputils": "^4.4.0-alpha.2",
"@jupyterlab/codemirror": "^4.3.0-alpha.2",
Expand Down
2 changes: 1 addition & 1 deletion examples/notebook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"clean": "rimraf build"
},
"dependencies": {
"@jupyter/web-components": "^0.16.3",
"@jupyter/web-components": "^0.16.6",
"@jupyter/ydoc": "^2.0.1",
"@jupyterlab/application": "^4.3.0-alpha.2",
"@jupyterlab/apputils": "^4.4.0-alpha.2",
Expand Down
2 changes: 1 addition & 1 deletion examples/terminal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"clean": "rimraf build"
},
"dependencies": {
"@jupyter/web-components": "^0.16.3",
"@jupyter/web-components": "^0.16.6",
"@jupyterlab/application": "^4.3.0-alpha.2",
"@jupyterlab/coreutils": "^6.3.0-alpha.2",
"@jupyterlab/services": "^7.3.0-alpha.2",
Expand Down
30 changes: 30 additions & 0 deletions galata/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,36 @@ Possible values are:

By default the user is stored in-memory.

### kernels

- type: \<Map\<string, Kernel.IModel> | null>

Kernels created during the test.
Possible values are:

- null: The kernels API won't be mocked
- Map\<string, Kernel.IModel>: The kernels created during a test.
By default the kernels created during a test will be tracked and disposed at the end.

Example:

```ts
test('should return the active kernels', async ({ page, kernels }) => {
await page.notebook.createNew();

// Wait for the poll to tick
await page.waitForResponse(
async response =>
response.url().includes('api/kernels') &&
response.request().method() === 'GET' &&
((await response.json()) as any[]).length === 1
);

expect(kernels.size).toEqual(1);
// You can introspect the kernels.values()[0] if needed
});
```

### sessions

- type: \<Map\<string, Session.IModel> | null>
Expand Down
34 changes: 32 additions & 2 deletions galata/src/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import type { Session, TerminalAPI, User } from '@jupyterlab/services';
import type { Kernel, Session, TerminalAPI, User } from '@jupyterlab/services';
import {
test as base,
Page,
Expand Down Expand Up @@ -56,6 +56,16 @@ export type GalataOptions = {
* Default: true
*/
autoGoto: boolean;
/**
* Kernels created during the test.
*
* Possible values are:
* - null: The kernels API won't be mocked
* - Map<string, Kernel.IModel>: The kernels created during a test.
*
* By default the kernels created during a test will be tracked and disposed at the end.
*/
kernels: Map<string, Kernel.IModel> | null;
/**
* Mock JupyterLab config in-memory or not.
*
Expand Down Expand Up @@ -180,6 +190,24 @@ export const test: TestType<
* Note: Setting it to false allows to register new route mock-ups for example.
*/
autoGoto: [true, { option: true }],
/**
* Kernels created during the test.
*
* Possible values are:
* - null: The kernels API won't be mocked
* - Map<string, Kernel.IModel>: The kernels created during a test.
*
* By default the kernels created during a test will be tracked and disposed at the end.
*/
kernels: async ({ request }, use) => {
const kernels = new Map<string, Kernel.IModel>();

await use(kernels);

if (kernels.size > 0) {
await galata.Mock.clearRunners(request, [...kernels.keys()], 'kernels');
}
},
/**
* Mock JupyterLab config in-memory or not.
*
Expand Down Expand Up @@ -353,6 +381,7 @@ export const test: TestType<
appPath,
autoGoto,
baseURL,
kernels,
mockConfig,
mockSettings,
mockState,
Expand All @@ -378,7 +407,8 @@ export const test: TestType<
sessions,
terminals,
tmpPath,
waitForApplication
waitForApplication,
kernels
)
);
}
Expand Down
66 changes: 53 additions & 13 deletions galata/src/galata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import type * as nbformat from '@jupyterlab/nbformat';
import type {
Kernel,
Session,
TerminalAPI,
User,
Expand Down Expand Up @@ -150,6 +151,12 @@ export namespace galata {
* Default true
*/
mockUser?: boolean | Partial<User.IUser>;
/**
* Whether to store kernels in memory or not.
*
* Default true
*/
mockKernels?: boolean;
/**
* Whether to store sessions in memory or not.
*
Expand Down Expand Up @@ -216,7 +223,8 @@ export namespace galata {
sessions: Map<string, Session.IModel> | null,
terminals: Map<string, TerminalAPI.IModel> | null,
tmpPath: string,
waitForApplication: (page: Page, helpers: IJupyterLabPage) => Promise<void>
waitForApplication: (page: Page, helpers: IJupyterLabPage) => Promise<void>,
kernels?: Map<string, Kernel.IModel> | null
): Promise<IJupyterLabPageFixture> {
// Hook the helpers
const jlabWithPage = addHelpersToPage(
Expand Down Expand Up @@ -273,9 +281,12 @@ export namespace galata {
await Mock.mockUser(page, user);
}

// Add sessions and terminals trackers
// Add kernels, sessions and terminals trackers
if (kernels) {
await Mock.mockRunners(page, kernels, 'kernels');
}
if (sessions) {
await Mock.mockRunners(page, sessions, 'sessions');
await Mock.mockRunners(page, sessions, 'sessions', kernels ?? undefined);
}
if (terminals) {
await Mock.mockRunners(page, terminals, 'terminals');
Expand Down Expand Up @@ -310,6 +321,7 @@ export namespace galata {
*/
export async function newPage(options: INewPageOption): Promise<{
page: IJupyterLabPageFixture;
kernels: Map<string, Kernel.IModel> | null;
sessions: Map<string, Session.IModel> | null;
terminals: Map<string, TerminalAPI.IModel> | null;
}> {
Expand All @@ -320,6 +332,7 @@ export namespace galata {
browser,
waitForApplication,
mockConfig,
mockKernels,
mockSessions,
mockSettings,
mockState,
Expand All @@ -330,6 +343,7 @@ export namespace galata {
appPath: '/lab',
autoGoto: true,
mockConfig: true,
mockKernels: true,
mockSessions: true,
mockSettings: galata.DEFAULT_SETTINGS,
mockState: true,
Expand All @@ -341,6 +355,7 @@ export namespace galata {
const context = await browser.newContext();
const page = await context.newPage();

const kernels = mockKernels ? new Map<string, Kernel.IModel>() : null;
const sessions = mockSessions ? new Map<string, Session.IModel>() : null;
const terminals = mockTerminals
? new Map<string, TerminalAPI.IModel>()
Expand All @@ -359,8 +374,10 @@ export namespace galata {
sessions,
terminals,
tmpPath,
waitForApplication
waitForApplication,
kernels
),
kernels,
sessions,
terminals
};
Expand Down Expand Up @@ -407,6 +424,15 @@ export namespace galata {
*/
export const extensions = /.*\/lab\/api\/extensions.*/;

/**
* Kernels API
*
* The kernel id can be found in the named group `id`.
*
* The id will be prefixed by '/'.
*/
export const kernels = /.*\/api\/kernels(?!pecs)(?<id>\/[@:-\w]+)?/;

/**
* Sessions API
*
Expand Down Expand Up @@ -703,7 +729,7 @@ export namespace galata {
export async function clearRunners(
request: APIRequestContext,
runners: string[],
type: 'sessions' | 'terminals'
type: 'kernels' | 'sessions' | 'terminals'
): Promise<boolean> {
const responses = await Promise.all(
[...new Set(runners)].map(id =>
Expand Down Expand Up @@ -780,6 +806,12 @@ export namespace galata {
});
}

const routes = {
kernels: Routes.kernels,
sessions: Routes.sessions,
terminals: Routes.terminals
};

/**
* Mock the runners API to display only those created during a test
*
Expand All @@ -790,10 +822,10 @@ export namespace galata {
export function mockRunners(
page: Page,
runners: Map<string, any>,
type: 'sessions' | 'terminals'
type: 'kernels' | 'sessions' | 'terminals',
kernels?: Map<string, Kernel.IModel>
): Promise<void> {
const routeRegex =
type === 'sessions' ? Routes.sessions : Routes.terminals;
const routeRegex = routes[type];
// Listen for closing connection (may happen when request are still being processed)
let isClosed = false;
const ctxt = page.context();
Expand Down Expand Up @@ -836,7 +868,7 @@ export namespace galata {
}
const data = await response.json();
// Update stored runners
runners.set(type === 'sessions' ? data.id : data.name, data);
runners.set(type === 'terminals' ? data.name : data.id, data);

if (!page.isClosed() && !isClosed) {
return route.fulfill({
Expand Down Expand Up @@ -870,7 +902,7 @@ export namespace galata {
const updated = new Set<string>();
data.forEach(item => {
const itemID: string =
type === 'sessions' ? item.id : item.name;
type === 'terminals' ? item.name : item.id;
if (runners.has(itemID)) {
updated.add(itemID);
runners.set(itemID, item);
Expand Down Expand Up @@ -909,7 +941,11 @@ export namespace galata {
}
const data = await response.json();
// Update stored runners
runners.set(type === 'sessions' ? data.id : data.name, data);
runners.set(type === 'terminals' ? data.name : data.id, data);
// Update kernels
if (kernels && type === 'sessions' && data.kernel.id) {
kernels.set(data.kernel.id, data.kernel);
}

if (!page.isClosed() && !isClosed) {
return route.fulfill({
Expand All @@ -933,11 +969,15 @@ export namespace galata {
break;
}
const data = await response.json();
const id = type === 'sessions' ? data.id : data.name;
const id = type === 'terminals' ? data.name : data.id;
runners.set(id, data);
// Update kernels
if (kernels && type === 'sessions' && data.kernel.id) {
kernels.set(data.kernel.id, data.kernel);
}
if (!page.isClosed() && !isClosed) {
return route.fulfill({
status: type === 'sessions' ? 201 : 200,
status: type === 'terminals' ? 200 : 201,
body: JSON.stringify(data),
contentType: 'application/json',
headers: response.headers as any
Expand Down
11 changes: 6 additions & 5 deletions galata/src/helpers/debuggerpanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,19 +100,20 @@ export class DebuggerHelper {
* Waits for variables to be populated in the variables panel
*/
async waitForVariables(): Promise<void> {
await this.page.locator('.jp-DebuggerVariables-body ul').waitFor();
await this.page
.locator('.jp-DebuggerVariables-body')
.getByRole('tree')
.waitFor();
}

/**
* render variable
*/
async renderVariable(name: string): Promise<void> {
await this.page
.locator(`.jp-DebuggerVariables :text("${name}")`)
.getByRole('treeitem', { name: `${name}:` })
.click({ button: 'right' });
await this.page
.locator('.lm-Menu-itemLabel:text("Render Variable")')
.click();
await this.page.getByRole('menuitem', { name: 'Render Variable' }).click();
await this.page.locator('.jp-VariableRendererPanel-renderer').waitFor();
}

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 450e8fc

Please sign in to comment.