From 6676158dfc9bc678501e9ecf9b3a99b20f406148 Mon Sep 17 00:00:00 2001 From: Ryan Laurie <30528226+iethree@users.noreply.github.com> Date: Tue, 14 Nov 2023 23:53:46 -0700 Subject: [PATCH] Quarantine Flaky e2e Tests (#35676) * add special flaky group * tag tests with flakes over 10% * mark more flaky jobs --- .github/actions/build-e2e-matrix/action.yml | 1 + .github/workflows/e2e-tests.yml | 10 +- .../actions/actions-on-dashboards.cy.spec.js | 158 +++---- .../dashboard-cards/click-behavior.cy.spec.js | 242 +++++------ .../dashboard-card-resizing.cy.spec.js | 140 ++++--- .../embedding/embedding-smoketests.cy.spec.js | 150 +++---- .../models/models-metadata.cy.spec.js | 2 +- .../native/native_subquery.cy.spec.js | 34 +- .../search/recently-viewed.cy.spec.js | 4 +- e2e/test/scenarios/onboarding/urls.cy.spec.js | 2 +- .../permissions/sandboxes.cy.spec.js | 386 +++++++++--------- .../sharing/subscriptions.cy.spec.js | 140 ++++--- .../pivot_tables.cy.spec.js | 2 +- 13 files changed, 660 insertions(+), 611 deletions(-) diff --git a/.github/actions/build-e2e-matrix/action.yml b/.github/actions/build-e2e-matrix/action.yml index 9108f991ab1..edb2636f7e1 100644 --- a/.github/actions/build-e2e-matrix/action.yml +++ b/.github/actions/build-e2e-matrix/action.yml @@ -50,6 +50,7 @@ runs: ["visualizations-tabular", {} ], ["oss-subset", { edition: 'oss', context: "special" } ], ["slow", { runner: beefierRunner, context: "special" } ], + ["flaky", { runner: beefierRunner, context: "special" } ], ["mongo", { context: "qa-database" } ], ]; diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index a9670da171a..636c011e82c 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -173,11 +173,19 @@ jobs: --spec './e2e/test/scenarios/**/*.cy.spec.js' \ --browser ${{ steps.cypress-prep.outputs.chrome-path }} + - name: Run Flaky Cypress tests + if: matrix.name == 'flaky' && github.event_name != 'schedule' + run: | + yarn run test-cypress-run \ + --env grepTags="@flaky",grepOmitFiltered=true \ + --spec './e2e/test/scenarios/**/*.cy.spec.js' \ + --browser ${{ steps.cypress-prep.outputs.chrome-path }} + - name: Run EE Cypress tests on ${{ matrix.name }} if: matrix.context == 'folder' && github.event_name != 'schedule' run: | yarn run test-cypress-run \ - --env grepTags="-@slow+-@mongo --@quarantine",grepOmitFiltered=true \ + --env grepTags="-@slow+-@mongo+-@flaky --@quarantine",grepOmitFiltered=true \ --folder ${{ matrix.name }} \ --browser ${{ steps.cypress-prep.outputs.chrome-path }} diff --git a/e2e/test/scenarios/actions/actions-on-dashboards.cy.spec.js b/e2e/test/scenarios/actions/actions-on-dashboards.cy.spec.js index b327224d56b..7898669b3d1 100644 --- a/e2e/test/scenarios/actions/actions-on-dashboards.cy.spec.js +++ b/e2e/test/scenarios/actions/actions-on-dashboards.cy.spec.js @@ -476,101 +476,105 @@ const MODEL_NAME = "Test Action Model"; }); }); - it("can update various data types via implicit actions", () => { - cy.get("@modelId").then(id => { - createImplicitAction({ - kind: "update", - model_id: id, + it( + "can update various data types via implicit actions", + { tags: "@flaky" }, + () => { + cy.get("@modelId").then(id => { + createImplicitAction({ + kind: "update", + model_id: id, + }); }); - }); - createDashboardWithActionButton({ - actionName: "Update", - idFilter: true, - }); + createDashboardWithActionButton({ + actionName: "Update", + idFilter: true, + }); - filterWidget().click(); - addWidgetStringFilter("1"); + filterWidget().click(); + addWidgetStringFilter("1"); - cy.findByRole("button", { name: "Update" }).click(); + cy.findByRole("button", { name: "Update" }).click(); - cy.wait("@prefetchValues"); + cy.wait("@prefetchValues"); - const oldRow = many_data_types_rows[0]; + const oldRow = many_data_types_rows[0]; - modal().within(() => { - changeValue({ - fieldName: "UUID", - fieldType: "text", - oldValue: oldRow.uuid, - newValue: "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a77", - }); + modal().within(() => { + changeValue({ + fieldName: "UUID", + fieldType: "text", + oldValue: oldRow.uuid, + newValue: "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a77", + }); - changeValue({ - fieldName: "Integer", - fieldType: "number", - oldValue: oldRow.integer, - newValue: 123, - }); + changeValue({ + fieldName: "Integer", + fieldType: "number", + oldValue: oldRow.integer, + newValue: 123, + }); - changeValue({ - fieldName: "Float", - fieldType: "number", - oldValue: oldRow.float, - newValue: 2.2, - }); + changeValue({ + fieldName: "Float", + fieldType: "number", + oldValue: oldRow.float, + newValue: 2.2, + }); - cy.findByLabelText("Boolean").should("be.checked").click(); + cy.findByLabelText("Boolean").should("be.checked").click(); - changeValue({ - fieldName: "String", - fieldType: "text", - oldValue: oldRow.string, - newValue: "new string", - }); + changeValue({ + fieldName: "String", + fieldType: "text", + oldValue: oldRow.string, + newValue: "new string", + }); - changeValue({ - fieldName: "Date", - fieldType: "date", - oldValue: oldRow.date, - newValue: "2020-05-01", - }); + changeValue({ + fieldName: "Date", + fieldType: "date", + oldValue: oldRow.date, + newValue: "2020-05-01", + }); - // we can't assert on this value because mysql and postgres seem to - // handle timezones differently 🥴 - cy.findByPlaceholderText("TimestampTZ") - .should("have.attr", "type", "datetime-local") - .clear() - .type("2020-05-01T16:45:00"); + // we can't assert on this value because mysql and postgres seem to + // handle timezones differently 🥴 + cy.findByPlaceholderText("TimestampTZ") + .should("have.attr", "type", "datetime-local") + .clear() + .type("2020-05-01T16:45:00"); - cy.button("Update").click(); - }); + cy.button("Update").click(); + }); - cy.wait("@executeAction"); + cy.wait("@executeAction"); - queryWritableDB( - `SELECT * FROM ${TEST_COLUMNS_TABLE} WHERE id = 1`, - dialect, - ).then(result => { - expect(result.rows.length).to.equal(1); + queryWritableDB( + `SELECT * FROM ${TEST_COLUMNS_TABLE} WHERE id = 1`, + dialect, + ).then(result => { + expect(result.rows.length).to.equal(1); - const row = result.rows[0]; + const row = result.rows[0]; - expect(row).to.have.property( - "uuid", - "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a77", - ); - expect(row).to.have.property("integer", 123); - expect(row).to.have.property("float", 2.2); - expect(row).to.have.property("string", "new string"); - expect(row).to.have.property( - "boolean", - dialect === "mysql" ? 0 : false, - ); - expect(row.date).to.include("2020-05-01"); // js converts this to a full date obj - expect(row.timestampTZ).to.include("2020-05-01"); // we got timezone issues here - }); - }); + expect(row).to.have.property( + "uuid", + "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a77", + ); + expect(row).to.have.property("integer", 123); + expect(row).to.have.property("float", 2.2); + expect(row).to.have.property("string", "new string"); + expect(row).to.have.property( + "boolean", + dialect === "mysql" ? 0 : false, + ); + expect(row.date).to.include("2020-05-01"); // js converts this to a full date obj + expect(row.timestampTZ).to.include("2020-05-01"); // we got timezone issues here + }); + }, + ); it("can insert various data types via implicit actions", () => { cy.get("@modelId").then(id => { diff --git a/e2e/test/scenarios/dashboard-cards/click-behavior.cy.spec.js b/e2e/test/scenarios/dashboard-cards/click-behavior.cy.spec.js index 8c647c8a361..7a0efd546f2 100644 --- a/e2e/test/scenarios/dashboard-cards/click-behavior.cy.spec.js +++ b/e2e/test/scenarios/dashboard-cards/click-behavior.cy.spec.js @@ -925,129 +925,135 @@ describe("scenarios > dashboard > dashboard cards > click behavior", () => { .should("have.text", "Open the drill-through menu"); }); - it("should allow setting dashboard and saved question as custom destination for different columns", () => { - cy.createQuestion(TARGET_QUESTION); - cy.createDashboard( - { - ...TARGET_DASHBOARD, - parameters: [DASHBOARD_FILTER_TEXT, DASHBOARD_FILTER_TIME], - }, - { - wrapId: true, - idAlias: "targetDashboardId", - }, - ); - cy.createQuestionAndDashboard({ questionDetails }).then( - ({ body: card }) => { - visitDashboard(card.dashboard_id); - }, - ); - - editDashboard(); - - getDashboardCard().realHover().icon("click").click(); - - (function addCustomDashboardDestination() { - cy.log("custom destination (dashboard) behavior for 'Count' column"); - - getCountToDashboardMapping().should("not.exist"); - cy.get("aside").findByText(COUNT_COLUMN_NAME).click(); - addDashboardDestination(); - cy.get("aside") - .findByText("Select a dashboard tab") - .should("not.exist"); - cy.get("aside").findByText("No available targets").should("not.exist"); - addTextParameter(); - addTimeParameter(); - cy.get("aside") - .findByRole("textbox") - .type(`Count: {{${COUNT_COLUMN_ID}}}`, { - parseSpecialCharSequences: false, - }); - - cy.icon("chevronleft").click(); - - getCountToDashboardMapping().should("exist"); - getDashboardCard() - .button() - .should("have.text", "1 column has custom behavior"); - })(); - - (function addCustomQuestionDestination() { - cy.log( - "custom destination (question) behavior for 'Created at' column", + it( + "should allow setting dashboard and saved question as custom destination for different columns", + { tags: "@flaky" }, + () => { + cy.createQuestion(TARGET_QUESTION); + cy.createDashboard( + { + ...TARGET_DASHBOARD, + parameters: [DASHBOARD_FILTER_TEXT, DASHBOARD_FILTER_TIME], + }, + { + wrapId: true, + idAlias: "targetDashboardId", + }, + ); + cy.createQuestionAndDashboard({ questionDetails }).then( + ({ body: card }) => { + visitDashboard(card.dashboard_id); + }, ); - getCreatedAtToQuestionMapping().should("not.exist"); - cy.get("aside").findByText(CREATED_AT_COLUMN_NAME).click(); - /** - * TODO: remove the next line when metabase#34845 is fixed - * @see https://github.com/metabase/metabase/issues/34845 - */ - cy.get("aside").findByText("Unknown").click(); - addSavedQuestionDestination(); - addSavedQuestionCreatedAtParameter(); - addSavedQuestionQuantityParameter(); - cy.get("aside") - .findByRole("textbox") - .type(`Created at: {{${CREATED_AT_COLUMN_ID}}}`, { - parseSpecialCharSequences: false, - }); - - cy.icon("chevronleft").click(); - - getCreatedAtToQuestionMapping().should("exist"); - getDashboardCard() - .button() - .should("have.text", "2 columns have custom behavior"); - })(); - - cy.get("aside").button("Done").click(); - saveDashboard(); - - (function testDashboardDestinationClick() { - cy.log("it handles 'Count' column click"); + editDashboard(); + + getDashboardCard().realHover().icon("click").click(); + + (function addCustomDashboardDestination() { + cy.log("custom destination (dashboard) behavior for 'Count' column"); + + getCountToDashboardMapping().should("not.exist"); + cy.get("aside").findByText(COUNT_COLUMN_NAME).click(); + addDashboardDestination(); + cy.get("aside") + .findByText("Select a dashboard tab") + .should("not.exist"); + cy.get("aside") + .findByText("No available targets") + .should("not.exist"); + addTextParameter(); + addTimeParameter(); + cy.get("aside") + .findByRole("textbox") + .type(`Count: {{${COUNT_COLUMN_ID}}}`, { + parseSpecialCharSequences: false, + }); + + cy.icon("chevronleft").click(); + + getCountToDashboardMapping().should("exist"); + getDashboardCard() + .button() + .should("have.text", "1 column has custom behavior"); + })(); + + (function addCustomQuestionDestination() { + cy.log( + "custom destination (question) behavior for 'Created at' column", + ); - getTableCell(COLUMN_INDEX.COUNT) - .should("have.text", `Count: ${POINT_COUNT}`) - .click(); - cy.findAllByTestId("field-set") - .should("have.length", 2) - .should("contain.text", POINT_COUNT) - .should("contain.text", POINT_CREATED_AT_FORMATTED); - cy.get("@targetDashboardId").then(targetDashboardId => { - cy.location().should(({ pathname, search }) => { - expect(pathname).to.equal(`/dashboard/${targetDashboardId}`); - expect(search).to.equal( - `?${DASHBOARD_FILTER_TEXT.slug}=${POINT_COUNT}&${DASHBOARD_FILTER_TIME.slug}=${POINT_CREATED_AT}`, - ); + getCreatedAtToQuestionMapping().should("not.exist"); + cy.get("aside").findByText(CREATED_AT_COLUMN_NAME).click(); + /** + * TODO: remove the next line when metabase#34845 is fixed + * @see https://github.com/metabase/metabase/issues/34845 + */ + cy.get("aside").findByText("Unknown").click(); + addSavedQuestionDestination(); + addSavedQuestionCreatedAtParameter(); + addSavedQuestionQuantityParameter(); + cy.get("aside") + .findByRole("textbox") + .type(`Created at: {{${CREATED_AT_COLUMN_ID}}}`, { + parseSpecialCharSequences: false, + }); + + cy.icon("chevronleft").click(); + + getCreatedAtToQuestionMapping().should("exist"); + getDashboardCard() + .button() + .should("have.text", "2 columns have custom behavior"); + })(); + + cy.get("aside").button("Done").click(); + saveDashboard(); + + (function testDashboardDestinationClick() { + cy.log("it handles 'Count' column click"); + + getTableCell(COLUMN_INDEX.COUNT) + .should("have.text", `Count: ${POINT_COUNT}`) + .click(); + cy.findAllByTestId("field-set") + .should("have.length", 2) + .should("contain.text", POINT_COUNT) + .should("contain.text", POINT_CREATED_AT_FORMATTED); + cy.get("@targetDashboardId").then(targetDashboardId => { + cy.location().should(({ pathname, search }) => { + expect(pathname).to.equal(`/dashboard/${targetDashboardId}`); + expect(search).to.equal( + `?${DASHBOARD_FILTER_TEXT.slug}=${POINT_COUNT}&${DASHBOARD_FILTER_TIME.slug}=${POINT_CREATED_AT}`, + ); + }); }); - }); - })(); - - cy.go("back"); - - (function testQuestionDestinationClick() { - cy.log("it handles 'Created at' column click"); - - getTableCell(COLUMN_INDEX.CREATED_AT) - .should("have.text", `Created at: ${POINT_CREATED_AT_FORMATTED}`) - .click(); - cy.findByTestId("qb-filters-panel") - .should("contain.text", "Created At is August 1–31, 2022") - .should("contain.text", "Quantity is equal to 79"); - cy.location().should(({ hash, pathname }) => { - expect(pathname).to.equal("/question"); - const card = deserializeCardFromUrl(hash); - expect(card.name).to.deep.equal(TARGET_QUESTION.name); - expect(card.display).to.deep.equal(TARGET_QUESTION.display); - expect(card.dataset_query.query).to.deep.equal({ - ...TARGET_QUESTION.query, - filter: ["and", QUERY_FILTER_CREATED_AT, QUERY_FILTER_QUANTITY], + })(); + + cy.go("back"); + + (function testQuestionDestinationClick() { + cy.log("it handles 'Created at' column click"); + + getTableCell(COLUMN_INDEX.CREATED_AT) + .should("have.text", `Created at: ${POINT_CREATED_AT_FORMATTED}`) + .click(); + cy.findByTestId("qb-filters-panel") + .should("contain.text", "Created At is August 1–31, 2022") + .should("contain.text", "Quantity is equal to 79"); + cy.location().should(({ hash, pathname }) => { + expect(pathname).to.equal("/question"); + const card = deserializeCardFromUrl(hash); + expect(card.name).to.deep.equal(TARGET_QUESTION.name); + expect(card.display).to.deep.equal(TARGET_QUESTION.display); + expect(card.dataset_query.query).to.deep.equal({ + ...TARGET_QUESTION.query, + filter: ["and", QUERY_FILTER_CREATED_AT, QUERY_FILTER_QUANTITY], + }); }); - }); - })(); - }); + })(); + }, + ); it("should allow setting dashboard tab with parameter for a column", () => { cy.createQuestion(TARGET_QUESTION); diff --git a/e2e/test/scenarios/dashboard-cards/dashboard-card-resizing.cy.spec.js b/e2e/test/scenarios/dashboard-cards/dashboard-card-resizing.cy.spec.js index a19ac884e2a..6d4a7131039 100644 --- a/e2e/test/scenarios/dashboard-cards/dashboard-card-resizing.cy.spec.js +++ b/e2e/test/scenarios/dashboard-cards/dashboard-card-resizing.cy.spec.js @@ -202,92 +202,100 @@ describe("scenarios > dashboard card resizing", () => { cy.signInAsAdmin(); }); - it("should display all visualization cards with their default sizes", () => { - TEST_QUESTIONS.forEach(question => { - cy.createQuestion(question); - }); - cy.createDashboard().then(({ body: { id: dashId } }) => { - visitDashboard(dashId); - - cy.findByTestId("dashboard-header").within(() => { - cy.findByLabelText("Edit dashboard").click(); - cy.findByLabelText("Add questions").click(); - }); - + it( + "should display all visualization cards with their default sizes", + { tags: "@flaky" }, + () => { TEST_QUESTIONS.forEach(question => { - cy.findByLabelText(question.name).click(); + cy.createQuestion(question); }); + cy.createDashboard().then(({ body: { id: dashId } }) => { + visitDashboard(dashId); - saveDashboard(); + cy.findByTestId("dashboard-header").within(() => { + cy.findByLabelText("Edit dashboard").click(); + cy.findByLabelText("Add questions").click(); + }); - cy.request("GET", `/api/dashboard/${dashId}`).then(({ body }) => { - body.dashcards.forEach(({ card, size_x, size_y }) => { - const { height, width } = getDefaultSize(card.display); - expect(size_x).to.equal(width); - expect(size_y).to.equal(height); + TEST_QUESTIONS.forEach(question => { + cy.findByLabelText(question.name).click(); }); - }); - }); - }); - it(`should not allow cards to be resized smaller than min height`, () => { - const cardIds = []; - TEST_QUESTIONS.forEach(question => { - cy.createQuestion(question).then(({ body: { id } }) => { - cardIds.push(id); - }); - }); - cy.createDashboard().then(({ body: { id: dashId } }) => { - cy.request("PUT", `/api/dashboard/${dashId}`, { - dashcards: cardIds.map((cardId, index) => ({ - id: index, - card_id: cardId, - row: index * 2, - col: 0, - size_x: 2, - size_y: 2, - })), - }); - visitDashboard(dashId); - editDashboard(); - - cy.request("GET", `/api/dashboard/${dashId}`).then(({ body }) => { - const dashcards = body.dashcards; - dashcards.forEach(({ card }) => { - const dashcard = cy.contains(".DashCard", card.name); - resizeDashboardCard({ - card: dashcard, - x: getDefaultSize(card.display).width * 100, - y: getDefaultSize(card.display).height * 100, + saveDashboard(); + + cy.request("GET", `/api/dashboard/${dashId}`).then(({ body }) => { + body.dashcards.forEach(({ card, size_x, size_y }) => { + const { height, width } = getDefaultSize(card.display); + expect(size_x).to.equal(width); + expect(size_y).to.equal(height); }); }); + }); + }, + ); - saveDashboard(); + it( + `should not allow cards to be resized smaller than min height`, + { tags: "@flaky" }, + () => { + const cardIds = []; + TEST_QUESTIONS.forEach(question => { + cy.createQuestion(question).then(({ body: { id } }) => { + cardIds.push(id); + }); + }); + cy.createDashboard().then(({ body: { id: dashId } }) => { + cy.request("PUT", `/api/dashboard/${dashId}`, { + dashcards: cardIds.map((cardId, index) => ({ + id: index, + card_id: cardId, + row: index * 2, + col: 0, + size_x: 2, + size_y: 2, + })), + }); + visitDashboard(dashId); editDashboard(); - dashcards.forEach(({ card }) => { - const dashcard = cy.contains(".DashCard", card.name); - dashcard.within(() => { + cy.request("GET", `/api/dashboard/${dashId}`).then(({ body }) => { + const dashcards = body.dashcards; + dashcards.forEach(({ card }) => { + const dashcard = cy.contains(".DashCard", card.name); resizeDashboardCard({ card: dashcard, - x: -getDefaultSize(card.display).width * 200, - y: -getDefaultSize(card.display).height * 200, + x: getDefaultSize(card.display).width * 100, + y: getDefaultSize(card.display).height * 100, }); }); - }); - saveDashboard(); + saveDashboard(); + editDashboard(); + + dashcards.forEach(({ card }) => { + const dashcard = cy.contains(".DashCard", card.name); + dashcard.within(() => { + resizeDashboardCard({ + card: dashcard, + x: -getDefaultSize(card.display).width * 200, + y: -getDefaultSize(card.display).height * 200, + }); + }); + }); - cy.request("GET", `/api/dashboard/${dashId}`).then(({ body }) => { - body.dashcards.forEach(({ card, size_x, size_y }) => { - const { height, width } = getMinSize(card.display); - expect(size_x).to.equal(width); - expect(size_y).to.equal(height); + saveDashboard(); + + cy.request("GET", `/api/dashboard/${dashId}`).then(({ body }) => { + body.dashcards.forEach(({ card, size_x, size_y }) => { + const { height, width } = getMinSize(card.display); + expect(size_x).to.equal(width); + expect(size_y).to.equal(height); + }); }); }); }); - }); - }); + }, + ); describe("metabase#31701 - preventing link dashboard card overflows", () => { viewports.forEach(([width, height]) => { diff --git a/e2e/test/scenarios/embedding/embedding-smoketests.cy.spec.js b/e2e/test/scenarios/embedding/embedding-smoketests.cy.spec.js index 2d30a89255f..50e63a842c5 100644 --- a/e2e/test/scenarios/embedding/embedding-smoketests.cy.spec.js +++ b/e2e/test/scenarios/embedding/embedding-smoketests.cy.spec.js @@ -214,95 +214,99 @@ describe("scenarios > embedding > smoke tests", { tags: "@OSS" }, () => { dashboard: ORDERS_DASHBOARD_ID, }; ["question", "dashboard"].forEach(object => { - it(`should be able to publish/embed and then unpublish a ${object} without filters`, () => { - const embeddableObject = object === "question" ? "card" : "dashboard"; - const objectName = - object === "question" ? "Orders" : "Orders in a dashboard"; - - cy.intercept("PUT", `/api/${embeddableObject}/${ids[object]}`).as( - "embedObject", - ); - cy.intercept("GET", `/api/${embeddableObject}/embeddable`).as( - "currentlyEmbeddedObject", - ); + it( + `should be able to publish/embed and then unpublish a ${object} without filters`, + { tags: "@flaky" }, + () => { + const embeddableObject = object === "question" ? "card" : "dashboard"; + const objectName = + object === "question" ? "Orders" : "Orders in a dashboard"; + + cy.intercept("PUT", `/api/${embeddableObject}/${ids[object]}`).as( + "embedObject", + ); + cy.intercept("GET", `/api/${embeddableObject}/embeddable`).as( + "currentlyEmbeddedObject", + ); - visitAndEnableSharing(object); + visitAndEnableSharing(object); - cy.findByTestId("embedding-settings").within(() => { - cy.findByRole("heading", { name: "Style" }); - cy.findByRole("heading", { name: "Appearance" }); - cy.findByRole("heading", { name: "Font" }).should("not.exist"); - cy.findByRole("heading", { name: "Download data" }).should( - "not.exist", - ); + cy.findByTestId("embedding-settings").within(() => { + cy.findByRole("heading", { name: "Style" }); + cy.findByRole("heading", { name: "Appearance" }); + cy.findByRole("heading", { name: "Font" }).should("not.exist"); + cy.findByRole("heading", { name: "Download data" }).should( + "not.exist", + ); - cy.findByText("Parameters"); - cy.findByText( - /This (question|dashboard) doesn't have any parameters to configure yet./, - ); - cy.findByText("Parameters"); - }); + cy.findByText("Parameters"); + cy.findByText( + /This (question|dashboard) doesn't have any parameters to configure yet./, + ); + cy.findByText("Parameters"); + }); - cy.findByTestId("embedding-preview").within(() => { - cy.findByText( - /You will need to publish this (question|dashboard) before you can embed it in another application./, - ); + cy.findByTestId("embedding-preview").within(() => { + cy.findByText( + /You will need to publish this (question|dashboard) before you can embed it in another application./, + ); - cy.button("Publish").click(); - cy.wait("@embedObject"); - }); + cy.button("Publish").click(); + cy.wait("@embedObject"); + }); - visitIframe(); + visitIframe(); - cy.findByTestId("embed-frame").within(() => { - cy.findByRole("heading", { name: objectName }); - cy.get(".cellData").contains("37.65"); - }); + cy.findByTestId("embed-frame").within(() => { + cy.findByRole("heading", { name: objectName }); + cy.get(".cellData").contains("37.65"); + }); - cy.findByRole("contentinfo").within(() => { - cy.findByRole("link") - .should("have.text", "Powered by Metabase") - .and("have.attr", "href") - .and("eq", "https://metabase.com/"); - }); + cy.findByRole("contentinfo").within(() => { + cy.findByRole("link") + .should("have.text", "Powered by Metabase") + .and("have.attr", "href") + .and("eq", "https://metabase.com/"); + }); - cy.log( - `Make sure the ${object} shows up in the standalone embeds page`, - ); - cy.signInAsAdmin(); - cy.visit(standalonePath); - cy.wait("@currentlyEmbeddedObject"); + cy.log( + `Make sure the ${object} shows up in the standalone embeds page`, + ); + cy.signInAsAdmin(); + cy.visit(standalonePath); + cy.wait("@currentlyEmbeddedObject"); - const sectionTestId = new RegExp(`-embedded-${object}s-setting`); + const sectionTestId = new RegExp(`-embedded-${object}s-setting`); - cy.findByTestId(sectionTestId) - .find("tbody tr") - .should("have.length", 1) - .and("contain", objectName); + cy.findByTestId(sectionTestId) + .find("tbody tr") + .should("have.length", 1) + .and("contain", objectName); - cy.log(`Unpublish ${object}`); - visitAndEnableSharing(object); + cy.log(`Unpublish ${object}`); + visitAndEnableSharing(object); - cy.findByTestId("embedding-settings").within(() => { - cy.findByRole("heading", { name: "Danger zone" }); - cy.findByText(`This will disable embedding for this ${object}.`); - cy.button("Unpublish").click(); - cy.wait("@embedObject"); - }); + cy.findByTestId("embedding-settings").within(() => { + cy.findByRole("heading", { name: "Danger zone" }); + cy.findByText(`This will disable embedding for this ${object}.`); + cy.button("Unpublish").click(); + cy.wait("@embedObject"); + }); - visitIframe(); - cy.findByTestId("embed-frame").findByText( - "Embedding is not enabled for this object.", - ); + visitIframe(); + cy.findByTestId("embed-frame").findByText( + "Embedding is not enabled for this object.", + ); - cy.signInAsAdmin(); - cy.visit(standalonePath); - cy.wait("@currentlyEmbeddedObject"); + cy.signInAsAdmin(); + cy.visit(standalonePath); + cy.wait("@currentlyEmbeddedObject"); - mainPage() - .findAllByText(/No (questions|dashboards) have been embedded yet./) - .should("have.length", 2); - }); + mainPage() + .findAllByText(/No (questions|dashboards) have been embedded yet./) + .should("have.length", 2); + }, + ); }); it("should regenerate embedding token and invalidate previous embed url", () => { diff --git a/e2e/test/scenarios/models/models-metadata.cy.spec.js b/e2e/test/scenarios/models/models-metadata.cy.spec.js index bf74e010cf9..47d768e4342 100644 --- a/e2e/test/scenarios/models/models-metadata.cy.spec.js +++ b/e2e/test/scenarios/models/models-metadata.cy.spec.js @@ -192,7 +192,7 @@ describe("scenarios > models metadata", () => { // Check that the relation is automatically suggested in the notebook once it is implemented. }); - it("should keep metadata in sync with the query", () => { + it("should keep metadata in sync with the query", { tags: "@flaky" }, () => { cy.createNativeQuestion( { name: "Native Model", diff --git a/e2e/test/scenarios/native/native_subquery.cy.spec.js b/e2e/test/scenarios/native/native_subquery.cy.spec.js index 5286c938f53..b4d722e35e2 100644 --- a/e2e/test/scenarios/native/native_subquery.cy.spec.js +++ b/e2e/test/scenarios/native/native_subquery.cy.spec.js @@ -308,23 +308,27 @@ describe("scenarios > question > native subquery", () => { ); }); - it("should be able to reference a saved native question that ends with a semicolon `;` (metabase#28218)", () => { - const questionDetails = { - name: "28218", - native: { query: "select 1;" }, // semicolon is important here - }; + it( + "should be able to reference a saved native question that ends with a semicolon `;` (metabase#28218)", + { tags: "@flaky" }, + () => { + const questionDetails = { + name: "28218", + native: { query: "select 1;" }, // semicolon is important here + }; - cy.createNativeQuestion(questionDetails).then( - ({ body: { id: baseQuestionId } }) => { - const tagID = `#${baseQuestionId}`; + cy.createNativeQuestion(questionDetails).then( + ({ body: { id: baseQuestionId } }) => { + const tagID = `#${baseQuestionId}`; - startNewNativeQuestion(); - SQLFilter.enterParameterizedQuery(`SELECT * FROM {{${tagID}`); + startNewNativeQuestion(); + SQLFilter.enterParameterizedQuery(`SELECT * FROM {{${tagID}`); - runNativeQuery(); + runNativeQuery(); - cy.get(".cellData").should("contain", "1"); - }, - ); - }); + cy.get(".cellData").should("contain", "1"); + }, + ); + }, + ); }); diff --git a/e2e/test/scenarios/onboarding/search/recently-viewed.cy.spec.js b/e2e/test/scenarios/onboarding/search/recently-viewed.cy.spec.js index 4e22e2deec6..7454a2e4a92 100644 --- a/e2e/test/scenarios/onboarding/search/recently-viewed.cy.spec.js +++ b/e2e/test/scenarios/onboarding/search/recently-viewed.cy.spec.js @@ -39,13 +39,13 @@ describe("search > recently viewed", () => { cy.findByTestId("loading-spinner").should("not.exist"); }); - it("shows list of recently viewed items", () => { + it("shows list of recently viewed items", { tags: "@flaky" }, () => { assertRecentlyViewedItem(0, "Orders in a dashboard", "Dashboard"); assertRecentlyViewedItem(1, "Orders", "Question"); assertRecentlyViewedItem(2, "People", "Table"); }); - it("allows to select an item from keyboard", () => { + it("allows to select an item from keyboard", { tags: "@flaky" }, () => { // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage cy.findByText("Recently viewed"); cy.get("body").trigger("keydown", { key: "ArrowDown" }); diff --git a/e2e/test/scenarios/onboarding/urls.cy.spec.js b/e2e/test/scenarios/onboarding/urls.cy.spec.js index 14513c0c292..3c2c7f8f5bc 100644 --- a/e2e/test/scenarios/onboarding/urls.cy.spec.js +++ b/e2e/test/scenarios/onboarding/urls.cy.spec.js @@ -71,7 +71,7 @@ describe("URLs", () => { }); }); - describe("collections", () => { + describe("collections", { tags: "@flaky" }, () => { it("should slugify collection name", () => { cy.visit("/collection/root"); // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage diff --git a/e2e/test/scenarios/permissions/sandboxes.cy.spec.js b/e2e/test/scenarios/permissions/sandboxes.cy.spec.js index 288c2663d12..81b457a8259 100644 --- a/e2e/test/scenarios/permissions/sandboxes.cy.spec.js +++ b/e2e/test/scenarios/permissions/sandboxes.cy.spec.js @@ -444,219 +444,227 @@ describeEE("formatting > sandboxes", () => { cy.findByText("97.44"); // Subtotal for order #10 }); - describe("with display values remapped to use a foreign key", () => { - beforeEach(() => { - cy.log("Remap Product ID's display value to `title`"); - remapDisplayValueToFK({ - display_value: ORDERS.PRODUCT_ID, - name: "Product ID", - fk: PRODUCTS.TITLE, - }); - }); - - /** - * There isn't an exact issue that this test reproduces, but it is basically a version of (metabase-enterprise#520) - * that uses a query builder instead of SQL based questions. - */ - it("should be able to sandbox using query builder saved questions", () => { - cy.log("Create 'Orders'-based question using QB"); - cy.createQuestion({ - name: "520_Orders", - query: { - "source-table": ORDERS_ID, - filter: [">", ["field", ORDERS.TOTAL, null], 10], - }, - }).then(({ body: { id: CARD_ID } }) => { - cy.sandboxTable({ - table_id: ORDERS_ID, - card_id: CARD_ID, - attribute_remappings: { - attr_uid: ["dimension", ["field", ORDERS.USER_ID, null]], - }, + describe( + "with display values remapped to use a foreign key", + { tags: "@flaky" }, + () => { + beforeEach(() => { + cy.log("Remap Product ID's display value to `title`"); + remapDisplayValueToFK({ + display_value: ORDERS.PRODUCT_ID, + name: "Product ID", + fk: PRODUCTS.TITLE, }); }); - cy.log("Create 'Products'-based question using QB"); - cy.createQuestion({ - name: "520_Products", - query: { - "source-table": PRODUCTS_ID, - filter: [">", ["field", PRODUCTS.PRICE, null], 10], - }, - }).then(({ body: { id: CARD_ID } }) => { - cy.sandboxTable({ - table_id: PRODUCTS_ID, - card_id: CARD_ID, - attribute_remappings: { - attr_cat: ["dimension", ["field", PRODUCTS.CATEGORY, null]], - }, - }); - }); + /** + * There isn't an exact issue that this test reproduces, but it is basically a version of (metabase-enterprise#520) + * that uses a query builder instead of SQL based questions. + */ + it( + "should be able to sandbox using query builder saved questions", + { tags: "@flaky" }, + () => { + cy.log("Create 'Orders'-based question using QB"); + cy.createQuestion({ + name: "520_Orders", + query: { + "source-table": ORDERS_ID, + filter: [">", ["field", ORDERS.TOTAL, null], 10], + }, + }).then(({ body: { id: CARD_ID } }) => { + cy.sandboxTable({ + table_id: ORDERS_ID, + card_id: CARD_ID, + attribute_remappings: { + attr_uid: ["dimension", ["field", ORDERS.USER_ID, null]], + }, + }); + }); - cy.signOut(); - cy.signInAsSandboxedUser(); + cy.log("Create 'Products'-based question using QB"); + cy.createQuestion({ + name: "520_Products", + query: { + "source-table": PRODUCTS_ID, + filter: [">", ["field", PRODUCTS.PRICE, null], 10], + }, + }).then(({ body: { id: CARD_ID } }) => { + cy.sandboxTable({ + table_id: PRODUCTS_ID, + card_id: CARD_ID, + attribute_remappings: { + attr_cat: ["dimension", ["field", PRODUCTS.CATEGORY, null]], + }, + }); + }); - openOrdersTable({ - callback: xhr => expect(xhr.response.body.error).not.to.exist, - }); + cy.signOut(); + cy.signInAsSandboxedUser(); - cy.get(".cellData").contains("Awesome Concrete Shoes").click(); - // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage - cy.findByText(/View details/i).click(); + openOrdersTable({ + callback: xhr => expect(xhr.response.body.error).not.to.exist, + }); - cy.log( - "It should show object details instead of filtering by this Product ID", + cy.get(".cellData").contains("Awesome Concrete Shoes").click(); + // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage + cy.findByText(/View details/i).click(); + + cy.log( + "It should show object details instead of filtering by this Product ID", + ); + cy.findByTestId("object-detail"); + cy.findAllByText("McClure-Lockman"); + }, ); - cy.findByTestId("object-detail"); - cy.findAllByText("McClure-Lockman"); - }); - /** - * This issue (metabase-enterprise#520) has a peculiar quirk: - * - It works ONLY if SQL question is first run (`result_metadata` builds), and then the question is saved. - * - In a real-world scenario it is quite possible for an admin to save that SQL question without running it first. This fails! - * (more info: https://github.com/metabase/metabase-enterprise/issues/520#issuecomment-772528159) - * - * That's why this test has 2 versions that reflect both scenarios. We'll call them "normal" and "workaround". - * Until the underlying issue is fixed, "normal" scenario will be skipped. - * - * Related issues: metabase#10474, metabase#14629 - */ - - // skipping the workaround test because the function `runAndSaveQuestion` - // relies on the existence of a save button on a saved question that is not dirty - // which is a bug fixed in ssue metabase#14302 - ["normal" /* , "workaround" */].forEach(test => { - it(`${test.toUpperCase()} version:\n advanced sandboxing should not ignore data model features like object detail of FK (metabase-enterprise#520)`, () => { - cy.intercept("POST", "/api/card/*/query").as("cardQuery"); - cy.intercept("PUT", "/api/card/*").as("questionUpdate"); - - cy.createNativeQuestion({ - name: "EE_520_Q1", - native: { - query: - "SELECT * FROM ORDERS WHERE USER_ID={{sandbox}} AND TOTAL > 10", - "template-tags": { - sandbox: { - "display-name": "Sandbox", - id: "1115dc4f-6b9d-812e-7f72-b87ab885c88a", - name: "sandbox", - type: "number", + /** + * This issue (metabase-enterprise#520) has a peculiar quirk: + * - It works ONLY if SQL question is first run (`result_metadata` builds), and then the question is saved. + * - In a real-world scenario it is quite possible for an admin to save that SQL question without running it first. This fails! + * (more info: https://github.com/metabase/metabase-enterprise/issues/520#issuecomment-772528159) + * + * That's why this test has 2 versions that reflect both scenarios. We'll call them "normal" and "workaround". + * Until the underlying issue is fixed, "normal" scenario will be skipped. + * + * Related issues: metabase#10474, metabase#14629 + */ + + // skipping the workaround test because the function `runAndSaveQuestion` + // relies on the existence of a save button on a saved question that is not dirty + // which is a bug fixed in ssue metabase#14302 + ["normal" /* , "workaround" */].forEach(test => { + it(`${test.toUpperCase()} version:\n advanced sandboxing should not ignore data model features like object detail of FK (metabase-enterprise#520)`, () => { + cy.intercept("POST", "/api/card/*/query").as("cardQuery"); + cy.intercept("PUT", "/api/card/*").as("questionUpdate"); + + cy.createNativeQuestion({ + name: "EE_520_Q1", + native: { + query: + "SELECT * FROM ORDERS WHERE USER_ID={{sandbox}} AND TOTAL > 10", + "template-tags": { + sandbox: { + "display-name": "Sandbox", + id: "1115dc4f-6b9d-812e-7f72-b87ab885c88a", + name: "sandbox", + type: "number", + }, }, }, - }, - }).then(({ body: { id: CARD_ID } }) => { - test === "workaround" - ? runAndSaveQuestion({ question: CARD_ID, sandboxValue: "1" }) - : null; - - cy.sandboxTable({ - table_id: ORDERS_ID, - card_id: CARD_ID, - attribute_remappings: { - attr_uid: ["variable", ["template-tag", "sandbox"]], - }, + }).then(({ body: { id: CARD_ID } }) => { + test === "workaround" + ? runAndSaveQuestion({ question: CARD_ID, sandboxValue: "1" }) + : null; + + cy.sandboxTable({ + table_id: ORDERS_ID, + card_id: CARD_ID, + attribute_remappings: { + attr_uid: ["variable", ["template-tag", "sandbox"]], + }, + }); }); - }); - cy.createNativeQuestion({ - name: "EE_520_Q2", - native: { - query: - "SELECT * FROM PRODUCTS WHERE CATEGORY={{sandbox}} AND PRICE > 10", - "template-tags": { - sandbox: { - "display-name": "Sandbox", - id: "3d69ba99-7076-2252-30bd-0bb8810ba895", - name: "sandbox", - type: "text", + cy.createNativeQuestion({ + name: "EE_520_Q2", + native: { + query: + "SELECT * FROM PRODUCTS WHERE CATEGORY={{sandbox}} AND PRICE > 10", + "template-tags": { + sandbox: { + "display-name": "Sandbox", + id: "3d69ba99-7076-2252-30bd-0bb8810ba895", + name: "sandbox", + type: "text", + }, }, }, + }).then(({ body: { id: CARD_ID } }) => { + test === "workaround" + ? runAndSaveQuestion({ + question: CARD_ID, + sandboxValue: "Widget", + }) + : null; + + cy.sandboxTable({ + table_id: PRODUCTS_ID, + card_id: CARD_ID, + attribute_remappings: { + attr_cat: ["variable", ["template-tag", "sandbox"]], + }, + }); + }); + + cy.signOut(); + cy.signInAsSandboxedUser(); + + openOrdersTable(); + + cy.log("Reported failing on v1.36.x"); + + cy.log( + "It should show remapped Display Values instead of Product ID", + ); + cy.get(".cellData").contains("Awesome Concrete Shoes").click(); + // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage + cy.findByText(/View details/i).click(); + + cy.log( + "It should show object details instead of filtering by this Product ID", + ); + // The name of this Vendor is visible in "details" only + cy.findByTestId("object-detail"); + cy.findAllByText("McClure-Lockman"); + + /** + * Helper function related to this test only! + */ + function runAndSaveQuestion({ question, sandboxValue } = {}) { + // Run the question + cy.visit(`/question/${question}?sandbox=${sandboxValue}`); + // Wait for results + cy.wait("@cardQuery"); + // Save the question + cy.findByText("Save").click(); + modal().within(() => { + cy.button("Save").click(); + }); + // Wait for an update so the other queries don't accidentally cancel it + cy.wait("@questionUpdate"); + } + }); + }); + + it("simple sandboxing should work (metabase#14629)", () => { + cy.sandboxTable({ + table_id: ORDERS_ID, + attribute_remappings: { + attr_uid: ["dimension", ["field", ORDERS.USER_ID, null]], }, - }).then(({ body: { id: CARD_ID } }) => { - test === "workaround" - ? runAndSaveQuestion({ - question: CARD_ID, - sandboxValue: "Widget", - }) - : null; - - cy.sandboxTable({ - table_id: PRODUCTS_ID, - card_id: CARD_ID, - attribute_remappings: { - attr_cat: ["variable", ["template-tag", "sandbox"]], + }); + + cy.updatePermissionsSchemas({ + schemas: { + PUBLIC: { + [PRODUCTS_ID]: "all", }, - }); + }, }); cy.signOut(); cy.signInAsSandboxedUser(); + openOrdersTable({ + callback: xhr => expect(xhr.response.body.error).not.to.exist, + }); - openOrdersTable(); - - cy.log("Reported failing on v1.36.x"); - - cy.log( - "It should show remapped Display Values instead of Product ID", - ); - cy.get(".cellData").contains("Awesome Concrete Shoes").click(); + // Title of the first order for User ID = 1 // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage - cy.findByText(/View details/i).click(); - - cy.log( - "It should show object details instead of filtering by this Product ID", - ); - // The name of this Vendor is visible in "details" only - cy.findByTestId("object-detail"); - cy.findAllByText("McClure-Lockman"); - - /** - * Helper function related to this test only! - */ - function runAndSaveQuestion({ question, sandboxValue } = {}) { - // Run the question - cy.visit(`/question/${question}?sandbox=${sandboxValue}`); - // Wait for results - cy.wait("@cardQuery"); - // Save the question - cy.findByText("Save").click(); - modal().within(() => { - cy.button("Save").click(); - }); - // Wait for an update so the other queries don't accidentally cancel it - cy.wait("@questionUpdate"); - } + cy.findByText("Awesome Concrete Shoes"); }); - }); - - it("simple sandboxing should work (metabase#14629)", () => { - cy.sandboxTable({ - table_id: ORDERS_ID, - attribute_remappings: { - attr_uid: ["dimension", ["field", ORDERS.USER_ID, null]], - }, - }); - - cy.updatePermissionsSchemas({ - schemas: { - PUBLIC: { - [PRODUCTS_ID]: "all", - }, - }, - }); - - cy.signOut(); - cy.signInAsSandboxedUser(); - openOrdersTable({ - callback: xhr => expect(xhr.response.body.error).not.to.exist, - }); - - // Title of the first order for User ID = 1 - // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage - cy.findByText("Awesome Concrete Shoes"); - }); - }); + }, + ); ["remapped", "default"].forEach(test => { it(`${test.toUpperCase()} version:\n should work on questions with joins, with sandboxed target table, where target fields cannot be filtered (metabase#13642)`, () => { diff --git a/e2e/test/scenarios/sharing/subscriptions.cy.spec.js b/e2e/test/scenarios/sharing/subscriptions.cy.spec.js index 18037cc7990..aeee325858e 100644 --- a/e2e/test/scenarios/sharing/subscriptions.cy.spec.js +++ b/e2e/test/scenarios/sharing/subscriptions.cy.spec.js @@ -196,99 +196,105 @@ describe("scenarios > dashboard > subscriptions", () => { }); }); - describe("let non-users unsubscribe from subscriptions", () => { - it("should allow non-user to unsubscribe from subscription", () => { - const nonUserEmail = "non-user@example.com"; - const dashboardName = "Orders in a dashboard"; + describe( + "let non-users unsubscribe from subscriptions", + { tags: "@flaky" }, + () => { + it("should allow non-user to unsubscribe from subscription", () => { + const nonUserEmail = "non-user@example.com"; + const dashboardName = "Orders in a dashboard"; - visitDashboard(ORDERS_DASHBOARD_ID); + visitDashboard(ORDERS_DASHBOARD_ID); - setupSubscriptionWithRecipient(nonUserEmail); + setupSubscriptionWithRecipient(nonUserEmail); - emailSubscriptionRecipients(); + emailSubscriptionRecipients(); - openEmailPage(dashboardName).then(() => { - cy.intercept("/api/session/pulse/unsubscribe").as("unsubscribe"); - cy.findByText("Unsubscribe").click(); - cy.wait("@unsubscribe"); - cy.contains( - `You've unsubscribed ${nonUserEmail} from the "${dashboardName}" alert.`, - ).should("exist"); + openEmailPage(dashboardName).then(() => { + cy.intercept("/api/session/pulse/unsubscribe").as("unsubscribe"); + cy.findByText("Unsubscribe").click(); + cy.wait("@unsubscribe"); + cy.contains( + `You've unsubscribed ${nonUserEmail} from the "${dashboardName}" alert.`, + ).should("exist"); + }); + + openDashboardSubscriptions(); + openPulseSubscription(); + + sidebar().findByText(nonUserEmail).should("not.exist"); }); - openDashboardSubscriptions(); - openPulseSubscription(); + it("should allow non-user to undo-unsubscribe from subscription", () => { + const nonUserEmail = "non-user@example.com"; + const dashboardName = "Orders in a dashboard"; + visitDashboard(ORDERS_DASHBOARD_ID); - sidebar().findByText(nonUserEmail).should("not.exist"); - }); + setupSubscriptionWithRecipient(nonUserEmail); - it("should allow non-user to undo-unsubscribe from subscription", () => { - const nonUserEmail = "non-user@example.com"; - const dashboardName = "Orders in a dashboard"; - visitDashboard(ORDERS_DASHBOARD_ID); + emailSubscriptionRecipients(); - setupSubscriptionWithRecipient(nonUserEmail); + openEmailPage(dashboardName).then(() => { + cy.intercept("/api/session/pulse/unsubscribe").as("unsubscribe"); + cy.intercept("/api/session/pulse/unsubscribe/undo").as( + "resubscribe", + ); - emailSubscriptionRecipients(); + cy.findByText("Unsubscribe").click(); + cy.wait("@unsubscribe"); - openEmailPage(dashboardName).then(() => { - cy.intercept("/api/session/pulse/unsubscribe").as("unsubscribe"); - cy.intercept("/api/session/pulse/unsubscribe/undo").as("resubscribe"); + cy.contains( + `You've unsubscribed ${nonUserEmail} from the "${dashboardName}" alert.`, + ).should("exist"); - cy.findByText("Unsubscribe").click(); - cy.wait("@unsubscribe"); + cy.findByText("Undo").click(); + cy.wait("@resubscribe"); - cy.contains( - `You've unsubscribed ${nonUserEmail} from the "${dashboardName}" alert.`, - ).should("exist"); + cy.contains( + `Okay, ${nonUserEmail} is subscribed to the "${dashboardName}" alert again.`, + ).should("exist"); + }); - cy.findByText("Undo").click(); - cy.wait("@resubscribe"); + openDashboardSubscriptions(); + openPulseSubscription(); - cy.contains( - `Okay, ${nonUserEmail} is subscribed to the "${dashboardName}" alert again.`, - ).should("exist"); + sidebar().findByText(nonUserEmail).should("exist"); }); - openDashboardSubscriptions(); - openPulseSubscription(); + it("should show 404 page when missing required parameters", () => { + const nonUserEmail = "non-user@example.com"; - sidebar().findByText(nonUserEmail).should("exist"); - }); + const params = { + hash: "459a8e9f8d9e", + email: nonUserEmail, + }; // missing pulse-id - it("should show 404 page when missing required parameters", () => { - const nonUserEmail = "non-user@example.com"; + cy.visit({ + url: `/unsubscribe`, + qs: params, + }); - const params = { - hash: "459a8e9f8d9e", - email: nonUserEmail, - }; // missing pulse-id - - cy.visit({ - url: `/unsubscribe`, - qs: params, + cy.findByLabelText("error page").should("exist"); }); - cy.findByLabelText("error page").should("exist"); - }); + it("should show error message when server responds with an error", () => { + const nonUserEmail = "non-user@example.com"; - it("should show error message when server responds with an error", () => { - const nonUserEmail = "non-user@example.com"; + const params = { + hash: "459a8e9f8d9e", + email: nonUserEmail, + "pulse-id": "f", // invalid pulse-id + }; - const params = { - hash: "459a8e9f8d9e", - email: nonUserEmail, - "pulse-id": "f", // invalid pulse-id - }; + cy.visit({ + url: `/unsubscribe`, + qs: params, + }); - cy.visit({ - url: `/unsubscribe`, - qs: params, + cy.findByLabelText("error message").should("exist"); }); - - cy.findByLabelText("error message").should("exist"); - }); - }); + }, + ); it("should persist attachments for dashboard subscriptions (metabase#14117)", () => { assignRecipient(); diff --git a/e2e/test/scenarios/visualizations-tabular/pivot_tables.cy.spec.js b/e2e/test/scenarios/visualizations-tabular/pivot_tables.cy.spec.js index 75ba69e7530..de9ac22d5b2 100644 --- a/e2e/test/scenarios/visualizations-tabular/pivot_tables.cy.spec.js +++ b/e2e/test/scenarios/visualizations-tabular/pivot_tables.cy.spec.js @@ -462,7 +462,7 @@ describe("scenarios > visualizations > pivot tables", { tags: "@slow" }, () => { cy.findByText(/Sort order/).should("not.be.visible"); }); - it("should allow sorting fields", () => { + it("should allow sorting fields", { tags: "@flaky" }, () => { // Pivot by a single column with many values (100 bins). // Having many values hides values that are sorted to the end. // This lets us assert on presence of a certain value. -- GitLab