diff --git a/.eslintrc.js b/.eslintrc.js
index 6eb0be02d2..e9aafba8d9 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -156,6 +156,7 @@ module.exports = {
allowConditional: true,
},
],
+ "playwright/no-page-pause": "error",
"playwright/no-wait-for-timeout": "error",
"playwright/no-useless-not": "error",
"playwright/expect-expect": [
diff --git a/end-to-end-tests/fixtures/modDefinitions/brick-actions.yaml b/end-to-end-tests/fixtures/modDefinitions/brick-actions.yaml
new file mode 100644
index 0000000000..1267d45a20
--- /dev/null
+++ b/end-to-end-tests/fixtures/modDefinitions/brick-actions.yaml
@@ -0,0 +1,81 @@
+kind: recipe
+options:
+ schema:
+ type: object
+ properties: {}
+ uiSchema:
+ ui:order:
+ - "*"
+metadata:
+ id: "{{ modId }}"
+ name: Mod Actions Test
+ version: 1.0.0
+ description: Created with the PixieBrix Page Editor
+apiVersion: v3
+definitions:
+ extensionPoint:
+ kind: extensionPoint
+ definition:
+ type: menuItem
+ reader:
+ - "@pixiebrix/document-metadata"
+ - "@pixiebrix/document-context"
+ - element: "@pixiebrix/html/element"
+ isAvailable:
+ matchPatterns:
+ - https://github.com/*
+ urlPatterns: []
+ selectors: []
+ allFrames: true
+ containerSelector: span:has(> span:contains('Review in codespace'))
+ targetMode: document
+ attachMode: once
+ position: append
+ template: {{{ caption }}}
+extensionPoints:
+ - label: Button
+ config:
+ caption: Action
+ action:
+ - id: "@pixiebrix/form-modal"
+ rootMode: document
+ config:
+ schema:
+ title: Example Form
+ type: object
+ properties:
+ example:
+ title: Example Field
+ type: string
+ description: An example form field
+ uiSchema:
+ ui:order:
+ - "*"
+ cancelable: true
+ submitCaption: Submit
+ location: modal
+ outputKey: form
+ root: null
+ label: Custom modal 123
+ - id: "@pixiebrix/state/assign"
+ rootMode: document
+ config:
+ value: !nunjucks ""
+ root: null
+ label: Assign Mod Var Brick 123
+ - id: "@pixiebrix/browser/alert"
+ rootMode: document
+ config:
+ type: info
+ duration: 2500
+ message: !nunjucks ""
+ root: null
+ label: Alert Brick 123
+ dynamicCaption: false
+ onSuccess: true
+ synchronous: false
+ permissions:
+ origins: []
+ permissions: []
+ id: extensionPoint
+ services: {}
diff --git a/end-to-end-tests/pageObjects/extensionConsole/workshop/modEditor.ts b/end-to-end-tests/pageObjects/extensionConsole/workshop/modEditor.ts
index ced352261f..83902a847c 100644
--- a/end-to-end-tests/pageObjects/extensionConsole/workshop/modEditor.ts
+++ b/end-to-end-tests/pageObjects/extensionConsole/workshop/modEditor.ts
@@ -65,6 +65,12 @@ export class WorkshopModEditor extends BasePageObject {
);
const uuid = uuidv4();
const modId = `@extension-e2e-test-unaffiliated/${modDefinitionName}-${uuid}`;
+ if (!modDefinition.includes("{{ modId }}")) {
+ throw new Error(
+ `The mod definition ${modDefinitionName} does not contain the placeholder {{ modId }}`,
+ );
+ }
+
const replacedDefinition = modDefinition.replace("{{ modId }}", modId);
await this.textArea.fill(replacedDefinition);
diff --git a/end-to-end-tests/pageObjects/pageEditor/modListingPanel.ts b/end-to-end-tests/pageObjects/pageEditor/modListingPanel.ts
index c55b7adff2..434700545e 100644
--- a/end-to-end-tests/pageObjects/pageEditor/modListingPanel.ts
+++ b/end-to-end-tests/pageObjects/pageEditor/modListingPanel.ts
@@ -47,6 +47,7 @@ export class ModListItem extends BasePageObject {
export class ModListingPanel extends BasePageObject {
addButton = this.getByRole("button", { name: "Add", exact: true });
+ quickFilterInput = this.getByPlaceholder("Quick filter");
/**
* Adds a starter brick in the Page Editor. Generates a unique mod name to prevent
@@ -73,4 +74,18 @@ export class ModListingPanel extends BasePageObject {
modName,
);
}
+
+ getModStarterBrick(modName: string, starterBrickName: string) {
+ const modStarterBricks = this.locator(
+ `.collapse:below(:text("${modName}"))`,
+ );
+ return new ModListItem(
+ modStarterBricks
+ .locator(".list-group-item", {
+ hasText: starterBrickName,
+ })
+ .first(),
+ starterBrickName,
+ );
+ }
}
diff --git a/end-to-end-tests/tests/pageEditor/brickActions.spec.ts b/end-to-end-tests/tests/pageEditor/brickActions.spec.ts
new file mode 100644
index 0000000000..2b40437c82
--- /dev/null
+++ b/end-to-end-tests/tests/pageEditor/brickActions.spec.ts
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 PixieBrix, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import { expect, test } from "../../fixtures/testBase";
+// @ts-expect-error -- https://youtrack.jetbrains.com/issue/AQUA-711/Provide-a-run-configuration-for-Playwright-tests-in-specs-with-fixture-imports-only
+import { test as base } from "@playwright/test";
+import { ActivateModPage } from "../../pageObjects/extensionConsole/modsPage";
+
+const testModDefinitionName = "brick-actions";
+test.use({ modDefinitionNames: [testModDefinitionName] });
+test("brick actions panel shows when starter brick is selected", async ({
+ page,
+ extensionId,
+ modDefinitionsMap,
+ newPageEditorPage,
+}) => {
+ const { id: modId } = modDefinitionsMap[testModDefinitionName];
+ const modActivationPage = new ActivateModPage(page, extensionId, modId);
+ await modActivationPage.goto();
+ await modActivationPage.clickActivateAndWaitForModsPageRedirect();
+
+ await page.goto("/");
+ const pageEditorPage = await newPageEditorPage(page.url());
+
+ await pageEditorPage.modListingPanel
+ .getModListItemByName("Mod Actions Test")
+ .activate();
+
+ await expect(pageEditorPage.brickActionsPanel.root).toBeHidden();
+
+ const testStarterBrick = pageEditorPage.modListingPanel.getModStarterBrick(
+ "Mod Actions Test",
+ "Button",
+ );
+ await testStarterBrick.activate();
+ await expect(pageEditorPage.brickActionsPanel.root).toBeVisible();
+});