mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 12:55:00 +00:00
### TL;DR * Fix the issue of inaccurate content replacement in AI Replace Selection * Optimize unit Tests utils ### What Changed 1. Fixed the issue of inaccurate content replacement in AI Replace Selection: - Convert the AI Answer into a Snapshot, then transform it into a sequence of Blocks ready for insertion. - Invoke the `replaceSelectedTextWithBlocks` command to replace the current selection with blocks (given the complexity of block combinations, this command uses [ts-pattern](https://github.com/gvergnaud/ts-pattern) implementation to ensure compile-time prevention of pattern handling omissions). 2. Optimized unit test assertions for commands, now allowing direct document content comparison using `toEqualDoc`. ```ts const host = affine` <affine-page id="page"> <affine-note id="note"> <affine-paragraph id="paragraph-1">Hel<anchor />lo</affine-paragraph> <affine-paragraph id="paragraph-2">Wor<focus />ld</affine-paragraph> </affine-note> </affine-page> `; // .... const expected = affine` <affine-page id="page"> <affine-note id="note"> <affine-paragraph id="paragraph-1">Hel111</affine-paragraph> <affine-code id="code"></affine-code> <affine-paragraph id="paragraph-2">222ld</affine-paragraph> </affine-note> </affine-page> `; expect(host.doc).toEqualDoc(expected.doc); ``` 3. Added support for text cursors in unit test template syntax. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit > CLOSE BS-3278 - **New Features** - Introduced the ability to replace selected text in documents with blocks, supporting advanced merging and insertion scenarios for various block types. - **Bug Fixes** - Improved handling of text selection and cursor placement in document templates used for testing. - **Tests** - Added comprehensive tests for replacing selected text with blocks, including edge cases and complex selection scenarios. - Enhanced test utilities for document structure comparison and selection handling. - Updated end-to-end tests to verify correct replacement of selected text via AI-driven actions. - **Chores** - Added and updated dependencies to support new features. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
167 lines
6.4 KiB
TypeScript
167 lines
6.4 KiB
TypeScript
import { IS_MAC } from '@blocksuite/global/env';
|
|
import { expect } from '@playwright/test';
|
|
|
|
import { test } from '../base/base-test';
|
|
|
|
test.describe('AIChatWith/Text', () => {
|
|
test.beforeEach(async ({ loggedInPage: page, utils }) => {
|
|
await utils.testUtils.setupTestEnvironment(page);
|
|
await utils.chatPanel.openChatPanel(page);
|
|
});
|
|
|
|
test('should support stop generating', async ({
|
|
loggedInPage: page,
|
|
utils,
|
|
}) => {
|
|
await utils.editor.askAIWithText(page, 'Appel');
|
|
await page.getByTestId('action-fix-grammar').click();
|
|
await expect(page.getByTestId('ai-generating')).toBeVisible();
|
|
const stop = await page.getByTestId('ai-stop');
|
|
await stop.click();
|
|
await expect(page.getByTestId('ai-generating')).not.toBeVisible();
|
|
});
|
|
|
|
test('should support copy answer', async ({ loggedInPage: page, utils }) => {
|
|
const { translate } = await utils.editor.askAIWithText(page, 'Apple');
|
|
const { answer } = await translate('German');
|
|
await expect(answer).toHaveText(/Apfel/, { timeout: 10000 });
|
|
const copy = answer.getByTestId('answer-copy-button');
|
|
await copy.click();
|
|
await expect(answer.getByTestId('answer-copied')).toBeVisible();
|
|
const clipboardText = await page.evaluate(() =>
|
|
navigator.clipboard.readText()
|
|
);
|
|
expect(clipboardText).toBe('Apfel');
|
|
});
|
|
|
|
test('should support insert below', async ({ loggedInPage: page, utils }) => {
|
|
const { translate } = await utils.editor.askAIWithText(page, 'Apple');
|
|
const { answer } = await translate('German');
|
|
await expect(answer).toHaveText(/Apfel/, { timeout: 10000 });
|
|
const insertBelow = answer.getByTestId('answer-insert-below');
|
|
await insertBelow.click();
|
|
const content = await utils.editor.getEditorContent(page);
|
|
expect(content).toBe('Apple\nApfel');
|
|
});
|
|
|
|
test('should support insert above', async ({ loggedInPage: page, utils }) => {
|
|
const { generateHeadings } = await utils.editor.askAIWithText(
|
|
page,
|
|
'AFFiNE'
|
|
);
|
|
const { answer } = await generateHeadings();
|
|
await answer.locator('h1').isVisible();
|
|
await expect(answer).toHaveText(/AFFiNE/, { timeout: 10000 });
|
|
|
|
const insertAbove = answer.getByTestId('answer-insert-above');
|
|
await insertAbove.click();
|
|
const content = await utils.editor.getEditorContent(page);
|
|
expect(content).toBe('AFFiNE\nAFFiNE');
|
|
});
|
|
|
|
test('should support replace selection', async ({
|
|
loggedInPage: page,
|
|
utils,
|
|
}) => {
|
|
await utils.editor.focusToEditor(page);
|
|
await page.keyboard.insertText('I Loev Apple');
|
|
|
|
// Select the word "Loev"
|
|
const SHORT_KEY = IS_MAC ? 'Alt' : 'Control';
|
|
await page.keyboard.press(`${SHORT_KEY}+ArrowLeft`);
|
|
await page.keyboard.press('ArrowLeft');
|
|
await page.keyboard.press(`Shift+${SHORT_KEY}+ArrowLeft`);
|
|
|
|
const { fixSpelling } = await utils.editor.showAIMenu(page);
|
|
const { answer } = await fixSpelling();
|
|
await expect(answer).toHaveText(/Love/, { timeout: 10000 });
|
|
const replace = answer.getByTestId('answer-replace');
|
|
await replace.click();
|
|
const content = await utils.editor.getEditorContent(page);
|
|
expect(content).toBe('I Love Apple');
|
|
});
|
|
|
|
test('should support continue in chat', async ({
|
|
loggedInPage: page,
|
|
utils,
|
|
}) => {
|
|
const { translate } = await utils.editor.askAIWithText(page, 'Apple');
|
|
const { answer } = await translate('German');
|
|
await expect(answer).toHaveText(/Apfel/, { timeout: 10000 });
|
|
const continueInChat = answer.getByTestId('answer-continue-in-chat');
|
|
await continueInChat.click();
|
|
const chatPanelInput = await page.getByTestId('chat-panel-input-container');
|
|
const quote = await chatPanelInput.getByTestId('chat-selection-quote');
|
|
await expect(quote).toHaveText(/Apple/, { timeout: 10000 });
|
|
});
|
|
|
|
test('should support regenerate', async ({ loggedInPage: page, utils }) => {
|
|
const { translate } = await utils.editor.askAIWithText(page, 'Apple');
|
|
const { answer } = await translate('German');
|
|
const regenerate = answer.getByTestId('answer-regenerate');
|
|
await regenerate.click();
|
|
const content = await utils.editor.getEditorContent(page);
|
|
expect(content).toBe('Apple');
|
|
});
|
|
|
|
test('should show error when request failed', async ({
|
|
loggedInPage: page,
|
|
utils,
|
|
}) => {
|
|
await page.route('**/graphql', route => route.abort('failed'));
|
|
await utils.editor.askAIWithText(page, 'Appel');
|
|
await page.getByTestId('action-fix-spelling').click();
|
|
await expect(page.getByTestId('ai-error')).toBeVisible();
|
|
});
|
|
|
|
test('should support retry when error', async ({
|
|
loggedInPage: page,
|
|
utils,
|
|
}) => {
|
|
await page.route('**/graphql', route => route.abort('failed'));
|
|
await utils.editor.askAIWithText(page, 'Appel');
|
|
await page.getByTestId('action-fix-spelling').click();
|
|
const aiPanelContainer = await page.getByTestId('ai-panel-container');
|
|
|
|
await page.route('**/graphql', route => route.continue());
|
|
await aiPanelContainer.getByTestId('error-retry').click();
|
|
const answer = await utils.editor.waitForAiAnswer(page);
|
|
await expect(answer).toHaveText(/Apple/, { timeout: 10000 });
|
|
});
|
|
|
|
test('should support discard', async ({ loggedInPage: page, utils }) => {
|
|
const { translate } = await utils.editor.askAIWithText(page, 'Apple');
|
|
const { answer } = await translate('German');
|
|
const discard = answer.getByTestId('answer-discard');
|
|
await discard.click();
|
|
await expect(answer).not.toBeVisible();
|
|
const content = await utils.editor.getEditorContent(page);
|
|
expect(content).toBe('Apple');
|
|
});
|
|
|
|
test('should support discard when click outside', async ({
|
|
loggedInPage: page,
|
|
utils,
|
|
}) => {
|
|
const { translate } = await utils.editor.askAIWithText(page, 'Apple');
|
|
const { answer } = await translate('German');
|
|
await page.mouse.click(0, 0);
|
|
await expect(page.getByText('Discard the AI result')).toBeVisible();
|
|
await page.getByTestId('confirm-modal-confirm').click();
|
|
await expect(answer).not.toBeVisible();
|
|
const content = await utils.editor.getEditorContent(page);
|
|
expect(content).toBe('Apple');
|
|
});
|
|
|
|
test('should focus on textarea', async ({ loggedInPage: page, utils }) => {
|
|
await utils.editor.askAIWithText(page, 'Apple');
|
|
|
|
const textarea = await utils.editor.whatAreYourThoughts(page, 'Coffee');
|
|
|
|
await expect(textarea).toBeFocused();
|
|
|
|
const value = await textarea.inputValue();
|
|
expect(value).toBe('Coffee');
|
|
});
|
|
});
|