Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor UI tests #86

Merged
merged 10 commits into from
Oct 9, 2024
Merged
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

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* Copyright (c) Jupyter Development Team.
* Distributed under the terms of the Modified BSD License.
*/

import { expect, galata, test } from '@jupyterlab/galata';
import { UUID } from '@lumino/coreutils';

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

const FILENAME = 'my-chat.chat';
const MSG_CONTENT = 'Hello World!';
const USERNAME = USER.identity.username;

test.use({
mockUser: USER,
mockSettings: { ...galata.DEFAULT_SETTINGS }
});

test.describe('#messageToolbar', () => {
const additionnalContent = ' Messages can be edited';

const msg = {
type: 'msg',
id: UUID.uuid4(),
sender: USERNAME,
body: MSG_CONTENT,
time: 1714116341
};
const chatContent = {
messages: [msg],
users: {}
};
chatContent.users[USERNAME] = USER.identity;

test.beforeEach(async ({ page }) => {
// Create a chat file with content
await page.filebrowser.contents.uploadContent(
JSON.stringify(chatContent),
'text',
FILENAME
);
});

test.afterEach(async ({ page }) => {
if (await page.filebrowser.contents.fileExists(FILENAME)) {
await page.filebrowser.contents.deleteFile(FILENAME);
}
});

test('message should have a toolbar', async ({ page }) => {
const chatPanel = await openChat(page, FILENAME);
const message = chatPanel
.locator('.jp-chat-messages-container .jp-chat-rendermime-markdown')
.first();

await expect(message.locator('.jp-chat-toolbar')).not.toBeVisible();

//Should display the message toolbar
await message.hover({ position: { x: 5, y: 5 } });
await expect(message.locator('.jp-chat-toolbar')).toBeVisible();
});

test('should update the message', async ({ page }) => {
const chatPanel = await openChat(page, FILENAME);
const message = chatPanel
.locator('.jp-chat-messages-container .jp-chat-message')
.first();
const messageContent = message.locator('.jp-chat-rendermime-markdown');

// Should display the message toolbar
await messageContent.hover({ position: { x: 5, y: 5 } });
await messageContent.locator('.jp-chat-toolbar jp-button').first().click();

await expect(messageContent).not.toBeVisible();

const editInput = chatPanel
.locator('.jp-chat-messages-container .jp-chat-input-container')
.getByRole('combobox');

await expect(editInput).toBeVisible();
await editInput.focus();
await editInput.press('End');
await editInput.pressSequentially(additionnalContent);
await editInput.press('Enter');

// It seems that the markdown renderer adds a new line.
await expect(messageContent).toHaveText(
MSG_CONTENT + additionnalContent + '\n'
);
expect(
await message.locator('.jp-chat-message-header').textContent()
).toContain('(edited)');
});

test('should cancel message edition', async ({ page }) => {
const chatPanel = await openChat(page, FILENAME);
const message = chatPanel
.locator('.jp-chat-messages-container .jp-chat-message')
.first();
const messageContent = message.locator('.jp-chat-rendermime-markdown');

// Should display the message toolbar
await messageContent.hover({ position: { x: 5, y: 5 } });
await messageContent.locator('.jp-chat-toolbar jp-button').first().click();

await expect(messageContent).not.toBeVisible();

const editInput = chatPanel
.locator('.jp-chat-messages-container .jp-chat-input-container')
.getByRole('combobox');

await expect(editInput).toBeVisible();
await editInput.focus();
await editInput.press('End');
await editInput.pressSequentially(additionnalContent);

const cancelButton = chatPanel
.locator('.jp-chat-messages-container .jp-chat-input-container')
.getByTitle('Cancel edition');
await expect(cancelButton).toBeVisible();
await cancelButton.click();
await expect(editInput).not.toBeVisible();

// It seems that the markdown renderer adds a new line.
await expect(messageContent).toHaveText(MSG_CONTENT + '\n');
expect(
await message.locator('.jp-chat-message-header').textContent()
).not.toContain('(edited)');
});

test('should set the message as deleted', async ({ page }) => {
const chatPanel = await openChat(page, FILENAME);
const message = chatPanel
.locator('.jp-chat-messages-container .jp-chat-message')
.first();
const messageContent = message.locator('.jp-chat-rendermime-markdown');

// Should display the message toolbar
await messageContent.hover({ position: { x: 5, y: 5 } });
await messageContent.locator('.jp-chat-toolbar jp-button').last().click();

await expect(messageContent).not.toBeVisible();
expect(
await message.locator('.jp-chat-message-header').textContent()
).toContain('(message deleted)');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/*
* Copyright (c) Jupyter Development Team.
* Distributed under the terms of the Modified BSD License.
*/

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

import { User } from '@jupyterlab/services';
import { UUID } from '@lumino/coreutils';

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

const FILENAME = 'my-chat.chat';
const MSG_CONTENT = 'Hello World!';
const USERNAME = USER.identity.username;

test.describe('#notifications', () => {
const baseTime = 1714116341;
const messagesCount = 15;
const messagesList: any[] = [];
for (let i = 0; i < messagesCount; i++) {
messagesList.push({
type: 'msg',
id: UUID.uuid4(),
sender: USERNAME,
body: `Message ${i}`,
time: baseTime + i * 60
});
}

const chatContent = {
messages: messagesList,
users: {}
};
chatContent.users[USERNAME] = USER.identity;

let guestPage: IJupyterLabPageFixture;

test.beforeEach(
async ({ baseURL, browser, page, tmpPath, waitForApplication }) => {
// Create a chat file with content
await page.filebrowser.contents.uploadContent(
JSON.stringify(chatContent),
'text',
FILENAME
);

// Create a new user.
const user2: Partial<User.IUser> = {
identity: {
username: 'jovyan_2',
name: 'jovyan_2',
display_name: 'jovyan_2',
initials: 'JP',
color: 'var(--jp-collaborator-color2)'
}
};

// Create a new page for guest.
const { page: newPage } = await galata.newPage({
baseURL: baseURL!,
browser,
mockUser: user2,
tmpPath,
waitForApplication
});
await newPage.evaluate(() => {
// Acknowledge any dialog
window.galataip.on('dialog', d => {
d?.resolve();
});
});
guestPage = newPage;
}
);

test.afterEach(async ({ page }) => {
guestPage.close();
if (await page.filebrowser.contents.fileExists(FILENAME)) {
await page.filebrowser.contents.deleteFile(FILENAME);
}
});

test('should receive notification on unread message', async ({ page }) => {
const chatPanel = await openChat(page, FILENAME);
const messages = chatPanel.locator('.jp-chat-message');
await messages.first().scrollIntoViewIfNeeded();

await sendMessage(guestPage, FILENAME, MSG_CONTENT);
await page.waitForCondition(
async () => (await page.notifications).length > 0
);
const notifications = await page.notifications;
expect(notifications).toHaveLength(1);

// TODO: fix it, the notification should be info but is 'default'
// expect(notifications[0].type).toBe('info');
expect(notifications[0].message).toBe(
'1 incoming message(s) in my-chat.chat'
);
});

test('should remove notification when the message is read', async ({
page
}) => {
const chatPanel = await openChat(page, FILENAME);
const messages = chatPanel.locator('.jp-chat-message');
await messages.first().scrollIntoViewIfNeeded();

await sendMessage(guestPage, FILENAME, MSG_CONTENT);
await page.waitForCondition(
async () => (await page.notifications).length > 0
);
let notifications = await page.notifications;
expect(notifications).toHaveLength(1);

await messages.last().scrollIntoViewIfNeeded();
await page.waitForCondition(
async () => (await page.notifications).length === 0
);
});

test('should update existing notification on new message', async ({
page
}) => {
const chatPanel = await openChat(page, FILENAME);
const messages = chatPanel.locator('.jp-chat-message');
await messages.first().scrollIntoViewIfNeeded();

await sendMessage(guestPage, FILENAME, MSG_CONTENT);
await page.waitForCondition(
async () => (await page.notifications).length > 0
);
let notifications = await page.notifications;
expect(notifications).toHaveLength(1);

expect(notifications[0].message).toBe(
'1 incoming message(s) in my-chat.chat'
);

await sendMessage(guestPage, FILENAME, MSG_CONTENT);
notifications = await page.notifications;
expect(notifications[0].message).toBe(
'2 incoming message(s) in my-chat.chat'
);
});

test('should remove notifications from settings', async ({ page }) => {
const chatPanel = await openChat(page, FILENAME);
const messages = chatPanel.locator('.jp-chat-message');
await messages.first().scrollIntoViewIfNeeded();

await sendMessage(guestPage, FILENAME, MSG_CONTENT);
await page.waitForCondition(
async () => (await page.notifications).length > 0
);
let notifications = await page.notifications;
expect(notifications).toHaveLength(1);

const settings = await openSettings(page);
const unreadNotifications = settings?.getByRole('checkbox', {
name: 'unreadNotifications'
});
await unreadNotifications?.uncheck();

// wait for the settings to be saved
await expect(page.activity.getTabLocator('Settings')).toHaveAttribute(
'class',
/jp-mod-dirty/
);
await expect(page.activity.getTabLocator('Settings')).not.toHaveAttribute(
'class',
/jp-mod-dirty/
);

// Activate the chat panel
await page.activity.activateTab(FILENAME);

await page.waitForCondition(
async () => (await page.notifications).length === 0
);

await sendMessage(guestPage, FILENAME, MSG_CONTENT);
await expect(messages).toHaveCount(messagesCount + 2);

notifications = await page.notifications;
expect(notifications).toHaveLength(0);
});

test('should add unread symbol in tab label', async ({ page }) => {
const chatPanel = await openChat(page, FILENAME);
const messages = chatPanel.locator('.jp-chat-message');
await messages.first().scrollIntoViewIfNeeded();

const tab = page.activity.getTabLocator(FILENAME);
const tabLabel = tab.locator('.lm-TabBar-tabLabel');
await expect(tabLabel).toHaveText(FILENAME);

await sendMessage(guestPage, FILENAME, MSG_CONTENT);
const beforePseudo = tabLabel.evaluate(elem => {
return window.getComputedStyle(elem, ':before');
});
expect(await beforePseudo).toHaveProperty('content', '"* "');
expect(await tab.screenshot()).toMatchSnapshot('tab-with-unread.png');

await messages.last().scrollIntoViewIfNeeded();
expect(await tab.screenshot()).toMatchSnapshot('tab-without-unread.png');
});
});
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
Loading