Compare commits

...

5 Commits

Author SHA1 Message Date
Elena Torró
b28457860c Merge pull request #8388 from penpot/ladybenko-fix-cargo-clean
🔧 Run cargo clean on devenv start
2026-02-17 15:34:13 +01:00
Belén Albeza
23b268b414 🔧 Run cargo clean on devenv start 2026-02-17 15:08:30 +01:00
Elena Torró
32706a1460 Merge pull request #8386 from penpot/alotor-fix-watch-script
🐛 Fix watch script in wasm
2026-02-17 15:08:24 +01:00
alonso.torres
f0e3f1a319 🐛 Fix watch script in wasm 2026-02-17 14:27:36 +01:00
Alejandro Alonso
afb252f42e 🔧 Migrate text editor v2 tests to wasm viewport 2026-02-17 12:59:53 +01:00
9 changed files with 79 additions and 122 deletions

View File

@@ -40,8 +40,9 @@
"watch:app:libs": "node ./scripts/build-libs.js --watch",
"watch:app:main": "clojure -M:dev:shadow-cljs watch main worker storybook",
"clear:shadow-cache": "rm -rf .shadow-cljs",
"clear:wasm": "cargo clean --manifest-path ../render-wasm/Cargo.toml",
"watch": "exit 0",
"watch:app": "pnpm run clear:shadow-cache && pnpm run build:wasm && concurrently --kill-others-on-fail \"pnpm run watch:app:assets\" \"pnpm run watch:app:main\" \"pnpm run watch:app:libs\"",
"watch:app": "pnpm run clear:shadow-cache && pnpm run clear:wasm && pnpm run build:wasm && concurrently --kill-others-on-fail \"pnpm run watch:app:assets\" \"pnpm run watch:app:main\" \"pnpm run watch:app:libs\"",
"watch:storybook": "pnpm run build:storybook:assets && concurrently --kill-others-on-fail \"storybook dev -p 6006 --no-open\" \"node ./scripts/watch-storybook.js\""
},
"devDependencies": {

View File

@@ -35,8 +35,8 @@ export class WasmWorkspacePage extends WorkspacePage {
return WasmWorkspacePage.mockConfigFlags(this.page, flags);
}
constructor(page) {
super(page);
constructor(page, options) {
super(page, options);
this.canvas = page.getByTestId("canvas-wasm-shapes");
}

View File

@@ -35,45 +35,9 @@ export class WorkspacePage extends BaseWebSocketPage {
}
async waitForEditor() {
return this.page.waitForSelector('[data-itype="editor"]');
}
async waitForRoot() {
return this.page.waitForSelector('[data-itype="root"]');
}
async waitForParagraph(nth) {
if (!nth) {
return this.page.waitForSelector('[data-itype="paragraph"]');
}
return this.page.waitForSelector(
`[data-itype="paragraph"]:nth-child(${nth})`,
);
}
async waitForParagraphStyle(nth, styleName) {
const paragraph = await this.waitForParagraph(nth);
return this.waitForStyle(paragraph, styleName);
}
async waitForTextSpan(nth = 0) {
if (!nth) {
return this.page.waitForSelector('[data-itype="span"]');
}
return this.page.waitForSelector(
`[data-itype="span"]:nth-child(${nth})`,
);
}
async waitForTextSpanContent(nth = 0) {
const textSpan = await this.waitForTextSpan(nth);
const textContent = await textSpan.textContent();
return textContent;
}
async waitForTextSpanStyle(nth, styleName) {
const textSpan = await this.waitForTextSpan(nth);
return this.waitForStyle(textSpan, styleName);
const typographyInput =
this.workspacePage.rightSidebar.getByLabel("Font Size");
await expect(typographyInput).toBeVisible();
}
async startEditing() {
@@ -98,7 +62,7 @@ export class WorkspacePage extends BaseWebSocketPage {
}
async moveFromStart(offset = 0) {
await this.page.keyboard.press("ArrowLeft");
await this.page.keyboard.press("Home");
await this.moveToRight(offset);
}
@@ -125,7 +89,7 @@ export class WorkspacePage extends BaseWebSocketPage {
await expect(locator).toBeVisible();
await locator.focus();
await locator.fill(`${newValue}`);
await locator.blur();
await this.page.keyboard.press("Enter");
}
changeFontSize(newValue) {
@@ -390,10 +354,12 @@ export class WorkspacePage extends BaseWebSocketPage {
const timeToWait = options?.timeToWait ?? 100;
await this.page.keyboard.press("T");
await this.page.waitForTimeout(timeToWait);
const layersCountBefore = await this.layers.getByTestId("layer-row").count();
await this.clickAndMove(x1, y1, x2, y2);
await expect(this.page.getByTestId("text-editor")).toBeVisible();
if (initialText) {
await this.waitForSelectedShapeName("Text");
await this.page.keyboard.type(initialText);
}
}
@@ -493,10 +459,23 @@ export class WorkspacePage extends BaseWebSocketPage {
async expectSelectedLayer(name) {
await expect(
this.layers
.getByTestId("layer-row")
.filter({ has: this.page.getByText(name) }),
).toHaveClass(/selected/);
this.layers.getByRole("checkbox", { name, checked: true }),
).toBeVisible();
}
async getSelectedShapeName() {
const selectedLayer = this.layers
.getByRole("checkbox", { checked: true })
.first();
await selectedLayer.waitFor({ state: "visible" });
return (await selectedLayer.innerText()).trim();
}
async waitForSelectedShapeName(expectedName) {
const selectedLayer = this.layers
.getByRole("checkbox", { checked: true })
.first();
await expect(selectedLayer).toHaveText(expectedName);
}
async expectHiddenToolbarOptions() {

View File

@@ -1,14 +1,14 @@
import { test, expect } from "@playwright/test";
import { Clipboard } from "../../helpers/Clipboard";
import { WorkspacePage } from "../pages/WorkspacePage";
import { WasmWorkspacePage } from "../pages/WasmWorkspacePage";
const timeToWait = 100;
test.beforeEach(async ({ page, context }) => {
await Clipboard.enable(context, Clipboard.Permission.ALL);
await WorkspacePage.init(page);
await WorkspacePage.mockConfigFlags(page, ["enable-feature-text-editor-v2"]);
await WasmWorkspacePage.init(page);
await WasmWorkspacePage.mockConfigFlags(page, ["enable-feature-text-editor-v2"]);
});
test.afterEach(async ({ context }) => {
@@ -17,22 +17,21 @@ test.afterEach(async ({ context }) => {
test("Create a new text shape", async ({ page }) => {
const initialText = "Lorem ipsum";
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
await workspace.goToWorkspace();
await workspace.createTextShape(190, 150, 300, 200, initialText);
const textContent = await workspace.textEditor.waitForTextSpanContent();
expect(textContent).toBe(initialText);
await workspace.textEditor.stopEditing();
await workspace.waitForSelectedShapeName(initialText);
});
test("Create a new text shape from pasting text", async ({ page, context }) => {
const textToPaste = "Lorem ipsum";
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -43,13 +42,9 @@ test("Create a new text shape from pasting text", async ({ page, context }) => {
await workspace.clickAt(190, 150);
await workspace.paste("keyboard");
await page.waitForTimeout(timeToWait);
const textContent = await workspace.textEditor.waitForTextSpanContent();
expect(textContent).toBe(textToPaste);
await workspace.textEditor.stopEditing();
await expect(workspace.layers.getByText(textToPaste)).toBeVisible();
});
test("Create a new text shape from pasting text using context menu", async ({
@@ -57,7 +52,7 @@ test("Create a new text shape from pasting text using context menu", async ({
context,
}) => {
const textToPaste = "Lorem ipsum";
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -67,17 +62,15 @@ test("Create a new text shape from pasting text using context menu", async ({
await workspace.clickAt(190, 150);
await workspace.paste("context-menu");
const textContent = await workspace.textEditor.waitForTextSpanContent();
expect(textContent).toBe(textToPaste);
await workspace.textEditor.stopEditing();
await expect(workspace.layers.getByText(textToPaste)).toBeVisible();
});
test("Update an already created text shape by appending text", async ({
page,
}) => {
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -87,15 +80,14 @@ test("Update an already created text shape by appending text", async ({
await workspace.textEditor.startEditing();
await workspace.textEditor.moveFromEnd(0);
await page.keyboard.type(" dolor sit amet");
const textContent = await workspace.textEditor.waitForTextSpanContent();
expect(textContent).toBe("Lorem ipsum dolor sit amet");
await workspace.textEditor.stopEditing();
await workspace.waitForSelectedShapeName("Lorem ipsum dolor sit amet");
});
test("Update an already created text shape by prepending text", async ({
page,
}) => {
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -105,15 +97,14 @@ test("Update an already created text shape by prepending text", async ({
await workspace.textEditor.startEditing();
await workspace.textEditor.moveFromStart(0);
await page.keyboard.type("Dolor sit amet ");
const textContent = await workspace.textEditor.waitForTextSpanContent();
expect(textContent).toBe("Dolor sit amet Lorem ipsum");
await workspace.textEditor.stopEditing();
await workspace.waitForSelectedShapeName("Dolor sit amet Lorem ipsum");
});
test.skip("Update an already created text shape by inserting text in between", async ({
page,
}) => {
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -123,9 +114,8 @@ test.skip("Update an already created text shape by inserting text in between", a
await workspace.textEditor.startEditing();
await workspace.textEditor.moveFromStart(5);
await page.keyboard.type(" dolor sit amet");
const textContent = await workspace.textEditor.waitForTextSpanContent();
expect(textContent).toBe("Lorem dolor sit amet ipsum");
await workspace.textEditor.stopEditing();
await workspace.waitForSelectedShapeName("Lorem dolor sit amet ipsum");
});
test("Update a new text shape appending text by pasting text", async ({
@@ -133,7 +123,7 @@ test("Update a new text shape appending text by pasting text", async ({
context,
}) => {
const textToPaste = " dolor sit amet";
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -146,17 +136,16 @@ test("Update a new text shape appending text by pasting text", async ({
await workspace.textEditor.startEditing();
await workspace.textEditor.moveFromEnd();
await workspace.paste("keyboard");
const textContent = await workspace.textEditor.waitForTextSpanContent();
expect(textContent).toBe("Lorem ipsum dolor sit amet");
await workspace.textEditor.stopEditing();
});
await workspace.waitForSelectedShapeName("Lorem ipsum dolor sit amet");
});
test.skip("Update a new text shape prepending text by pasting text", async ({
page,
context,
}) => {
const textToPaste = "Dolor sit amet ";
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -169,16 +158,17 @@ test.skip("Update a new text shape prepending text by pasting text", async ({
await workspace.textEditor.startEditing();
await workspace.textEditor.moveFromStart();
await workspace.paste("keyboard");
const textContent = await workspace.textEditor.waitForTextSpanContent();
expect(textContent).toBe("Dolor sit amet Lorem ipsum");
await workspace.textEditor.stopEditing();
await workspace.hideUI();
await expect(workspace.canvas).toHaveScreenshot();
});
test("Update a new text shape replacing (starting) text with pasted text", async ({
page,
}) => {
const textToPaste = "Dolor sit amet";
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -192,17 +182,15 @@ test("Update a new text shape replacing (starting) text with pasted text", async
await workspace.paste("keyboard");
const textContent = await workspace.textEditor.waitForTextSpanContent();
expect(textContent).toBe("Dolor sit amet ipsum");
await workspace.textEditor.stopEditing();
await workspace.waitForSelectedShapeName("Dolor sit amet ipsum");
});
test("Update a new text shape replacing (ending) text with pasted text", async ({
page,
}) => {
const textToPaste = "dolor sit amet";
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -216,17 +204,15 @@ test("Update a new text shape replacing (ending) text with pasted text", async (
await workspace.paste("keyboard");
const textContent = await workspace.textEditor.waitForTextSpanContent();
expect(textContent).toBe("Lorem dolor sit amet");
await workspace.textEditor.stopEditing();
await workspace.waitForSelectedShapeName("Lorem dolor sit amet");
});
test("Update a new text shape replacing (in between) text with pasted text", async ({
page,
}) => {
const textToPaste = "dolor sit amet";
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -240,16 +226,14 @@ test("Update a new text shape replacing (in between) text with pasted text", asy
await workspace.paste("keyboard");
const textContent = await workspace.textEditor.waitForTextSpanContent();
expect(textContent).toBe("Lordolor sit ametsum");
await workspace.textEditor.stopEditing();
await workspace.waitForSelectedShapeName("Lordolor sit ametsum");
});
test("Update text font size selecting a part of it (starting)", async ({
page,
}) => {
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -260,18 +244,16 @@ test("Update text font size selecting a part of it (starting)", async ({
await workspace.textEditor.startEditing();
await workspace.textEditor.selectFromStart(5);
await workspace.textEditor.changeFontSize(36);
const textContent1 = await workspace.textEditor.waitForTextSpanContent(1);
expect(textContent1).toBe("Lorem");
const textContent2 = await workspace.textEditor.waitForTextSpanContent(2);
expect(textContent2).toBe(" ipsum");
await workspace.textEditor.stopEditing();
await workspace.hideUI();
await expect(workspace.canvas).toHaveScreenshot();
});
test.skip("Update text line height selecting a part of it (starting)", async ({
test("Update text line height selecting a part of it (starting)", async ({
page,
}) => {
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -281,24 +263,17 @@ test.skip("Update text line height selecting a part of it (starting)", async ({
await workspace.clickLeafLayer("Lorem ipsum");
await workspace.textEditor.startEditing();
await workspace.textEditor.selectFromStart(5);
await workspace.textEditor.changeLineHeight(1.4);
const lineHeight = await workspace.textEditor.waitForParagraphStyle(
1,
"line-height",
);
expect(lineHeight).toBe("1.4");
const textContent = await workspace.textEditor.waitForTextSpanContent();
expect(textContent).toBe("Lorem ipsum");
await workspace.textEditor.changeLineHeight(4.4);
await workspace.textEditor.stopEditing();
await workspace.hideUI();
await expect(workspace.canvas).toHaveScreenshot();
});
test.skip("Update text letter spacing selecting a part of it (starting)", async ({
page,
}) => {
const workspace = new WorkspacePage(page, {
const workspace = new WasmWorkspacePage(page, {
textEditor: true,
});
await workspace.setupEmptyFile();
@@ -309,16 +284,14 @@ test.skip("Update text letter spacing selecting a part of it (starting)", async
await workspace.textEditor.startEditing();
await workspace.textEditor.selectFromStart(5);
await workspace.textEditor.changeLetterSpacing(10);
const textContent1 = await workspace.textEditor.waitForTextSpanContent(1);
expect(textContent1).toBe("Lorem");
const textContent2 = await workspace.textEditor.waitForTextSpanContent(2);
expect(textContent2).toBe(" ipsum");
await workspace.textEditor.stopEditing();
await workspace.hideUI();
await expect(workspace.canvas).toHaveScreenshot();
});
test("BUG 11552 - Apply styles to the current caret", async ({ page }) => {
const workspace = new WorkspacePage(page);
const workspace = new WasmWorkspacePage(page);
await workspace.setupEmptyFile();
await workspace.mockGetFile("text-editor/get-file-11552.json");
await workspace.mockRPC(

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -84,6 +84,8 @@
:on-click on-select-shape
:on-context-menu on-context-menu
:data-testid "layer-row"
:role "checkbox"
:aria-checked selected?
:class (stl/css-case
:layer-row true
:highlight highlighted?

View File

@@ -13,6 +13,8 @@ copy_shared_artifact;
pushd $_SCRIPT_DIR;
cargo watch \
--why \
-i "_tmp*"
-x "build $CARGO_PARAMS" \
-s "./build" \
-s "echo 'DONE\n'";