mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-16 20:02:20 +02:00
Photoshop-parity editor client: layers, selection/masking, brushes,
smart filters, LUT import, Quick Edit, mobile gestures, workspaces,
batch operations, and the service-worker versioning (v978->v1006).
Source: vendor/photocraft (ad1cff44) photo-editor client files, merged
onto upstream/dev (a8c147b2). Conflict resolution documented in
pr_work/A_conflicts.md; editor files taken from vendor/photocraft
(upstream's editor is an earlier snapshot of the same feature).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
3.3 KiB
JavaScript
67 lines
3.3 KiB
JavaScript
const { test, expect } = require('@playwright/test');
|
|
const { selectTool } = require('./helpers.js');
|
|
const { dragOnCanvas, editorState, openBlankEditor, reopenDraft, waitForDraft } = require('./helpers.js');
|
|
|
|
test('independent layer locks enforce operations and survive undo and reopen', async ({ page, request }) => {
|
|
await openBlankEditor(page, { width: 360, height: 260 }, 'Layer locks E2E');
|
|
const editRow = page.locator('.ge-layer-item[data-layer-id]').filter({ hasText: 'Edit' }).first();
|
|
const lockButton = editRow.locator('.ge-layer-lock-btn');
|
|
const opacityRow = editRow.locator('.ge-layer-opacity-row');
|
|
const lockBox = await lockButton.boundingBox();
|
|
const opacityBox = await opacityRow.boundingBox();
|
|
expect(lockBox).toBeTruthy();
|
|
expect(opacityBox).toBeTruthy();
|
|
expect(lockBox.y + lockBox.height).toBeLessThanOrEqual(opacityBox.y + 1);
|
|
|
|
const toggleLock = async type => {
|
|
await lockButton.click();
|
|
const menu = page.locator('#ge-layer-lock-menu');
|
|
await expect(menu).toBeVisible();
|
|
await menu.locator(`[data-lock-type="${type}"]`).click();
|
|
};
|
|
|
|
await toggleLock('position');
|
|
expect((await editorState(page)).layers.find(layer => layer.name === 'Edit').locks.position).toBe(true);
|
|
await expect(lockButton).toHaveClass(/active/);
|
|
|
|
await selectTool(page, 'move');
|
|
await dragOnCanvas(page, { x: 0.35, y: 0.35 }, { x: 0.55, y: 0.50 });
|
|
expect((await editorState(page)).layers.find(layer => layer.name === 'Edit').offset).toEqual({ x: 0, y: 0 });
|
|
|
|
await page.locator('#ge-undo').click();
|
|
expect((await editorState(page)).layers.find(layer => layer.name === 'Edit').locks.position).toBe(false);
|
|
await page.locator('#ge-redo').click();
|
|
expect((await editorState(page)).layers.find(layer => layer.name === 'Edit').locks.position).toBe(true);
|
|
await toggleLock('position');
|
|
|
|
await toggleLock('pixels');
|
|
const emptyHash = (await editorState(page)).layers.find(layer => layer.name === 'Edit').pixelHash;
|
|
await selectTool(page, 'brush');
|
|
await dragOnCanvas(page, { x: 0.42, y: 0.42 }, { x: 0.58, y: 0.50 });
|
|
expect((await editorState(page)).layers.find(layer => layer.name === 'Edit').pixelHash).toBe(emptyHash);
|
|
await toggleLock('pixels');
|
|
|
|
await toggleLock('transparency');
|
|
await dragOnCanvas(page, { x: 0.42, y: 0.42 }, { x: 0.58, y: 0.50 });
|
|
expect((await editorState(page)).layers.find(layer => layer.name === 'Edit').pixelHash).toBe(emptyHash);
|
|
await toggleLock('transparency');
|
|
|
|
await dragOnCanvas(page, { x: 0.42, y: 0.42 }, { x: 0.58, y: 0.50 });
|
|
expect((await editorState(page)).layers.find(layer => layer.name === 'Edit').pixelHash).not.toBe(emptyHash);
|
|
|
|
await toggleLock('pixels');
|
|
await toggleLock('transparency');
|
|
await toggleLock('position');
|
|
const beforeReopen = await editorState(page);
|
|
const expectedLocks = beforeReopen.layers.find(layer => layer.name === 'Edit').locks;
|
|
expect(expectedLocks).toEqual({ pixels: true, transparency: true, position: true });
|
|
|
|
const draftId = await waitForDraft(page);
|
|
await reopenDraft(page, draftId);
|
|
const reopened = await editorState(page);
|
|
expect(reopened.layers.find(layer => layer.name === 'Edit').locks).toEqual(expectedLocks);
|
|
await expect(page.locator('.ge-layer-item[data-layer-id]').filter({ hasText: 'Edit' }).first().locator('.ge-layer-lock-btn')).toHaveClass(/active/);
|
|
|
|
await request.delete(`/api/editor-drafts/${encodeURIComponent(draftId)}`);
|
|
});
|