Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions ui-tests/test/editor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,40 @@ test.describe('Editor', () => {
await expect(page.locator('.jp-Notebook')).toHaveCount(0);
});

test('Should display a partial view with white space at the bottom', async ({
page,
tmpPath,
}) => {
const file = `${tmpPath}/${FILE}`;
await page.goto(`edit/${file}`);

await expect(page.locator('.cm-editor')).toBeVisible();
// wait for the file content to be rendered in the editor
await expect(page.locator('.cm-content')).toContainText('name: notebook');

// the edit page should display a partial view, with white space below
// the main panel
const spacer = page.locator('#spacer-widget-bottom');
await expect(spacer).toBeVisible();
const spacerBox = await spacer.boundingBox();
expect(spacerBox?.height).toBeGreaterThanOrEqual(16);
});

test('Should not render the micro toolbar for files', async ({
page,
tmpPath,
}) => {
const file = `${tmpPath}/${FILE}`;
await page.goto(`edit/${file}`);

await expect(page.locator('.cm-editor')).toBeVisible();

// the micro toolbar is added to the DOM but should be hidden via CSS
const microToolbar = page.locator('.jp-MainAreaWidget > .jp-Toolbar-micro');
await expect(microToolbar).toHaveCount(1);
await expect(microToolbar).toBeHidden();
});

test('Renaming the file via the menu entry', async ({ page, tmpPath }) => {
const file = `${tmpPath}/${FILE}`;
await page.goto(`edit/${file}`);
Expand Down
70 changes: 70 additions & 0 deletions ui-tests/test/filebrowser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,43 @@ test.describe('File Browser', () => {
await notebook.close();
});

test('Show the Upload button in the toolbar by default', async ({ page }) => {
const toolbar = page.locator('.jp-FileBrowser-toolbar');

await expect(toolbar.getByText('Upload')).toBeVisible();
});

test('Filter the file browser listing with the file filter', async ({
page,
}) => {
await page.filebrowser.refresh();

const toggleButton = page.locator(
'jp-button[data-command="filebrowser:toggle-file-filter"]'
);
const filterInput = page.locator('.jp-FileBrowser-filterBox input');
const listing = page.locator('.jp-DirListing-item');

// the file filter input is hidden by default
await expect(filterInput).toBeHidden();
await expect(listing).toHaveCount(3);

// clicking the toggle button shows the filter input
await toggleButton.click();
await expect(filterInput).toBeVisible();

// typing a query narrows down the listing
await filterInput.fill('folder1');
await expect(listing).toHaveCount(1);
await expect(listing).toHaveText(/folder1/);

// clicking the toggle button again hides the filter input and restores
// the full listing
await toggleButton.click();
await expect(filterInput).toBeHidden();
await expect(listing).toHaveCount(3);
});

test('Toggle the Date Created column from the header context menu', async ({
page,
}) => {
Expand Down Expand Up @@ -138,3 +175,36 @@ test.describe('File Browser settings', () => {
await expect(header.locator('.jp-id-created')).toBeVisible();
});
});

test.describe('File Browser toolbar settings', () => {
test.use({
mockSettings: {
...galata.DEFAULT_SETTINGS,
'@jupyter-notebook/tree-extension:widget': {
toolbar: [
{
name: 'uploader',
disabled: true,
},
],
},
},
});

test('Should hide the Upload button when disabled in the settings', async ({
page,
}) => {
const toolbar = page.locator('.jp-FileBrowser-toolbar');

// other toolbar items should still be visible
await expect(toolbar.getByText('New', { exact: true })).toBeVisible();
await expect(
toolbar.locator('[data-jp-item-name="refresh"]')
).toBeVisible();

// the Upload button should not be added to the toolbar
await expect(toolbar.locator('[data-jp-item-name="uploader"]')).toHaveCount(
0
);
});
});
73 changes: 73 additions & 0 deletions ui-tests/test/help.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import { expect } from '@jupyterlab/galata';

import { test } from './fixtures';

test.describe('Help menu', () => {
test('Should open the About dialog', async ({ page }) => {
await page.menu.clickMenuItem('Help>About Jupyter Notebook');

const dialog = page.locator('.jp-Dialog.jp-AboutNotebook');
await expect(dialog).toBeVisible();

// The version reported in the dialog should be a valid version number
await expect(dialog.locator('.jp-AboutNotebook-version')).toHaveText(
/^Version: \d+\.\d+\.\d+/
);

// The external links should open in a new tab
const githubLink = dialog.getByRole('link', {
name: 'JUPYTER NOTEBOOK ON GITHUB',
});
await expect(githubLink).toHaveAttribute(
'href',
'https://github.com/jupyter/notebook'
);
await expect(githubLink).toHaveAttribute('target', '_blank');

const contributorsLink = dialog.getByRole('link', {
name: 'CONTRIBUTOR LIST',
});
await expect(contributorsLink).toHaveAttribute(
'href',
'https://github.com/jupyter/notebook/pulse'
);
await expect(contributorsLink).toHaveAttribute('target', '_blank');

await expect(
dialog.locator('.jp-AboutNotebook-about-copyright')
).toBeVisible();

// Dismiss the dialog
await dialog.getByRole('button', { name: 'Dismiss' }).click();
await expect(dialog).toHaveCount(0);
});

test('Should open the Documentation in a new browser tab', async ({
page,
}) => {
const documentationUrl = 'https://jupyter-notebook.readthedocs.io/';

// Stub the external website so the test does not depend on network access
await page.context().route(`${documentationUrl}**`, (route) =>
route.fulfill({
contentType: 'text/html',
body: '<html><body>Documentation</body></html>',
})
);

const [popup] = await Promise.all([
page.waitForEvent('popup'),
page.menu.clickMenuItem('Help>Documentation'),
]);

// Only check the URL of the new tab, without waiting for the page to load
await popup.waitForURL(`${documentationUrl}en/stable/`, {
waitUntil: 'commit',
});
expect(popup.url()).toEqual(`${documentationUrl}en/stable/`);
await popup.close();
});
});
88 changes: 88 additions & 0 deletions ui-tests/test/notebook.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

Expand Down Expand Up @@ -79,7 +79,7 @@
await page
.locator('.jp-mod-outputsScrolled')
.nth(0)
.waitFor({ state: 'visible' });

Check failure on line 82 in ui-tests/test/notebook.spec.ts

View workflow job for this annotation

GitHub Actions / Merge UI Test Reports

[chromium] › ui-tests/test/notebook.spec.ts:62:7 › Notebook › Outputs should be scrolled automatically @chromium

1) [chromium] › ui-tests/test/notebook.spec.ts:62:7 › Notebook › Outputs should be scrolled automatically @chromium Error: locator.waitFor: Test timeout of 60000ms exceeded. Call log: - waiting for locator('.jp-mod-outputsScrolled').first() to be visible 80 | .locator('.jp-mod-outputsScrolled') 81 | .nth(0) > 82 | .waitFor({ state: 'visible' }); | ^ 83 | 84 | // execute the second cell 85 | await runAndAdvance(page); at /home/runner/work/notebook/notebook/ui-tests/test/notebook.spec.ts:82:8

// execute the second cell
await runAndAdvance(page);
Expand Down Expand Up @@ -156,6 +156,94 @@
expect(await panel.screenshot()).toMatchSnapshot(imageName);
});

