Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
brichet committed Sep 19, 2024
1 parent 1ca1354 commit 7d072b1
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,10 @@ module.exports = {
url: 'http://localhost:8888/lab',
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI
},
use: {
contextOptions: {
permissions: ['clipboard-read', 'clipboard-write']
}
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@
* Distributed under the terms of the Modified BSD License.
*/

import {
expect,
galata,
IJupyterLabPageFixture,
test
} from '@jupyterlab/galata';
import { expect, galata, test } from '@jupyterlab/galata';

import { openChat, sendMessage, USER } from './test-utils';
import { openChat, sendMessage, splitMainArea, USER } from './test-utils';

test.use({
mockUser: USER,
Expand All @@ -26,20 +21,6 @@ const FILENAME = 'toolbar.chat';
const CONTENT = 'print("This is a code cell")';
const MESSAGE = `\`\`\`\n${CONTENT}\n\`\`\``;

async function splitMainArea(page: IJupyterLabPageFixture, name: string) {
// Emulate drag and drop
const viewerHandle = page.activity.getTabLocator(name);
const viewerBBox = await viewerHandle.boundingBox();

await page.mouse.move(
viewerBBox!.x + 0.5 * viewerBBox!.width,
viewerBBox!.y + 0.5 * viewerBBox!.height
);
await page.mouse.down();
await page.mouse.move(viewerBBox!.x + 0.5 * viewerBBox!.width, 600);
await page.mouse.up();
}

test.describe('#codeToolbar', () => {
test.beforeEach(async ({ page }) => {
// Create a chat file
Expand Down Expand Up @@ -161,19 +142,22 @@ test.describe('#codeToolbar', () => {
expect(await page.notebook.getCellTextInput(1)).toBe(`${CONTENT}\n`);
});

test('replace active cell', async ({ page }) => {
test('replace active cell content', async ({ page }) => {
const chatPanel = await openChat(page, FILENAME);
const message = chatPanel.locator('.jp-chat-message');
const toolbarButtons = message.locator('.jp-chat-code-toolbar-item button');
const toolbarButtons = message.locator('.jp-chat-code-toolbar-item');

const notebook = await page.notebook.createNew();
// write content in the first cell.
const cell = await page.notebook.getCellLocator(0);
await cell?.getByRole('textbox').pressSequentially('initial content');

await sendMessage(page, FILENAME, MESSAGE);
await splitMainArea(page, notebook!);

// write content in the first cell.
const cell = await page.notebook.getCellLocator(0);
await cell?.getByRole('textbox').pressSequentially('initial content');
await expect(toolbarButtons.nth(2)).toHaveAccessibleName(
'Replace selection (active cell)'
);
await toolbarButtons.nth(2).click();

await page.activity.activateTab(notebook!);
Expand All @@ -184,10 +168,52 @@ test.describe('#codeToolbar', () => {
expect(await page.notebook.getCellTextInput(0)).toBe(`${CONTENT}\n`);
});

test('replace current selection', async ({ page }) => {
const cellContent = 'a = 1\nprint(f"a={a}")';
const chatPanel = await openChat(page, FILENAME);
const message = chatPanel.locator('.jp-chat-message');
const toolbarButtons = message.locator('.jp-chat-code-toolbar-item');

const notebook = await page.notebook.createNew();
// write content in the first cell.
const cell = (await page.notebook.getCellLocator(0))!;
await cell.getByRole('textbox').pressSequentially(cellContent);

// wait for code mirror to be ready.
await expect(cell.locator('.cm-line')).toHaveCount(2);
await expect(
cell.locator('.cm-line').nth(1).locator('.cm-builtin')
).toBeAttached();

// select the 'print' statement in the second line.
const selection = cell
?.locator('.cm-line')
.nth(1)
.locator('.cm-builtin')
.first();
await selection.dblclick({ position: { x: 10, y: 10 } });

await sendMessage(page, FILENAME, MESSAGE);
await splitMainArea(page, notebook!);

await expect(toolbarButtons.nth(2)).toHaveAccessibleName(
'Replace selection (1 line(s))'
);
await toolbarButtons.nth(2).click();

await page.activity.activateTab(notebook!);
await page.waitForCondition(
async () => (await page.notebook.getCellTextInput(0)) !== cellContent
);
expect(await page.notebook.getCellTextInput(0)).toBe(
`a = 1\n${CONTENT}\n(f"a={a}")`
);
});

test('should copy code content', async ({ page }) => {
const chatPanel = await openChat(page, FILENAME);
const message = chatPanel.locator('.jp-chat-message');
const toolbarButtons = message.locator('.jp-chat-code-toolbar-item button');
const toolbarButtons = message.locator('.jp-chat-code-toolbar-item');

const notebook = await page.notebook.createNew();

Expand All @@ -196,6 +222,10 @@ test.describe('#codeToolbar', () => {
// Copy the message code content to clipboard.
await toolbarButtons.last().click();

expect(await page.evaluate(() => navigator.clipboard.readText())).toBe(
`${CONTENT}\n`
);

await page.activity.activateTab(notebook!);
const cell = await page.notebook.getCellLocator(0);
await cell?.getByRole('textbox').press('Control+V');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Contents, User } from '@jupyterlab/services';
import { ReadonlyJSONObject, UUID } from '@lumino/coreutils';
import { Locator } from '@playwright/test';

import { openChat, sendMessage, USER } from './test-utils';
import { openChat, sendMessage, splitMainArea, USER } from './test-utils';

const FILENAME = 'my-chat.chat';
const MSG_CONTENT = 'Hello World!';
Expand Down Expand Up @@ -376,6 +376,111 @@ test.describe('#sendMessages', () => {
messages.locator('.jp-chat-message .jp-chat-rendermime-markdown')
).toHaveText(MSG_CONTENT + '\n');
});

test('should disable send with selection when there is no notebook', async ({
page
}) => {
const chatPanel = await openChat(page, FILENAME);
const input = chatPanel
.locator('.jp-chat-input-container')
.getByRole('combobox');
const openerButton = chatPanel.locator(
'.jp-chat-input-container .jp-chat-send-include-opener'
);
const sendWithSelection = page.locator('.jp-chat-send-include');

await input.pressSequentially(MSG_CONTENT);
await openerButton.click();
await expect(sendWithSelection).toBeVisible();
await expect(sendWithSelection).toBeDisabled();
await expect(sendWithSelection).toContainText(
'No selection or active cell'
);
});

test('should send with cell content', async ({ page }) => {
const cellContent = 'a = 1\nprint(f"a={a}")';
const chatPanel = await openChat(page, FILENAME);
const messages = chatPanel.locator('.jp-chat-messages-container');
const input = chatPanel
.locator('.jp-chat-input-container')
.getByRole('combobox');
const openerButton = chatPanel.locator(
'.jp-chat-input-container .jp-chat-send-include-opener'
);
const sendWithSelection = page.locator('.jp-chat-send-include');

const notebook = await page.notebook.createNew();
// write content in the first cell.
const cell = (await page.notebook.getCellLocator(0))!;
await cell.getByRole('textbox').pressSequentially(cellContent);

await splitMainArea(page, notebook!);

await input.pressSequentially(MSG_CONTENT);
await openerButton.click();
await expect(sendWithSelection).toBeVisible();
await expect(sendWithSelection).toBeEnabled();
await expect(sendWithSelection).toContainText('Code from 1 active cell');
await sendWithSelection.click();

await expect(messages!.locator('.jp-chat-message')).toHaveCount(1);

// It seems that the markdown renderer adds a new line, but the '\n' inserter when
// pressing Enter above is trimmed.
await expect(
messages.locator('.jp-chat-message .jp-chat-rendermime-markdown')
).toHaveText(`${MSG_CONTENT}\n${cellContent}\n`);
});

test('should send with text selection', async ({ page }) => {
const cellContent = 'a = 1\nprint(f"a={a}")';
const chatPanel = await openChat(page, FILENAME);
const messages = chatPanel.locator('.jp-chat-messages-container');
const input = chatPanel
.locator('.jp-chat-input-container')
.getByRole('combobox');
const openerButton = chatPanel.locator(
'.jp-chat-input-container .jp-chat-send-include-opener'
);
const sendWithSelection = page.locator('.jp-chat-send-include');

const notebook = await page.notebook.createNew();
await splitMainArea(page, notebook!);

// write content in the first cell.
const cell = (await page.notebook.getCellLocator(0))!;
await cell.getByRole('textbox').pressSequentially(cellContent);

// wait for code mirror to be ready.
await expect(cell.locator('.cm-line')).toHaveCount(2);
await expect(
cell.locator('.cm-line').nth(1).locator('.cm-builtin')
).toBeAttached();

// select the 'print' statement in the second line.
const selection = cell
?.locator('.cm-line')
.nth(1)
.locator('.cm-builtin')
.first();
await selection.dblclick({ position: { x: 10, y: 10 } });

await input.pressSequentially(MSG_CONTENT);
await openerButton.click();
await expect(sendWithSelection).toBeVisible();
await expect(sendWithSelection).toBeEnabled();
await expect(sendWithSelection).toContainText('1 line(s) selected');
await sendWithSelection.click();

await expect(messages!.locator('.jp-chat-message')).toHaveCount(1);

// It seems that the markdown renderer adds a new line, but the '\n' inserter when
// pressing Enter above is trimmed.
await expect(
messages.locator('.jp-chat-message .jp-chat-rendermime-markdown')
).toHaveText(`${MSG_CONTENT}\nprint\n`);
});
});

test.describe('#messagesNavigation', () => {
Expand Down
17 changes: 17 additions & 0 deletions python/jupyterlab-collaborative-chat/ui-tests/tests/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,20 @@ export const sendMessage = async (
await input.pressSequentially(content);
await sendButton.click();
};

export const splitMainArea = async (
page: IJupyterLabPageFixture,
name: string
) => {
// Emulate drag and drop
const viewerHandle = page.activity.getTabLocator(name);
const viewerBBox = await viewerHandle.boundingBox();

await page.mouse.move(
viewerBBox!.x + 0.5 * viewerBBox!.width,
viewerBBox!.y + 0.5 * viewerBBox!.height
);
await page.mouse.down();
await page.mouse.move(viewerBBox!.x + 0.5 * viewerBBox!.width, 600);
await page.mouse.up();
};

0 comments on commit 7d072b1

Please sign in to comment.