167 lines
5.6 KiB
TypeScript
167 lines
5.6 KiB
TypeScript
import { WRITABLE_DB_ID } from "e2e/support/cypress_data";
|
|
import {
|
|
DATA_APP_DISPLAY_NAME as APP_DISPLAY_NAME,
|
|
DATA_APP_NAME as APP_NAME,
|
|
createDataAppCollection,
|
|
createDataAppScoreboardAction,
|
|
visitDataAppRoute as visitAppRoute,
|
|
} from "e2e/support/helpers";
|
|
import type { CollectionPermission } from "metabase-types/api";
|
|
|
|
import { DATA_APP_TEST_ENV as TEST_ENV } from "./helpers";
|
|
|
|
const { H } = cy;
|
|
|
|
const TEST_TABLE = "scoreboard_actions";
|
|
const EXISTING_TEAM = "Amorous Aardvarks";
|
|
const RESOURCE_COLLECTION = "Data App resources";
|
|
|
|
describe(
|
|
"scenarios > data apps > actions (useAction)",
|
|
{ tags: ["@external", "@actions"] },
|
|
() => {
|
|
beforeEach(() => {
|
|
H.restore("postgres-writable");
|
|
cy.signInAsAdmin();
|
|
H.activateToken("bleeding-edge");
|
|
|
|
H.resetTestTable({ type: "postgres", table: TEST_TABLE });
|
|
H.resyncDatabase({ dbId: WRITABLE_DB_ID, tableName: TEST_TABLE });
|
|
H.setActionsEnabledForDB(WRITABLE_DB_ID);
|
|
});
|
|
|
|
const setupActionsApp = (actionParams: Record<string, string | number>) =>
|
|
createDataAppScoreboardAction().then((action) => {
|
|
H.mockDataApp(APP_NAME, {
|
|
displayName: APP_DISPLAY_NAME,
|
|
testEnv: { ...TEST_ENV, actionId: action.id, actionParams },
|
|
});
|
|
});
|
|
|
|
it("executes the action, exposing isExecuting and result, and resets", () => {
|
|
cy.intercept("POST", "/api/action/*/execute", (req) => {
|
|
req.on("response", (res) => {
|
|
res.setDelay(300);
|
|
});
|
|
});
|
|
|
|
setupActionsApp({ team_name: "Data App FC", score: 7 });
|
|
|
|
visitAppRoute("actions");
|
|
H.dataAppIframe(APP_DISPLAY_NAME).within(() => {
|
|
cy.findByTestId("action-execute").click();
|
|
cy.findByTestId("action-executing").should("have.text", "executing");
|
|
|
|
cy.findByTestId("action-result", { timeout: 30000 }).should(
|
|
"have.text",
|
|
"has-result",
|
|
);
|
|
cy.findByTestId("action-output").should("have.text", "returned-result");
|
|
cy.findByTestId("action-error").should("have.text", "no-error");
|
|
|
|
cy.findByTestId("action-reset").click();
|
|
cy.findByTestId("action-result").should("have.text", "no-result");
|
|
});
|
|
|
|
H.queryWritableDB(
|
|
`SELECT team_name, score FROM ${TEST_TABLE} WHERE team_name = 'Data App FC'`,
|
|
).then(({ rows }) => {
|
|
expect(rows).to.have.length(1);
|
|
expect(rows[0].score).to.eq(7);
|
|
});
|
|
});
|
|
|
|
it("surfaces an error when the action fails", () => {
|
|
// `team_name` is unique, so creating a team that already exists fails in the
|
|
// database — a real rejection, not a stubbed one.
|
|
setupActionsApp({ team_name: EXISTING_TEAM, score: 1 });
|
|
|
|
visitAppRoute("actions");
|
|
H.dataAppIframe(APP_DISPLAY_NAME).within(() => {
|
|
cy.findByTestId("action-execute").click();
|
|
|
|
cy.findByTestId("action-error", { timeout: 30000 }).should(
|
|
"have.text",
|
|
"has-error",
|
|
);
|
|
cy.findByTestId("action-result").should("have.text", "no-result");
|
|
cy.findByTestId("action-executing").should("have.text", "idle");
|
|
});
|
|
|
|
H.queryWritableDB(
|
|
`SELECT team_name FROM ${TEST_TABLE} WHERE team_name = '${EXISTING_TEAM}'`,
|
|
).then(({ rows }) => {
|
|
// Nothing was written - the existing team is still the only one.
|
|
expect(rows).to.have.length(1);
|
|
});
|
|
});
|
|
|
|
describe("collection permissions", () => {
|
|
const setupRestrictedApp = (access: CollectionPermission) =>
|
|
createDataAppCollection({ name: RESOURCE_COLLECTION, access }).then(
|
|
(collection) =>
|
|
createDataAppScoreboardAction({ collectionId: collection.id }).then(
|
|
(action) => {
|
|
H.mockDataApp(APP_NAME, {
|
|
displayName: APP_DISPLAY_NAME,
|
|
testEnv: {
|
|
...TEST_ENV,
|
|
actionId: action.id,
|
|
actionParams: { team_name: "Data App FC", score: 7 },
|
|
},
|
|
});
|
|
},
|
|
),
|
|
);
|
|
|
|
const assertNothingWritten = () =>
|
|
H.queryWritableDB(
|
|
`SELECT team_name FROM ${TEST_TABLE} WHERE team_name = 'Data App FC'`,
|
|
).then(({ rows }) => {
|
|
expect(rows).to.have.length(0);
|
|
});
|
|
|
|
it("refuses the action when the user cannot read its collection", () => {
|
|
setupRestrictedApp("none");
|
|
cy.signInAsNormalUser();
|
|
|
|
visitAppRoute("actions");
|
|
H.dataAppIframe(APP_DISPLAY_NAME).within(() => {
|
|
cy.findByTestId("action-execute").click();
|
|
|
|
cy.findByTestId("action-error", { timeout: 30000 }).should(
|
|
"have.text",
|
|
"has-error",
|
|
);
|
|
cy.findByTestId("action-result").should("have.text", "no-result");
|
|
});
|
|
|
|
assertNothingWritten();
|
|
});
|
|
|
|
it("executes the action when the user has view access to its collection", () => {
|
|
setupRestrictedApp("read");
|
|
cy.signInAsNormalUser();
|
|
|
|
visitAppRoute("actions");
|
|
H.dataAppIframe(APP_DISPLAY_NAME).within(() => {
|
|
cy.findByTestId("action-execute").click();
|
|
|
|
cy.findByTestId("action-result", { timeout: 30000 }).should(
|
|
"have.text",
|
|
"has-result",
|
|
);
|
|
cy.findByTestId("action-error").should("have.text", "no-error");
|
|
});
|
|
|
|
H.queryWritableDB(
|
|
`SELECT team_name, score FROM ${TEST_TABLE} WHERE team_name = 'Data App FC'`,
|
|
).then(({ rows }) => {
|
|
expect(rows).to.have.length(1);
|
|
expect(rows[0].score).to.eq(7);
|
|
});
|
|
});
|
|
});
|
|
},
|
|
);
|