test('Edit Notebook Metadata should open the right panel with Advanced Tools expanded', async ({
page,
tmpPath,
}) => {
const notebook = 'simple.ipynb';
await page.contents.uploadFile(
path.resolve(__dirname, `./notebooks/${notebook}`),
`${tmpPath}/${notebook}`
);
await page.goto(`notebooks/${tmpPath}/${notebook}`);

await waitForKernelReady(page);

await page.menu.clickMenuItem('Edit>Edit Notebook Metadata');

const panel = page.locator('#jp-right-stack');
await expect(panel).toBeVisible();

const notebookTools = page.locator('#notebook-tools.jp-NotebookTools');
await expect(notebookTools).toBeVisible();

// The Advanced Tools section should be expanded
const advancedTools = notebookTools.locator('.jp-Collapse', {
hasText: 'Advanced Tools',
});
await expect(advancedTools.locator('.jp-Collapse-header')).not.toHaveClass(
/jp-Collapse-header-collapsed/
);
await expect(advancedTools.locator('.jp-Collapse-contents')).toBeVisible();
});

test('Tab title should reflect the current document', async ({
page,
tmpPath,
}) => {
const notebook = 'simple.ipynb';
await page.contents.uploadFile(
path.resolve(__dirname, `./notebooks/${notebook}`),
`${tmpPath}/${notebook}`
);
await page.goto(`notebooks/${tmpPath}/${notebook}`);

// The tab title should be the notebook name with the ".ipynb" suffix stripped
await expect(page).toHaveTitle('simple');

// The tree page should have the default title
await page.goto(`tree/${tmpPath}`);
await expect(page).toHaveTitle('Home');
});

test('Favicon should switch to busy while a cell is running', async ({
page,
tmpPath,
}) => {
const notebook = 'empty.ipynb';
await page.contents.uploadFile(
path.resolve(__dirname, `./notebooks/${notebook}`),
`${tmpPath}/${notebook}`
);
await page.goto(`notebooks/${tmpPath}/${notebook}`);

await waitForKernelReady(page);

const favicon = page.locator('link[rel*="icon"]');

await page.click('.jp-Cell-inputArea');

// Enter code in the first cell
await page
.locator(
'.jp-Cell-inputArea >> .cm-editor >> .cm-content[contenteditable="true"]'
)
.type('import time; time.sleep(3)');

// Run the cell
await runAndAdvance(page);

// The favicon should switch to the busy icon while the kernel is busy
await expect(favicon).toHaveAttribute('href', /favicon-busy-1\.ico/, {
timeout: 15000,
});

// And back to the idle notebook icon when the execution is done
await expect(favicon).toHaveAttribute('href', /favicon-notebook\.ico/, {
timeout: 30000,
});
});

test('Clicking on "Close and Shut Down Notebook" should close the browser tab', async ({
page,
tmpPath,
Expand Down
Loading
Loading