Files
metabase/e2e/test/scenarios/actions/model-actions.cy.spec.js
Kamil Mielnik 5a1d677444 RFC 118. Prettier - arrowParens: “always” (#55807)
* Update .prettierrc
- remove "arrowParens": "avoid" so that it defaults to "always" instead

* Run "yarn prettier"
2025-03-27 09:18:07 +00:00

913 lines
28 KiB
JavaScript

import { assocIn } from "icepick";
const { H } = cy;
import {
SAMPLE_DB_ID,
USER_GROUPS,
WRITABLE_DB_ID,
} from "e2e/support/cypress_data";
import { IMPERSONATED_USER_ID } from "e2e/support/cypress_sample_instance_data";
import { getCreatePostgresRoleIfNotExistSql } from "e2e/support/test_roles";
import { createMockActionParameter } from "metabase-types/api/mocks";
const WRITABLE_TEST_TABLE = "scoreboard_actions";
const TEST_PARAMETER = createMockActionParameter({
id: "49596bcb-62bb-49d6-a92d-bf5dbfddf43b",
name: "Total",
slug: "total",
type: "number/=",
target: ["variable", ["template-tag", "total"]],
});
const TEST_TEMPLATE_TAG = {
id: TEST_PARAMETER.id,
type: "number",
name: TEST_PARAMETER.slug,
"display-name": TEST_PARAMETER.name,
slug: TEST_PARAMETER.slug,
};
const SAMPLE_QUERY_ACTION = {
name: "Demo Action",
type: "query",
parameters: [TEST_PARAMETER],
database_id: WRITABLE_DB_ID,
dataset_query: {
type: "native",
native: {
query: `UPDATE ORDERS SET TOTAL = TOTAL WHERE ID = {{ ${TEST_TEMPLATE_TAG.name} }}`,
"template-tags": {
[TEST_TEMPLATE_TAG.name]: TEST_TEMPLATE_TAG,
},
},
database: WRITABLE_DB_ID,
},
visualization_settings: {
fields: {
[TEST_PARAMETER.id]: {
id: TEST_PARAMETER.id,
required: true,
fieldType: "number",
inputType: "number",
},
},
},
};
const SAMPLE_WRITABLE_QUERY_ACTION = assocIn(
SAMPLE_QUERY_ACTION,
["dataset_query", "native", "query"],
`UPDATE ${WRITABLE_TEST_TABLE} SET score = 22 WHERE id = {{ ${TEST_TEMPLATE_TAG.name} }}`,
);
describe(
"scenarios > models > actions",
{ tags: ["@external", "@actions"] },
() => {
beforeEach(() => {
H.restore("postgres-12");
cy.signInAsAdmin();
H.setActionsEnabledForDB(WRITABLE_DB_ID);
H.createModelFromTableName({
tableName: "orders",
modelName: "Order",
idAlias: "modelId",
});
cy.intercept("GET", "/api/card/*").as("getModel");
cy.intercept("GET", "/api/action/*").as("getAction");
cy.intercept("GET", "/api/action?model-id=*").as("getModelAction");
cy.intercept("PUT", "/api/action/*").as("updateAction");
cy.intercept("POST", "/api/action/*/execute").as("executeAction");
cy.intercept("POST", "/api/action").as("createAction");
cy.intercept("GET", "/api/table/*/query_metadata*").as("fetchMetadata");
cy.intercept("GET", "/api/search?archived=true").as("getArchived");
cy.intercept("GET", "/api/search?*").as("getSearchResults");
cy.intercept("GET", "/api/database?*").as("getDatabase");
});
it("should allow CRUD operations on model actions", () => {
cy.get("@modelId").then((id) => {
cy.visit(`/model/${id}/detail`);
cy.wait("@getModel");
});
createBasicActions();
cy.findByLabelText("Action list").within(() => {
cy.get("li").eq(0).findByText("Create").should("be.visible");
cy.get("li").eq(1).findByText("Update").should("be.visible");
cy.get("li").eq(2).findByText("Delete").should("be.visible");
});
cy.findByRole("link", { name: "New action" }).click();
H.fillActionQuery("DELETE FROM orders WHERE id = {{ id }}");
cy.findByRole("radiogroup", { name: "Field type" })
.findByText("Number")
.click();
cy.findByRole("button", { name: "Save" }).click();
H.modal()
.eq(1)
.within(() => {
cy.findByLabelText("Name").type("Delete Order");
cy.findByRole("button", { name: "Create" }).click();
});
cy.findByLabelText("Action list")
.findByText("Delete Order")
.should("be.visible");
openActionEditorFor("Delete Order");
H.fillActionQuery(" AND status = 'pending'");
cy.findByRole("radiogroup", { name: "Field type" })
.findByLabelText("Number")
.should("be.checked");
cy.findByRole("button", { name: "Update" }).click();
cy.findByLabelText("Action list")
.findByText(
"DELETE FROM orders WHERE id = {{ id }} AND status = 'pending'",
)
.should("be.visible");
openActionMenuFor("Delete Order");
H.popover().findByText("Archive").click();
H.modal().within(() => {
cy.findByText("Archive Delete Order?").should("be.visible");
cy.findByRole("button", { name: "Archive" }).click();
});
cy.findByRole("listitem", { name: "Delete Order" }).should("not.exist");
cy.findByLabelText("Actions menu").click();
H.popover().findByText("Disable basic actions").click();
H.modal().within(() => {
cy.findByText("Disable basic actions?").should("be.visible");
cy.button("Disable").click();
});
cy.findByRole("main").within(() => {
cy.findByLabelText("Action list").should("not.exist");
cy.findByText("Create").should("not.exist");
cy.findByText("Update").should("not.exist");
cy.findByText("Delete").should("not.exist");
});
});
it("should allow to create an action with the New button", () => {
const QUERY = "UPDATE orders SET discount = {{ discount }}";
cy.visit("/");
cy.findByTestId("app-bar").findByText("New").click();
H.popover().findByText("Action").click();
cy.wait("@getDatabase");
H.fillActionQuery(QUERY);
cy.findByRole("dialog").within(() => {
cy.findByText(/New Action/)
.clear()
.type("Discount order");
cy.findByRole("button", { name: "Save" }).click();
});
H.modal().eq(1).findByText("Select a model").click();
H.entityPickerModal().within(() => {
cy.findByText("Order").click();
});
cy.findByRole("button", { name: "Create" }).click();
cy.get("@modelId").then((modelId) => {
cy.url().should("include", `/model/${modelId}/detail/actions`);
});
});
it("should respect permissions", () => {
// Enabling actions for sample database as well
// to test database picker behavior in the action editor
H.setActionsEnabledForDB(SAMPLE_DB_ID);
H.setTokenFeatures("all");
cy.updatePermissionsGraph({
[USER_GROUPS.ALL_USERS_GROUP]: {
[WRITABLE_DB_ID]: {
"view-data": "blocked",
"create-queries": "no",
},
},
[USER_GROUPS.DATA_GROUP]: {
[WRITABLE_DB_ID]: {
"view-data": "unrestricted",
"create-queries": "query-builder-and-native",
},
},
});
cy.get("@modelId").then((modelId) => {
cy.request("POST", "/api/action", {
...SAMPLE_QUERY_ACTION,
model_id: modelId,
});
cy.signIn("readonly");
cy.visit(`/model/${modelId}/detail/actions`);
cy.wait("@getModel");
});
openActionMenuFor(SAMPLE_QUERY_ACTION.name);
H.popover().within(() => {
cy.findByText("Archive").should("not.exist");
cy.findByText("View").click();
});
cy.findByRole("dialog").within(() => {
cy.findByDisplayValue(SAMPLE_QUERY_ACTION.name).should("be.disabled");
cy.findByText("Sample Database").should("not.exist");
cy.findByText("QA Postgres12").should("not.exist");
cy.button("Save").should("not.exist");
cy.button("Update").should("not.exist");
assertQueryEditorDisabled();
cy.findByRole("form").within(() => {
cy.icon("gear").should("not.exist");
});
cy.findByLabelText("Action settings").click();
cy.findByLabelText("Success message").should("be.disabled");
});
cy.signIn("normal");
cy.reload();
// Check can pick between all databases
cy.findByRole("dialog").findByText("QA Postgres12").click();
H.popover().within(() => {
cy.findByText("Sample Database").should("be.visible");
cy.findByText("QA Postgres12").should("be.visible");
});
cy.signInAsAdmin();
H.setActionsEnabledForDB(SAMPLE_DB_ID, false);
cy.signIn("normal");
cy.reload();
// Check can only see the action database
cy.findByRole("dialog").within(() => {
cy.findByText("QA Postgres12").click();
cy.findByText("Sample Database").should("not.exist");
});
});
it("should display parameters for variable template tags only", () => {
cy.visit("/");
cy.findByTestId("app-bar").findByText("New").click();
H.popover().findByText("Action").click();
H.fillActionQuery("{{#1-orders-model}}");
cy.findByLabelText("#1-orders-model").should("not.exist");
H.fillActionQuery("{{snippet:101}}");
cy.findByLabelText("#1-orders-model").should("not.exist");
cy.findByLabelText("101").should("not.exist");
H.fillActionQuery("{{id}}");
cy.findByLabelText("#1-orders-model").should("not.exist");
cy.findByLabelText("101").should("not.exist");
cy.findByLabelText("ID").should("be.visible");
});
it("should show detailed form errors for constraint violations when executing model actions", () => {
const actionName = "Update";
cy.get("@modelId").then((modelId) => {
H.createImplicitActions({ modelId });
cy.visit(`/model/${modelId}/detail`);
cy.wait("@getModel");
});
runActionFor(actionName);
H.modal().within(() => {
cy.findByLabelText("ID").type("1");
cy.findByLabelText("User ID").type("999999");
cy.button(actionName).click();
cy.wait("@executeAction");
cy.findByLabelText("User ID").should("not.exist");
cy.findByLabelText("User ID: This User_id does not exist.").should(
"exist",
);
cy.findByText("Unable to update the record.").should("exist");
});
});
},
);
["postgres", "mysql"].forEach((dialect) => {
describe(
`Write actions on model detail page (${dialect})`,
{ tags: "@external" },
() => {
beforeEach(() => {
cy.intercept("GET", "/api/card/*").as("getModel");
cy.intercept("GET", "/api/action/*").as("getAction");
cy.intercept("PUT", "/api/action/*").as("updateAction");
cy.intercept("POST", "/api/action").as("createAction");
cy.intercept("POST", "/api/action/*/public_link").as(
"enableActionSharing",
);
cy.intercept("DELETE", "/api/action/*/public_link").as(
"disableActionSharing",
);
H.restore(`${dialect}-writable`);
H.resetTestTable({ type: dialect, table: WRITABLE_TEST_TABLE });
cy.signInAsAdmin();
H.resyncDatabase({
dbId: WRITABLE_DB_ID,
tableName: WRITABLE_TEST_TABLE,
});
H.createModelFromTableName({
tableName: WRITABLE_TEST_TABLE,
idAlias: "writableModelId",
});
});
it("should allow action execution from the model detail page", () => {
H.queryWritableDB(
`SELECT * FROM ${WRITABLE_TEST_TABLE} WHERE id = 1`,
dialect,
).then((result) => {
const row = result.rows[0];
expect(row.score).to.equal(0);
});
cy.get("@writableModelId").then((modelId) => {
H.createAction({
...SAMPLE_WRITABLE_QUERY_ACTION,
model_id: modelId,
});
cy.visit(`/model/${modelId}/detail/actions`);
cy.wait("@getModel");
});
runActionFor(SAMPLE_QUERY_ACTION.name);
H.modal().within(() => {
cy.findByLabelText(TEST_PARAMETER.name).type("1");
cy.button(SAMPLE_QUERY_ACTION.name).click();
});
cy.findByTestId("toast-undo")
.findByText(`${SAMPLE_QUERY_ACTION.name} ran successfully`)
.should("be.visible");
H.queryWritableDB(
`SELECT * FROM ${WRITABLE_TEST_TABLE} WHERE id = 1`,
dialect,
).then((result) => {
const row = result.rows[0];
expect(row.score).to.equal(22);
});
});
it("should allow public sharing of actions and execution of public actions", () => {
const IMPLICIT_ACTION_NAME = "Update";
cy.get("@writableModelId").then((modelId) => {
H.createAction({
...SAMPLE_WRITABLE_QUERY_ACTION,
model_id: modelId,
});
H.createAction({
type: "implicit",
kind: "row/update",
name: IMPLICIT_ACTION_NAME,
model_id: modelId,
});
cy.visit(`/model/${modelId}/detail/actions`);
cy.wait("@getModel");
});
enableSharingFor(SAMPLE_WRITABLE_QUERY_ACTION.name, {
publicUrlAlias: "queryActionPublicUrl",
});
enableSharingFor(IMPLICIT_ACTION_NAME, {
publicUrlAlias: "implicitActionPublicUrl",
});
cy.signOut();
cy.get("@queryActionPublicUrl").then((url) => {
cy.visit(url);
cy.findByLabelText(TEST_PARAMETER.name).type("1");
cy.button(SAMPLE_QUERY_ACTION.name).click();
cy.findByText(
`${SAMPLE_WRITABLE_QUERY_ACTION.name} ran successfully`,
).should("be.visible");
cy.findByRole("form").should("not.exist");
cy.button(SAMPLE_QUERY_ACTION.name).should("not.exist");
H.queryWritableDB(
`SELECT * FROM ${WRITABLE_TEST_TABLE} WHERE id = 1`,
dialect,
).then((result) => {
const row = result.rows[0];
expect(row.score).to.equal(22);
});
});
cy.get("@implicitActionPublicUrl").then((url) => {
cy.visit(url);
// team 2 has 10 points, let's give them more
cy.findByLabelText("ID").type("2");
cy.findByLabelText(/score/i).type("16");
cy.findByLabelText(/team name/i).type("Bouncy Bears");
cy.button(IMPLICIT_ACTION_NAME).click();
cy.findByText(`${IMPLICIT_ACTION_NAME} ran successfully`).should(
"be.visible",
);
cy.findByRole("form").should("not.exist");
cy.button(IMPLICIT_ACTION_NAME).should("not.exist");
H.queryWritableDB(
`SELECT * FROM ${WRITABLE_TEST_TABLE} WHERE id = 2`,
dialect,
).then((result) => {
const row = result.rows[0];
expect(row.score).to.equal(16);
expect(row.team_name).to.equal("Bouncy Bears");
// should not mutate form fields that we don't touch
expect(row.status).to.not.be.a("null");
});
});
cy.signInAsAdmin();
cy.get("@writableModelId").then((modelId) => {
cy.visit(`/model/${modelId}/detail/actions`);
cy.wait("@getModel");
});
disableSharingFor(SAMPLE_QUERY_ACTION.name);
disableSharingFor(IMPLICIT_ACTION_NAME);
cy.signOut();
cy.get("@queryActionPublicUrl").then((url) => {
cy.visit(url);
cy.findByRole("form").should("not.exist");
cy.button(SAMPLE_QUERY_ACTION.name).should("not.exist");
cy.findByText("Not found").should("be.visible");
});
cy.get("@implicitActionPublicUrl").then((url) => {
cy.visit(url);
cy.findByRole("form").should("not.exist");
cy.button(SAMPLE_QUERY_ACTION.name).should("not.exist");
cy.findByText("Not found").should("be.visible");
});
});
it("should allow query action execution from the model details page", () => {
verifyScoreValue(0, dialect);
cy.get("@writableModelId").then((modelId) => {
H.createAction({
...SAMPLE_WRITABLE_QUERY_ACTION,
model_id: modelId,
});
cy.visit(`/model/${modelId}/detail/actions`);
cy.wait("@getModel");
});
openActionEditorFor(SAMPLE_QUERY_ACTION.name);
H.fillActionQuery(" [[and status = {{ current_status}}]]");
cy.findAllByTestId("form-field-container")
.filter(":contains('Current Status')")
.within(() => {
cy.findByLabelText("Show field").click();
cy.icon("gear").click();
});
H.popover().within(() => {
cy.findByLabelText("Required").uncheck();
});
cy.findByRole("button", { name: "Update" }).click();
runActionFor(SAMPLE_QUERY_ACTION.name);
H.modal().within(() => {
cy.findByLabelText(TEST_PARAMETER.name).type("1");
cy.findByLabelText("Current Status").should("not.exist");
cy.button(SAMPLE_QUERY_ACTION.name).click();
});
cy.findByTestId("toast-undo")
.findByText(`${SAMPLE_QUERY_ACTION.name} ran successfully`)
.should("be.visible");
verifyScoreValue(22, dialect);
openActionEditorFor(SAMPLE_QUERY_ACTION.name);
cy.findAllByTestId("form-field-container")
.filter(":contains('Current Status')")
.within(() => {
cy.icon("gear").click();
});
H.popover().within(() => {
cy.findByLabelText("Required").check();
});
cy.findByRole("button", { name: "Update" }).click();
runActionFor(SAMPLE_QUERY_ACTION.name);
H.modal().within(() => {
cy.findByLabelText(TEST_PARAMETER.name).type("1");
cy.findByLabelText("Current Status").should("not.exist");
cy.button(SAMPLE_QUERY_ACTION.name).should("be.disabled");
cy.findByRole("button", { name: "Cancel" }).click();
});
openActionEditorFor(SAMPLE_QUERY_ACTION.name);
// reset score value to 0
resetAndVerifyScoreValue(dialect);
cy.findByRole("dialog").within(() => {
cy.findAllByTestId("form-field-container")
.filter(":contains('Current Status')")
.within(() => {
cy.findByLabelText("Show field").click();
cy.findByLabelText("Show field").should("be.checked");
});
cy.findByRole("button", { name: "Update" }).click();
});
runActionFor(SAMPLE_QUERY_ACTION.name);
H.modal().within(() => {
cy.findByLabelText(TEST_PARAMETER.name).type("1");
cy.button(SAMPLE_QUERY_ACTION.name).should("be.disabled");
cy.findByLabelText("Current Status").type("active");
cy.button(SAMPLE_QUERY_ACTION.name).click();
});
verifyScoreValue(22, dialect);
});
it("should allow implicit action execution from the model details page", () => {
cy.get("@writableModelId").then((id) => {
cy.visit(`/model/${id}/detail`);
cy.wait("@getModel");
});
createBasicActions();
openActionEditorFor("Create");
cy.wait("@getAction").then(({ response }) => {
const { parameters, visualization_settings } = response.body;
expect(parameters).to.have.length(5);
expect(visualization_settings).to.have.property("fields");
});
cy.findAllByTestId("form-field-container")
.filter(":contains('Created At')")
.within(() => {
cy.findByLabelText("Show field").click();
cy.findByLabelText("Show field").should("not.be.checked");
});
cy.findByRole("button", { name: "Update" }).click();
runActionFor("Create");
H.modal().within(() => {
cy.findByLabelText("Created At").should("not.exist");
cy.findByLabelText("Team Name").type("Zebras");
cy.findByLabelText("Score").type("1");
cy.findByRole("button", { name: "Save" }).click();
});
cy.findByTestId("toast-undo")
.findByText("Successfully saved")
.should("be.visible");
// show toast
H.queryWritableDB(
`SELECT * FROM ${WRITABLE_TEST_TABLE} WHERE team_name = 'Zebras'`,
dialect,
).then((result) => {
expect(result.rows.length).to.equal(1);
const row = result.rows[0];
expect(row.score).to.equal(1);
});
});
it("should allow public sharing of query action and execution", () => {
cy.get("@writableModelId").then((modelId) => {
H.createAction({
...SAMPLE_WRITABLE_QUERY_ACTION,
model_id: modelId,
});
cy.visit(`/model/${modelId}/detail/actions`);
cy.wait("@getModel");
});
enableSharingFor(SAMPLE_WRITABLE_QUERY_ACTION.name, {
publicUrlAlias: "queryActionPublicUrl",
});
openActionEditorFor(SAMPLE_WRITABLE_QUERY_ACTION.name);
H.fillActionQuery(" [[ AND status = {{new_status}} ]]");
cy.findAllByTestId("form-field-container")
.filter(":contains('New Status')")
.within(() => {
cy.findByLabelText("Show field").click();
cy.findByLabelText("Show field").should("not.be.checked");
cy.icon("gear").click();
});
H.popover().within(() => {
cy.findByLabelText("Required").uncheck();
});
cy.findByRole("button", { name: "Update" }).click();
cy.signOut();
cy.get("@queryActionPublicUrl").then((url) => {
cy.visit(url);
cy.findByLabelText(TEST_PARAMETER.name).type("1");
cy.findByLabelText("New Status").should("not.exist");
cy.button(SAMPLE_QUERY_ACTION.name).click();
cy.findByText(
`${SAMPLE_WRITABLE_QUERY_ACTION.name} ran successfully`,
).should("be.visible");
H.queryWritableDB(
`SELECT * FROM ${WRITABLE_TEST_TABLE} WHERE id = 1`,
dialect,
).then((result) => {
const row = result.rows[0];
expect(row.score).to.equal(22);
});
});
});
it("should allow public sharing of implicit action and execution", () => {
cy.get("@writableModelId").then((id) => {
cy.visit(`/model/${id}/detail`);
cy.wait("@getModel");
});
createBasicActions();
enableSharingFor("Update", { publicUrlAlias: "updatePublicURL" });
openActionEditorFor("Update");
cy.findAllByTestId("form-field-container")
.filter(":contains('Created At')")
.within(() => {
cy.findByLabelText("Show field").click();
cy.findByLabelText("Show field").should("not.be.checked");
});
cy.findByRole("button", { name: "Update" }).click();
cy.wait("@updateAction");
cy.signOut();
cy.get("@updatePublicURL").then((url) => {
cy.visit(url);
// team 2 has 10 points, let's give them more
cy.findByLabelText("ID").type("2");
cy.findByLabelText("Score").type("16");
cy.findByLabelText("Team Name").type("Bouncy Bears");
cy.findByLabelText("Create At").should("not.exist");
cy.button("Update").click();
cy.findByText("Update ran successfully").should("be.visible");
H.queryWritableDB(
`SELECT * FROM ${WRITABLE_TEST_TABLE} WHERE id = 2`,
dialect,
).then((result) => {
const row = result.rows[0];
expect(row.score).to.equal(16);
expect(row.team_name).to.equal("Bouncy Bears");
});
});
});
it("should respect impersonated permission", () => {
cy.onlyOn(dialect === "postgres");
const role = "readonly_role";
const sql = getCreatePostgresRoleIfNotExistSql(
role,
`GRANT SELECT ON ${WRITABLE_TEST_TABLE} TO ${role};`,
);
H.setTokenFeatures("all");
H.queryWritableDB(sql);
cy.request("PUT", `/api/user/${IMPERSONATED_USER_ID}`, {
login_attributes: { role },
});
cy.updatePermissionsGraph(
{
[USER_GROUPS.ALL_USERS_GROUP]: {
[WRITABLE_DB_ID]: {
"view-data": "impersonated",
"create-queries": "query-builder-and-native",
},
},
// By default, all groups get `unrestricted` access that will override the impersonation.
[USER_GROUPS.COLLECTION_GROUP]: {
[WRITABLE_DB_ID]: {
"view-data": "blocked",
},
},
},
[
{
db_id: WRITABLE_DB_ID,
group_id: USER_GROUPS.ALL_USERS_GROUP,
attribute: "role",
},
],
);
H.queryWritableDB(
`SELECT *
FROM ${WRITABLE_TEST_TABLE}
WHERE id = 1`,
dialect,
).then((result) => {
const row = result.rows[0];
expect(row.score).to.equal(0);
});
cy.get("@writableModelId").then((modelId) => {
H.createAction({
...SAMPLE_WRITABLE_QUERY_ACTION,
model_id: modelId,
});
cy.signInAsImpersonatedUser();
cy.visit(`/model/${modelId}/detail/actions`);
cy.wait("@getModel");
});
runActionFor(SAMPLE_QUERY_ACTION.name);
H.modal().within(() => {
cy.findByLabelText(TEST_PARAMETER.name).type("1");
cy.button(SAMPLE_QUERY_ACTION.name).click();
cy.findByText(
"Error executing Action: Error executing write query: ERROR: permission denied for table scoreboard_actions",
);
});
H.queryWritableDB(
`SELECT *
FROM ${WRITABLE_TEST_TABLE}
WHERE id = 1`,
dialect,
).then((result) => {
const row = result.rows[0];
expect(row.score).to.equal(0);
});
});
},
);
});
function runActionFor(actionName) {
cy.findByRole("listitem", { name: actionName }).within(() => {
cy.icon("play").click();
});
cy.wait("@getAction");
}
function openActionMenuFor(actionName) {
cy.findByRole("listitem", { name: actionName }).within(() => {
cy.icon("ellipsis").click();
});
}
function openActionEditorFor(actionName, { isReadOnly = false } = {}) {
openActionMenuFor(actionName);
H.popover()
.findByText(isReadOnly ? "View" : "Edit")
.click();
}
function assertQueryEditorDisabled() {
// Ace doesn't act as a normal input, so we can't use `should("be.disabled")`
// Instead we'd assert that a user can't type in the editor
H.fillActionQuery("QWERTY");
cy.findByText("QWERTY").should("not.exist");
}
function enableSharingFor(actionName, { publicUrlAlias }) {
openActionEditorFor(actionName);
cy.findByRole("dialog").within(() => {
cy.button("Action settings").click();
cy.findByLabelText("Make public").should("not.be.checked").parent().click();
cy.wait("@enableActionSharing");
cy.findByLabelText("Public action form URL")
.invoke("val")
.then((url) => {
cy.wrap(url).as(publicUrlAlias);
});
cy.button("Cancel").click();
});
}
function disableSharingFor(actionName) {
openActionEditorFor(actionName);
cy.findByRole("dialog").within(() => {
cy.findByRole("button", { name: "Action settings" }).click();
cy.findByLabelText("Make public").should("be.checked").parent().click();
});
H.modal()
.eq(1)
.within(() => {
cy.findByText("Disable this public link?").should("be.visible");
cy.findByRole("button", { name: "Yes" }).click();
});
cy.wait("@disableActionSharing");
cy.findByRole("dialog").within(() => {
cy.button("Cancel").click();
});
}
function resetAndVerifyScoreValue(dialect) {
const newValue = 0;
H.queryWritableDB(
`UPDATE ${WRITABLE_TEST_TABLE} SET score = ${newValue} WHERE id = 1`,
dialect,
);
verifyScoreValue(newValue, dialect);
}
function verifyScoreValue(value, dialect) {
H.queryWritableDB(
`SELECT * FROM ${WRITABLE_TEST_TABLE} WHERE id = 1`,
dialect,
).then((result) => {
const row = result.rows[0];
expect(row.score).to.equal(value);
});
}
function createBasicActions() {
cy.findByRole("button", { name: /Create basic actions/i }).click();
cy.wait(["@createAction", "@createAction", "@createAction"]);
}