feat(editor): support pasting Excel data into database block (#9618)

close: BS-2338
This commit is contained in:
zzj3720
2025-01-09 14:35:18 +00:00
parent 6feb4def2f
commit 8e8058a44c
4 changed files with 184 additions and 5 deletions

View File

@@ -0,0 +1,72 @@
import { test } from '@affine-test/kit/playwright';
import { openHomePage } from '@affine-test/kit/utils/load-page';
import { waitForEditorLoad } from '@affine-test/kit/utils/page-logic';
import {
initDatabaseWithRows,
pasteExcelData,
selectFirstCell,
verifyCellContents,
} from './utils';
test.describe('Database Clipboard Operations', () => {
test('paste tab-separated data from Excel into database', async ({
page,
}) => {
// Open the home page and wait for the editor to load
await openHomePage(page);
await waitForEditorLoad(page);
// Create a database block with two rows
await initDatabaseWithRows(page, 2);
// Select the first cell and paste data
await selectFirstCell(page);
const mockExcelData = 'Cell 1A\tCell 1B\nCell 2A\tCell 2B';
await pasteExcelData(page, mockExcelData);
// Verify cell contents
await verifyCellContents(page, [
'Cell 1A',
'Cell 1B',
'Cell 2A',
'Cell 2B',
]);
});
test('handle empty cells when pasting tab-separated data', async ({
page,
}) => {
// Open the home page and wait for the editor to load
await openHomePage(page);
await waitForEditorLoad(page);
// Create a database block with two rows
await initDatabaseWithRows(page, 2);
// Select the first cell and paste data with empty cells
await selectFirstCell(page);
const mockExcelData = 'Cell 1A\t\nCell 2A\tCell 2B';
await pasteExcelData(page, mockExcelData);
// Verify cell contents including empty cells
await verifyCellContents(page, ['Cell 1A', '', 'Cell 2A', 'Cell 2B']);
});
test('handle pasting data larger than selected area', async ({ page }) => {
// Open the home page and wait for the editor to load
await openHomePage(page);
await waitForEditorLoad(page);
// Create a database block with one row
await initDatabaseWithRows(page, 1);
// Select the first cell and paste data larger than table
await selectFirstCell(page);
const mockExcelData = 'Cell 1A\tCell 1B\nCell 2A\tCell 2B';
await pasteExcelData(page, mockExcelData);
// Verify only the cells that exist are filled
await verifyCellContents(page, ['Cell 1A', 'Cell 1B']);
});
});

View File

@@ -0,0 +1,80 @@
import {
addDatabase,
clickNewPageButton,
} from '@affine-test/kit/utils/page-logic';
import type { Page } from '@playwright/test';
import { expect } from '@playwright/test';
/**
* Create a new database block in the current page
*/
export async function createDatabaseBlock(page: Page) {
await clickNewPageButton(page);
await page.waitForTimeout(500);
await page.keyboard.press('Enter');
await addDatabase(page);
}
/**
* Initialize a database with specified number of rows
*/
export async function initDatabaseWithRows(page: Page, rowCount: number) {
await createDatabaseBlock(page);
for (let i = 0; i < rowCount; i++) {
await addDatabaseRow(page);
}
}
/**
* Add a new row to the database
*/
export async function addDatabaseRow(page: Page) {
const addButton = page.locator('.data-view-table-group-add-row');
await addButton.waitFor();
await addButton.click();
}
/**
* Simulate pasting Excel data into database
* @param page Playwright page object
* @param data Tab-separated text data with newlines for rows
*/
export async function pasteExcelData(page: Page, data: string) {
await page.evaluate(data => {
const clipboardData = new DataTransfer();
clipboardData.setData('text/plain', data);
const pasteEvent = new ClipboardEvent('paste', {
clipboardData,
bubbles: true,
cancelable: true,
});
document.activeElement?.dispatchEvent(pasteEvent);
}, data);
}
/**
* Select the first cell in the database
*/
export async function selectFirstCell(page: Page) {
const firstCell = page.locator('affine-database-cell-container').first();
await firstCell.waitFor();
await firstCell.click();
}
/**
* Verify the contents of multiple cells in sequence
* @param page Playwright page object
* @param expectedContents Array of expected cell contents in order
*/
export async function verifyCellContents(
page: Page,
expectedContents: string[]
) {
const cells = page.locator('affine-database-cell-container');
for (let i = 0; i < expectedContents.length; i++) {
const cell = cells.nth(i);
await expect(cell.locator('uni-lit > *:first-child')).toHaveText(
expectedContents[i]
);
}
}