Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion playwright-tests/data/actionBlockElements.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"Encoder Push & Rotate": ["push rotate", "just rotate", "end"]
},
"code": {
"Code Block": ["input", "Edit Code"],
"Code Block": ["input", "Open Editor"],
"Comment Block": ["input"],
"Element Name": ["input"]
},
Expand Down
4 changes: 2 additions & 2 deletions playwright-tests/data/actionBlockLocators.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,8 @@ export const blocks = (page) => ({
"Code Block": {
block: page.locator("#action-menu").getByText("Code Block"),
elements: {
input: page.locator("pre"),
"Edit Code": page.getByRole("button", { name: "Edit Code" }),
input: page.locator("code-block .view-line").first(),
"Open Editor": page.getByRole("button", { name: "Open Editor" }),
},
},
"Comment Block": {
Expand Down
47 changes: 41 additions & 6 deletions playwright-tests/pages/configPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,18 @@ export class ConfigPage {
.filter({ hasText: "End" })
.locator("action-placeholder div")
.first();
this.commitCodeButton = page.getByRole("button", { name: "Commit" });
this.closeCodeButton = page.getByRole("button", { name: "Close" });
this.codeblockInput = page.locator(".view-line").first();
// The code block now has an inline editor with its own Commit button, so
// scope these to the full-screen editor modal (#monaco-container and its
// parent, which holds the modal's Commit/Close buttons).
this.commitCodeButton = page
.locator("#monaco-container")
.locator("xpath=..")
.getByRole("button", { name: "Commit" });
this.closeCodeButton = page
.locator("#monaco-container")
.locator("xpath=..")
.getByRole("button", { name: "Close" });
this.codeblockInput = page.locator("#monaco-container .view-line").first();
this.codeBlockCharacterLimitMessage = page.getByText(
"Config limit reached.",
);
Expand All @@ -100,11 +109,13 @@ export class ConfigPage {
}

async openAndAddActionBlock(category, blockName) {
await this.resetTransientUi();
await this.addActionBlockButton.click();
await this.blocks[category][blockName]["block"].click();
}

async openActionBlockList() {
await this.resetTransientUi();
await this.addActionBlockButton.click();
}

Expand Down Expand Up @@ -178,7 +189,10 @@ export class ConfigPage {
// Element and Action Operations

async selectAllActions() {
await this.configFocus.click();
// Focus the config panel itself rather than clicking into the area (which
// can land in an inline code editor that captures Ctrl+A as select-text),
// so the select-all-actions shortcut actually fires.
await this.page.locator(".configpanel").first().focus();
await this.keyboardActions.selectAll();
}

Expand All @@ -196,6 +210,26 @@ export class ConfigPage {

async clearElement() {
await this.elementButtons.clear.click();
// Clearing raises a transient progress toast ("Clearing element
// configuration..." → "...was reset to default!") that overlays the UI and
// can intercept the next click — including in a following test, since the
// page is shared across the spec. Reset it so it can't bleed across.
await this.resetTransientUi();
}

// Reset transient, page-level UI that bleeds across tests on the shared page:
// notification toasts (which otherwise linger ~5s) via the web build's test
// hook, and any leftover-open action menu / popover (Escape). Both can
// overlay and intercept a later click.
async resetTransientUi() {
await this.page
.evaluate(() => window.__gridTest?.resetLogStream?.())
.catch(() => {});
// Close any leftover-open action menu. Its search input is auto-focused and
// swallows Escape, so blur first to let the key reach the menu's
// document-level Escape handler.
await this.page.evaluate(() => document.activeElement?.blur());
await this.page.keyboard.press("Escape");
}

async copyAction() {
Expand Down Expand Up @@ -244,8 +278,9 @@ export class ConfigPage {

async addAndEditCodeBlock(code) {
await this.addCodeBlock();
await this.blocks["code"]["Code Block"]["elements"]["Edit Code"].click();
await this.page.getByText("Synced with Grid!").click();
await this.blocks["code"]["Code Block"]["elements"]["Open Editor"].click();
// Both the inline block and the modal show this status, so target one.
await this.page.getByText("Synced with Grid!").first().click();
await this.codeblockInput.click({ clickCount: 1 });

await this.keyboardActions.selectAll();
Expand Down
10 changes: 8 additions & 2 deletions playwright-tests/pages/modulePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,14 @@ export class ModulePage {
name: "Actions have been copied",
});

this.characterLimitPasteToast = page.getByText("Modifications can not");
this.characterLimitAddToast = page.getByText("Modifications can not");
// The same toast can stack (one per affected module/event), so target one
// to avoid strict-mode violations.
this.characterLimitPasteToast = page
.getByText("Modifications can not")
.first();
this.characterLimitAddToast = page
.getByText("Modifications can not")
.first();
this.storeButton = page.getByRole("button", { name: "Store" });
this.clearButton = page.getByRole("button", { name: "Clear" });
this.confirmClearButton = page.getByRole("button", {
Expand Down
3 changes: 3 additions & 0 deletions playwright-tests/tests/actionBlockExistence.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ async function setupModule(moduleName) {
await connectModulePage.addModule(moduleName);
}
async function changeModuleIfNeeded(category) {
// A prior test can leave the action menu open / a toast up on the shared
// page, which would intercept the "Remove Module" click below.
await configPage.resetTransientUi();
if (category === "specialButton") {
await modulePage.removeModule();
await setupModule("BU16");
Expand Down
2 changes: 1 addition & 1 deletion playwright-tests/tests/blocksTests.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ test.describe("Issues", () => {
await configPage.selectAllActions();
await page
.getByTestId("action-block")
.filter({ hasText: 'Code preview: print("hello")' })
.filter({ hasText: 'print("hello")' })
.getByTestId(/^action-checkbox/)
.click(); //uncheck codeblock
await configPage.removeAction();
Expand Down
9 changes: 9 additions & 0 deletions src/renderer/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import { debug_lowlevel_store } from "./main/panels/WebsocketMonitor/WebsocketMonitor.store";

import { logger } from "./runtime/runtime.store";
import { logStreamStore } from "./main/user-interface/cursor-log/LogStream.store";

import MiddlePanelContainer from "./main/MiddlePanelContainer.svelte";
import PanelToggleButton from "./main/PanelToggleButton.svelte";
Expand Down Expand Up @@ -285,6 +286,14 @@
//Disable Context Menu
onMount(async () => {
document.addEventListener("contextmenu", preventContextMenuEvent);
// Test-only seam: let the (web build) e2e suite reset transient UI state —
// notification toasts that otherwise linger ~5s and bleed across tests.
if (import.meta.env.VITE_BUILD_TARGET === "web") {
(window as any).__gridTest = {
...(window as any).__gridTest,
resetLogStream: () => logStreamStore.reset(),
};
}
loaded = true;
window.electron.appLoaded();
});
Expand Down
Loading
Loading