Files
AFFiNE-Mirror/blocksuite/tests-legacy/edgeless/selection/selection.spec.ts
2024-12-20 11:08:21 +00:00

467 lines
12 KiB
TypeScript

import { expect } from '@playwright/test';
import * as actions from '../../utils/actions/edgeless.js';
import {
getNoteBoundBoxInEdgeless,
setEdgelessTool,
switchEditorMode,
} from '../../utils/actions/edgeless.js';
import {
addBasicBrushElement,
addBasicRectShapeElement,
click,
clickInCenter,
dragBetweenCoords,
enterPlaygroundRoom,
getBoundingRect,
initEmptyEdgelessState,
initThreeParagraphs,
pressEnter,
waitNextFrame,
} from '../../utils/actions/index.js';
import {
assertBlockCount,
assertEdgelessRemoteSelectedModelRect,
assertEdgelessRemoteSelectedRect,
assertEdgelessSelectedModelRect,
assertEdgelessSelectedRect,
assertSelectionInNote,
} from '../../utils/asserts.js';
import { test } from '../../utils/playwright.js';
test('should update rect of selection when resizing viewport', async ({
page,
}) => {
await enterPlaygroundRoom(page);
await initEmptyEdgelessState(page);
await actions.switchEditorMode(page);
await actions.zoomResetByKeyboard(page);
await addBasicRectShapeElement(page, { x: 100, y: 100 }, { x: 200, y: 200 });
await dragBetweenCoords(page, { x: 120, y: 90 }, { x: 220, y: 130 });
const selectedRectClass = '.affine-edgeless-selected-rect';
await actions.zoomResetByKeyboard(page);
await assertEdgelessSelectedRect(page, [100, 100, 100, 100]);
await actions.decreaseZoomLevel(page);
await waitNextFrame(page);
await actions.decreaseZoomLevel(page);
await waitNextFrame(page);
const selectedRectInZoom = await getBoundingRect(page, selectedRectClass);
await assertEdgelessSelectedRect(page, [
selectedRectInZoom.x,
selectedRectInZoom.y,
50,
50,
]);
await actions.switchEditorEmbedMode(page);
await waitNextFrame(page);
const selectedRectInEmbed = await getBoundingRect(page, selectedRectClass);
await assertEdgelessSelectedRect(page, [
selectedRectInEmbed.x,
selectedRectInEmbed.y,
50,
50,
]);
await actions.switchEditorEmbedMode(page);
await actions.increaseZoomLevel(page);
await waitNextFrame(page);
await actions.increaseZoomLevel(page);
await waitNextFrame(page);
await assertEdgelessSelectedRect(page, [100, 100, 100, 100]);
});
test('should update react of remote selection when resizing viewport', async ({
context,
page: pageA,
}) => {
const room = await enterPlaygroundRoom(pageA);
await initEmptyEdgelessState(pageA);
await actions.switchEditorMode(pageA);
await actions.zoomResetByKeyboard(pageA);
const pageB = await context.newPage();
await enterPlaygroundRoom(pageB, {
room,
noInit: true,
});
await actions.switchEditorMode(pageB);
await actions.zoomResetByKeyboard(pageB);
await actions.createShapeElement(
pageA,
[0, 0],
[100, 100],
actions.Shape.Square
);
const point = await actions.toViewCoord(pageA, [50, 50]);
await click(pageA, { x: point[0], y: point[1] });
await click(pageB, { x: point[0], y: point[1] });
await assertEdgelessSelectedModelRect(pageB, [0, 0, 100, 100]);
await assertEdgelessRemoteSelectedModelRect(pageB, [0, 0, 100, 100]);
// to 50%
await actions.decreaseZoomLevel(pageB);
await waitNextFrame(pageB);
await actions.decreaseZoomLevel(pageB);
await waitNextFrame(pageB);
const selectedRectInZoom = await getBoundingRect(
pageB,
'.affine-edgeless-selected-rect'
);
await assertEdgelessRemoteSelectedRect(pageB, [
selectedRectInZoom.x,
selectedRectInZoom.y,
50,
50,
]);
});
test('select multiple shapes and translate', async ({ page }) => {
await enterPlaygroundRoom(page);
await initEmptyEdgelessState(page);
await switchEditorMode(page);
await actions.zoomResetByKeyboard(page);
await addBasicBrushElement(page, { x: 100, y: 100 }, { x: 200, y: 200 });
await page.mouse.click(110, 110);
await assertEdgelessSelectedRect(page, [98, 98, 104, 104]);
await addBasicRectShapeElement(page, { x: 210, y: 110 }, { x: 310, y: 210 });
await page.mouse.click(220, 120);
await assertEdgelessSelectedRect(page, [210, 110, 100, 100]);
await dragBetweenCoords(page, { x: 120, y: 90 }, { x: 220, y: 130 });
await assertEdgelessSelectedRect(page, [98, 98, 212, 112]);
await dragBetweenCoords(page, { x: 120, y: 120 }, { x: 150, y: 150 });
await assertEdgelessSelectedRect(page, [125, 128, 212, 112]);
await page.mouse.click(160, 160);
await assertEdgelessSelectedRect(page, [125, 128, 104, 104]);
await page.mouse.click(250, 150);
await assertEdgelessSelectedRect(page, [237, 140, 100, 100]);
});
test('selection box of shape element sync on fast dragging', async ({
page,
}) => {
await enterPlaygroundRoom(page);
await initEmptyEdgelessState(page);
await switchEditorMode(page);
await actions.zoomResetByKeyboard(page);
await setEdgelessTool(page, 'shape');
await dragBetweenCoords(page, { x: 100, y: 100 }, { x: 200, y: 200 });
await setEdgelessTool(page, 'default');
await dragBetweenCoords(
page,
{ x: 110, y: 110 },
{ x: 660, y: 460 },
{ click: true }
);
await assertEdgelessSelectedRect(page, [650, 446, 100, 100]);
});
test('when the selection is always a note, it should remain in an active state', async ({
page,
}) => {
await enterPlaygroundRoom(page);
const ids = await initEmptyEdgelessState(page);
await initThreeParagraphs(page);
await switchEditorMode(page);
await actions.zoomResetByKeyboard(page);
const bound = await getNoteBoundBoxInEdgeless(page, ids.noteId);
await setEdgelessTool(page, 'note');
const newNoteX = bound.x;
const newNoteY = bound.y + bound.height + 100;
// add text
await page.mouse.click(newNoteX, newNoteY);
await waitNextFrame(page);
await page.keyboard.type('hello');
await pressEnter(page);
// should wait for inline editor update and resizeObserver callback
await waitNextFrame(page);
// assert add text success
await assertBlockCount(page, 'edgeless-note', 2);
await clickInCenter(page, bound);
await clickInCenter(page, bound);
await waitNextFrame(page);
await assertSelectionInNote(page, ids.noteId, 'affine-edgeless-note');
});
test('should auto panning when selection rectangle reaches viewport edges', async ({
page,
}) => {
await enterPlaygroundRoom(page);
await initEmptyEdgelessState(page);
await switchEditorMode(page);
await actions.zoomResetByKeyboard(page);
await addBasicRectShapeElement(page, { x: 200, y: 100 }, { x: 300, y: 200 });
await page.mouse.click(210, 110);
await assertEdgelessSelectedRect(page, [200, 100, 100, 100]);
const selectedRectClass = '.affine-edgeless-selected-rect';
// Panning to the left
await setEdgelessTool(page, 'pan');
await dragBetweenCoords(
page,
{
x: 600,
y: 200,
},
{
x: 200,
y: 200,
}
);
await setEdgelessTool(page, 'default');
await page.mouse.click(210, 110);
let selectedRect = page.locator(selectedRectClass);
await page.waitForTimeout(300);
await expect(selectedRect).toBeHidden();
// Click to start selection and hold the mouse to trigger auto panning to the left
await page.mouse.move(210, 110);
await page.mouse.down();
await page.mouse.move(0, 210, { steps: 20 });
await page.waitForTimeout(500);
await page.mouse.up();
// Expect to select the shape element
selectedRect = page.locator(selectedRectClass);
await page.waitForTimeout(300);
await expect(selectedRect).toBeVisible();
// Panning to the top
await page.mouse.click(400, 600);
await setEdgelessTool(page, 'pan');
await dragBetweenCoords(
page,
{
x: 400,
y: 600,
},
{
x: 400,
y: 100,
}
);
await setEdgelessTool(page, 'default');
await page.mouse.click(600, 100);
selectedRect = page.locator(selectedRectClass);
await page.waitForTimeout(300);
await expect(selectedRect).toBeHidden();
// Click to start selection and hold the mouse to trigger auto panning to the top
await page.mouse.move(600, 100);
await page.mouse.down();
await page.mouse.move(400, 0, { steps: 20 });
await page.waitForTimeout(500);
await page.mouse.up();
// Expect to select the empty note
selectedRect = page.locator(selectedRectClass);
await page.waitForTimeout(300);
await expect(selectedRect).toBeVisible();
// Panning to the right
await page.mouse.click(100, 600);
await setEdgelessTool(page, 'pan');
await dragBetweenCoords(
page,
{
x: 20,
y: 600,
},
{
x: 1000,
y: 600,
}
);
await setEdgelessTool(page, 'default');
await page.mouse.click(800, 600);
selectedRect = page.locator(selectedRectClass);
await page.waitForTimeout(100);
await expect(selectedRect).toBeHidden();
// Click to start selection and hold the mouse to trigger auto panning to the right
await dragBetweenCoords(
page,
{
x: 800,
y: 600,
},
{
x: 1000,
y: 200,
},
{
beforeMouseUp: async () => {
await page.waitForTimeout(600);
},
}
);
// Expect to select the empty note
selectedRect = page.locator(selectedRectClass);
await page.waitForTimeout(300);
await expect(selectedRect).toBeVisible();
// Panning to the bottom
await page.mouse.click(400, 100);
await setEdgelessTool(page, 'pan');
await dragBetweenCoords(
page,
{
x: 400,
y: 100,
},
{
x: 400,
y: 850,
},
{
click: true,
}
);
await setEdgelessTool(page, 'default');
await waitNextFrame(page, 500);
await page.mouse.click(400, 400);
selectedRect = page.locator(selectedRectClass);
await page.waitForTimeout(100);
await expect(selectedRect).toBeHidden();
// Click to start selection and hold the mouse to trigger auto panning to the right
await dragBetweenCoords(
page,
{
x: 800,
y: 300,
},
{
x: 820,
y: 1150,
},
{
click: true,
beforeMouseUp: async () => {
await page.waitForTimeout(500);
},
}
);
// Expect to select the empty note
selectedRect = page.locator(selectedRectClass);
await page.waitForTimeout(300);
await expect(selectedRect).toBeVisible();
});
test('should also update dragging area when viewport changes', async ({
page,
}) => {
await enterPlaygroundRoom(page);
await initEmptyEdgelessState(page);
await switchEditorMode(page);
await actions.zoomResetByKeyboard(page);
// Panning to the top
await page.mouse.click(400, 600);
await setEdgelessTool(page, 'pan');
await dragBetweenCoords(
page,
{
x: 400,
y: 600,
},
{
x: 400,
y: 100,
}
);
await setEdgelessTool(page, 'default');
await page.mouse.click(200, 300);
const selectedRectClass = '.affine-edgeless-selected-rect';
let selectedRect = page.locator(selectedRectClass);
await expect(selectedRect).toBeHidden();
// set up initial dragging area
await page.mouse.move(200, 300);
await page.mouse.down();
await page.mouse.move(600, 200, { steps: 20 });
await page.waitForTimeout(300);
// wheel the viewport to the top
await page.mouse.wheel(0, -300);
await page.waitForTimeout(300);
await page.mouse.up();
// Expect to select the empty note
selectedRect = page.locator(selectedRectClass);
await page.waitForTimeout(300);
await expect(selectedRect).toBeVisible();
await page.waitForTimeout(300);
});
test('should select shapes while moving selection', async ({ page }) => {
await enterPlaygroundRoom(page);
await initEmptyEdgelessState(page);
await switchEditorMode(page);
await actions.zoomResetByKeyboard(page);
await addBasicRectShapeElement(page, { x: 100, y: 100 }, { x: 200, y: 200 });
// Make the selection out side the rect and move the selection to the rect
await dragBetweenCoords(
page,
// Make the selection not selecting the rect
{ x: 70, y: 70 },
{ x: 90, y: 90 },
{
beforeMouseUp: async () => {
await page.keyboard.down('Space');
// Move the selection over to the rect
await page.mouse.move(120, 120);
await page.keyboard.up('Space');
},
}
);
await assertEdgelessSelectedRect(page, [100, 100, 100, 100]);
await addBasicBrushElement(page, { x: 210, y: 100 }, { x: 310, y: 300 });
await page.mouse.click(211, 101);
// Make a wide selection and move it to select both of the shapes
await dragBetweenCoords(
page,
// Make the selection above the spaces
{ x: 70, y: 70 },
{ x: 400, y: 90 },
{
beforeMouseUp: async () => {
await page.keyboard.down('Space');
// Move the selection over both of the shapes
await page.mouse.move(400, 120);
await page.keyboard.up('Space');
},
}
);
await assertEdgelessSelectedRect(page, [100, 98, 212, 204]);
});