From 1f3fc980380987bf010a2312a65bf5b7f28ebe39 Mon Sep 17 00:00:00 2001 From: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com> Date: Mon, 1 Nov 2021 13:38:36 +0100 Subject: [PATCH] Abstract e2e downloads helpers (#18746) * Expose the e2e downloads helper function * Apply the new e2e downloads helper to the #18382 repro * Apply the new e2e downloads helper to the #18440 repro * Update the helper so it applies both for saved and unsaved questions * Add additional helper options * Redirect to a non-existing page * Reafactor `downloads` spec * Extract repro for #10803 --- frontend/test/__support__/e2e/cypress.js | 1 + .../e2e/helpers/e2e-downloads-helpers.js | 77 +++++++++ .../scenarios/downloads/downloads.cy.spec.js | 162 ++---------------- .../10803-timestamp-formatting.cy.spec.js | 69 ++++++++ ...19-temporal-units-not-formatted.cy.spec.js | 91 ++++------ ...-syntax-missing-renamed-columns.cy.spec.js | 71 +++----- ...-remapped-display-value-dropped.cy.spec.js | 98 ++++------- 7 files changed, 252 insertions(+), 317 deletions(-) create mode 100644 frontend/test/__support__/e2e/helpers/e2e-downloads-helpers.js create mode 100644 frontend/test/metabase/scenarios/downloads/reproductions/10803-timestamp-formatting.cy.spec.js diff --git a/frontend/test/__support__/e2e/cypress.js b/frontend/test/__support__/e2e/cypress.js index ddcd54e69b2..fd196cba40a 100644 --- a/frontend/test/__support__/e2e/cypress.js +++ b/frontend/test/__support__/e2e/cypress.js @@ -26,5 +26,6 @@ export * from "./helpers/e2e-email-helpers"; export * from "./helpers/e2e-slack-helpers"; export * from "./helpers/e2e-custom-column-helpers"; export * from "./helpers/e2e-dimension-list-helpers"; +export * from "./helpers/e2e-downloads-helpers"; Cypress.on("uncaught:exception", (err, runnable) => false); diff --git a/frontend/test/__support__/e2e/helpers/e2e-downloads-helpers.js b/frontend/test/__support__/e2e/helpers/e2e-downloads-helpers.js new file mode 100644 index 00000000000..8ca9cacbfd2 --- /dev/null +++ b/frontend/test/__support__/e2e/helpers/e2e-downloads-helpers.js @@ -0,0 +1,77 @@ +const xlsx = require("xlsx"); + +/** + * Trigger the download of CSV or XLSX files and assert on the results in the related sheet. + * It applies to both unsaved questions (queries) and the saved ones. + * + * @param {Object} params + * @param {("csv"|"xlsx")} params.fileType - file type we're downloading + * @param {number} [params.questionId] - needed only for saved questions + * @param {boolean} [params.raw] - tell SheetJs not to parse values + * @param {boolean} [params.logResults] - preview the results in the console log + * @param {function} callback + */ +export function downloadAndAssert( + { fileType, questionId, raw, logResults } = {}, + callback, +) { + const downloadClassName = `.Icon-${fileType}`; + const endpoint = getEndpoint(fileType, questionId); + + /** + * Please see the official Cypress example for more details: + * https://github.com/cypress-io/cypress-example-recipes/blob/master/examples/testing-dom__download/cypress/integration/form-submission-spec.js + */ + + cy.intercept("POST", endpoint, req => { + /** + * We must redirect in order to avoid Cypress being stuck on waiting for the new page to load. + * Intetionally redirecting to a non-existing page. + * + * Explanation: + * If we redirect to ANY of the existing pages, there's a lot of requests that need to complete for that page. + * - This helper function is usually the last piece of code to execute in any given test. + * - As soon as the assertions are complete, the new test starts + * - Assertions are usually faster than all of the previously mentioned requests from the redirect + * - This results in the next test being poluted with the requests that didn't finish from the last one. + * - Those "spill-over" requests end up in the beforeEach hook of the next test and can have unexpected results. + */ + + req.redirect("/foo"); + }).as("fileDownload"); + + cy.log(`Downloading ${fileType} file`); + + cy.icon("download").click(); + // Initiate the file download + cy.get(downloadClassName).click(); + + cy.wait("@fileDownload") + .its("request") + .then(req => { + // The payload for the xlsx is in the binary form + fileType === "xlsx" && Object.assign(req, { encoding: "binary" }); + + cy.request(req).then(({ body }) => { + const { SheetNames, Sheets } = xlsx.read(body, { + // See the full list of Parsing options: https://github.com/SheetJS/sheetjs#parsing-options + type: "binary", + raw, + }); + + const sheetName = SheetNames[0]; + const sheet = Sheets[sheetName]; + + logResults && console.log(sheet); + + callback(sheet); + }); + }); +} + +function getEndpoint(fileType, questionId) { + const questionEndpoint = `/api/card/${questionId}/query/${fileType}`; + const queryEndpoint = `/api/dataset/${fileType}`; + + return questionId ? questionEndpoint : queryEndpoint; +} diff --git a/frontend/test/metabase/scenarios/downloads/downloads.cy.spec.js b/frontend/test/metabase/scenarios/downloads/downloads.cy.spec.js index c85cc73b6e9..dcd655dbacd 100644 --- a/frontend/test/metabase/scenarios/downloads/downloads.cy.spec.js +++ b/frontend/test/metabase/scenarios/downloads/downloads.cy.spec.js @@ -1,30 +1,6 @@ -import { restore } from "__support__/e2e/cypress"; +import { restore, downloadAndAssert } from "__support__/e2e/cypress"; -const xlsx = require("xlsx"); - -// csv and Excel files have different sheet names, so define them here and we'll reuse it throughout -const testCases = [ - { type: "csv", firstSheetName: "Sheet1" }, - { type: "xlsx", firstSheetName: "Query result" }, -]; - -function testWorkbookDatetimes(workbook, download_type, sheetName) { - expect(workbook.SheetNames[0]).to.eq(sheetName); - expect(workbook.Sheets[sheetName]["A1"].v).to.eq("birth_date"); - expect(workbook.Sheets[sheetName]["B1"].v).to.eq("created_at"); - - // Excel and CSV will have different formats - if (download_type === "csv") { - expect(workbook.Sheets[sheetName]["A2"].v).to.eq("2020-06-03"); - expect(workbook.Sheets[sheetName]["B2"].v).to.eq("2020-06-03T23:41:23"); - } else if (download_type === "xlsx") { - // We tell the xlsx library to read raw and not parse dates - // So for the _date_ format we expect an integer - // And for timestamp, we expect a float - expect(workbook.Sheets[sheetName]["A2"].v).to.eq(43985); - expect(workbook.Sheets[sheetName]["B2"].v).to.eq(43985.98707175926); - } -} +const testCases = ["csv", "xlsx"]; describe("scenarios > question > download", () => { beforeEach(() => { @@ -32,132 +8,18 @@ describe("scenarios > question > download", () => { cy.signInAsAdmin(); }); - it("downloads Excel and CSV files", () => { - // let's download a binary file - - cy.visit("/question/new"); - cy.findByText("Simple question").click(); - cy.findByText("Saved Questions").click(); - cy.findByText("Orders, Count").click(); - cy.contains("18,760"); - cy.icon("download").click(); - - // Programatically issue download requests for this query for both CSV and Excel - - cy.wrap(testCases).each(testCase => { - const downloadClassName = `.Icon-${testCase.type}`; - const endpoint = `/api/dataset/${testCase.type}`; - const sheetName = testCase.firstSheetName; - - cy.log(`downloading a ${testCase.type} file`); - - cy.get(downloadClassName) - .parent() - .parent() - .get('input[name="query"]') - .invoke("val") - .then(download_query_params => { - cy.request({ - url: endpoint, - method: "POST", - form: true, - body: { query: download_query_params }, - encoding: "binary", - }).then(resp => { - const workbook = xlsx.read(resp.body, { type: "binary" }); - - expect(workbook.SheetNames[0]).to.eq(sheetName); - expect(workbook.Sheets[sheetName]["A1"].v).to.eq("Count"); - expect(workbook.Sheets[sheetName]["A2"].v).to.eq(18760); - }); - }); - }); - }); - - describe("metabase#10803", () => { - let questionId; - - beforeEach(() => { - cy.createNativeQuestion({ - name: "10803", - native: { - query: - "SELECT PARSEDATETIME('2020-06-03', 'yyyy-MM-dd') AS \"birth_date\", PARSEDATETIME('2020-06-03 23:41:23', 'yyyy-MM-dd hh:mm:ss') AS \"created_at\"", - "template-tags": {}, - }, - }).then(({ body }) => { - questionId = body.id; - }); - }); - - describe("for saved questions", () => { - it("should format the date properly", () => { - cy.wrap(testCases).each(testCase => { - cy.log(`downloading a ${testCase.type} file`); - const endpoint = `/api/card/${questionId}/query/${testCase.type}`; - - cy.request({ - url: endpoint, - method: "POST", - encoding: "binary", - }).then(resp => { - const workbook = xlsx.read(resp.body, { - type: "binary", - raw: true, - }); - - testWorkbookDatetimes( - workbook, - testCase.type, - testCase.firstSheetName, - ); - }); - }); - }); - }); - - describe("for unsaved questions", () => { - it("should format the date properly", () => { - // Go to the existing question "10803" - cy.visit(`/question/${questionId}`); - cy.contains(/open editor/i).click(); - cy.get(".ace_editor").type("{movetoend} "); // Adds a space at the end of the query to make it "dirty" - cy.icon("play") - .first() - .click(); - cy.icon("download").click(); - - cy.wrap(testCases).each(testCase => { - cy.log(`downloading a ${testCase.type} file`); - const downloadClassName = `.Icon-${testCase.type}`; - const endpoint = `/api/dataset/${testCase.type}`; + testCases.forEach(fileType => { + it(`downloads ${fileType} file`, () => { + cy.visit("/question/new"); + cy.findByText("Simple question").click(); + cy.findByText("Saved Questions").click(); + cy.findByText("Orders, Count").click(); - cy.get(downloadClassName) - .parent() - .parent() - .get('input[name="query"]') - .invoke("val") - .then(download_query_params => { - cy.request({ - url: endpoint, - method: "POST", - form: true, - body: { query: download_query_params }, - encoding: "binary", - }).then(resp => { - const workbook = xlsx.read(resp.body, { - type: "binary", - raw: true, - }); + cy.contains("18,760"); - testWorkbookDatetimes( - workbook, - testCase.type, - testCase.firstSheetName, - ); - }); - }); - }); + downloadAndAssert({ fileType }, sheet => { + expect(sheet["A1"].v).to.eq("Count"); + expect(sheet["A2"].v).to.eq(18760); }); }); }); diff --git a/frontend/test/metabase/scenarios/downloads/reproductions/10803-timestamp-formatting.cy.spec.js b/frontend/test/metabase/scenarios/downloads/reproductions/10803-timestamp-formatting.cy.spec.js new file mode 100644 index 00000000000..e6f221fdc4f --- /dev/null +++ b/frontend/test/metabase/scenarios/downloads/reproductions/10803-timestamp-formatting.cy.spec.js @@ -0,0 +1,69 @@ +import { + restore, + downloadAndAssert, + runNativeQuery, +} from "__support__/e2e/cypress"; + +let questionId; + +const testCases = ["csv", "xlsx"]; + +describe("issue 10803", () => { + beforeEach(() => { + cy.intercept("POST", "/api/dataset").as("dataset"); + + restore(); + cy.signInAsAdmin(); + + cy.createNativeQuestion({ + name: "10803", + native: { + query: + "SELECT PARSEDATETIME('2020-06-03', 'yyyy-MM-dd') AS \"birth_date\", PARSEDATETIME('2020-06-03 23:41:23', 'yyyy-MM-dd hh:mm:ss') AS \"created_at\"", + "template-tags": {}, + }, + }).then(({ body }) => { + questionId = body.id; + + cy.intercept("POST", `/api/card/${questionId}/query`).as("cardQuery"); + cy.visit(`/question/${questionId}`); + + cy.wait("@cardQuery"); + }); + }); + + testCases.forEach(fileType => { + it(`should format the date properly for ${fileType} in saved questions (metabase#10803)`, () => { + downloadAndAssert( + { fileType, questionId, logResults: true, raw: true }, + testWorkbookDatetimes, + ); + }); + + it(`should format the date properly for ${fileType} in unsaved questions`, () => { + // Add a space at the end of the query to make it "dirty" + cy.contains(/open editor/i).click(); + cy.get(".ace_editor").type("{movetoend} "); + + runNativeQuery(); + downloadAndAssert({ fileType, raw: true }, testWorkbookDatetimes); + }); + + function testWorkbookDatetimes(sheet) { + expect(sheet["A1"].v).to.eq("birth_date"); + expect(sheet["B1"].v).to.eq("created_at"); + + // Excel and CSV will have different formats + if (fileType === "csv") { + expect(sheet["A2"].v).to.eq("2020-06-03"); + expect(sheet["B2"].v).to.eq("2020-06-03T23:41:23"); + } else if (fileType === "xlsx") { + // We tell the xlsx library to read raw and not parse dates + // So for the _date_ format we expect an integer + // And for timestamp, we expect a float + expect(sheet["A2"].v).to.eq(43985); + expect(sheet["B2"].v).to.eq(43985.98707175926); + } + } + }); +}); diff --git a/frontend/test/metabase/scenarios/downloads/reproductions/18219-temporal-units-not-formatted.cy.spec.js b/frontend/test/metabase/scenarios/downloads/reproductions/18219-temporal-units-not-formatted.cy.spec.js index c1840b55a15..fbca7c20d92 100644 --- a/frontend/test/metabase/scenarios/downloads/reproductions/18219-temporal-units-not-formatted.cy.spec.js +++ b/frontend/test/metabase/scenarios/downloads/reproductions/18219-temporal-units-not-formatted.cy.spec.js @@ -1,7 +1,6 @@ -import { restore } from "__support__/e2e/cypress"; +import { restore, downloadAndAssert } from "__support__/e2e/cypress"; import { SAMPLE_DATASET } from "__support__/e2e/cypress_sample_dataset"; -const xlsx = require("xlsx"); const { ORDERS, ORDERS_ID } = SAMPLE_DATASET; const questionDetails = { @@ -13,10 +12,7 @@ const questionDetails = { }, }; -const testCases = [ - { type: "csv", sheetName: "Sheet1" }, - { type: "xlsx", sheetName: "Query result" }, -]; +const testCases = ["csv", "xlsx"]; describe.skip("issue 18219", () => { beforeEach(() => { @@ -24,60 +20,47 @@ describe.skip("issue 18219", () => { cy.signInAsAdmin(); }); - it("should format temporal units on export (metabase#18219)", () => { - cy.createQuestion(questionDetails).then(({ body: { id } }) => { - cy.intercept("POST", `/api/card/${id}/query`).as("cardQuery"); - cy.visit(`/question/${id}`); + testCases.forEach(fileType => { + it("should format temporal units on export (metabase#18219)", () => { + cy.createQuestion(questionDetails).then( + ({ body: { id: questionId } }) => { + cy.intercept("POST", `/api/card/${questionId}/query`).as("cardQuery"); + cy.visit(`/question/${questionId}`); - // Wait for `result_metadata` to load - cy.wait("@cardQuery"); + // Wait for `result_metadata` to load + cy.wait("@cardQuery"); - cy.findByText("Created At: Year"); - cy.findByText("2016"); - cy.findByText("744"); + cy.findByText("Created At: Year"); + cy.findByText("2016"); + cy.findByText("744"); - cy.icon("download").click(); - - cy.wrap(testCases).each(({ type, sheetName }) => { - cy.log(`downloading a ${type} file`); - const endpoint = `/api/card/${id}/query/${type}`; - - cy.request({ - url: endpoint, - method: "POST", - encoding: "binary", - }).then(resp => { - const workbook = xlsx.read(resp.body, { - type: "binary", - raw: true, - }); - - const A1 = workbook.Sheets[sheetName]["A1"]; - const A2 = workbook.Sheets[sheetName]["A2"]; + downloadAndAssert({ fileType, questionId, raw: true }, assertion); + }, + ); + }); - expect(A1.v).to.eq("Created At: Year"); + function assertion(sheet) { + expect(sheet["A1"].v).to.eq("Created At: Year"); - if (type === "csv") { - expect(A2.v).to.eq("2016"); - } + if (fileType === "csv") { + expect(sheet["A2"].v).to.eq("2016"); + } - if (type === "xlsx") { - /** - * Depending on how we end up solving this issue, - * the following assertion on the cell type might not be correct. - * It's very likely we'll format temporal breakouts as strings. - * I.e. we have to take into account Q1, Q2, etc. - */ - // expect(A2.t).to.eq("n"); + if (fileType === "xlsx") { + /** + * Depending on how we end up solving this issue, + * the following assertion on the cell type might not be correct. + * It's very likely we'll format temporal breakouts as strings. + * I.e. we have to take into account Q1, Q2, etc. + */ + // expect(A2.t).to.eq("n"); - /** - * Because of the excel date format, we cannot assert on the raw value `v`. - * Rather, we have to do it on the parsed value `w`. - */ - expect(A2.w).to.eq("2016"); - } - }); - }); - }); + /** + * Because of the excel date format, we cannot assert on the raw value `v`. + * Rather, we have to do it on the parsed value `w`. + */ + expect(sheet["A2"].w).to.eq("2016"); + } + } }); }); diff --git a/frontend/test/metabase/scenarios/downloads/reproductions/18382-old-syntax-missing-renamed-columns.cy.spec.js b/frontend/test/metabase/scenarios/downloads/reproductions/18382-old-syntax-missing-renamed-columns.cy.spec.js index 4ad694e529e..8101c9aacef 100644 --- a/frontend/test/metabase/scenarios/downloads/reproductions/18382-old-syntax-missing-renamed-columns.cy.spec.js +++ b/frontend/test/metabase/scenarios/downloads/reproductions/18382-old-syntax-missing-renamed-columns.cy.spec.js @@ -1,8 +1,10 @@ -import { restore, visitQuestionAdhoc } from "__support__/e2e/cypress"; +import { + restore, + visitQuestionAdhoc, + downloadAndAssert, +} from "__support__/e2e/cypress"; import { SAMPLE_DATASET } from "__support__/e2e/cypress_sample_dataset"; -const xlsx = require("xlsx"); - const { REVIEWS, REVIEWS_ID, PRODUCTS, PRODUCTS_ID } = SAMPLE_DATASET; /** @@ -39,7 +41,15 @@ const questionDetails = { }, display: "table", visualization_settings: { - // Rename columns + /** + * Rename columns + * + * Please note: it is currently not possible to use the old syntax for columns rename. + * That results in `500` error, and backend doesn't handle it at all. + * Once some kind of mechanism is put in place to prevent the app from breaking in such cases, + * change the following syntax to the old style `["field-id", ${COLUMN_ID}]` + */ + column_settings: { [`["ref",["field",${REVIEWS.ID},null]]`]: { column_title: "MOD:ID", @@ -74,14 +84,11 @@ const questionDetails = { const testCases = ["csv", "xlsx"]; -testCases.forEach(type => { - const downloadClassName = `.Icon-${type}`; - const endpoint = `/api/dataset/${type}`; - +testCases.forEach(fileType => { describe("issue 18382", () => { beforeEach(() => { // TODO: Please remove this line when issue gets fixed - cy.skipOn(type === "csv"); + cy.skipOn(fileType === "csv"); cy.intercept("POST", "/api/dataset").as("dataset"); @@ -92,42 +99,16 @@ testCases.forEach(type => { cy.wait("@dataset"); }); - it(`should handle the old syntax in downloads for ${type} (metabase#18382)`, () => { - cy.url().then(currentPage => { - cy.intercept("POST", endpoint, req => { - // We must redirect in order to avoid Cypress being stuck on waiting for the new page to load. - // But let's stay on the same page, instead of redirecting to `/` or something else. - req.redirect(currentPage); - }).as("fileDownload"); - }); - - cy.log(`Downloading ${type} file`); - - cy.icon("download").click(); - // Initiate the file download - cy.get(downloadClassName).click(); - - cy.wait("@fileDownload") - .its("request") - .then(req => { - // The payload for the xlsx is in the binary form - type === "xlsx" && Object.assign(req, { encoding: "binary" }); - - cy.request(req).then(({ body }) => { - const { SheetNames, Sheets } = xlsx.read(body, { - type: "binary", - }); - - const sheetName = SheetNames[0]; - const sheet = Sheets[sheetName]; - - expect(sheet["A1"].v).to.eq("MOD:Title"); - expect(sheet["B1"].v).to.eq("MOD:ID"); - expect(sheet["C1"].v).to.eq("MOD:Reviewer"); - - expect(sheet["A2"].v).to.eq("Aerodynamic Concrete Bench"); - }); - }); + it(`should handle the old syntax in downloads for ${fileType} (metabase#18382)`, () => { + downloadAndAssert({ fileType }, assertion); }); }); }); + +function assertion(sheet) { + expect(sheet["A1"].v).to.eq("MOD:Title"); + expect(sheet["B1"].v).to.eq("MOD:ID"); + expect(sheet["C1"].v).to.eq("MOD:Reviewer"); + + expect(sheet["A2"].v).to.eq("Aerodynamic Concrete Bench"); +} diff --git a/frontend/test/metabase/scenarios/downloads/reproductions/18440-remapped-display-value-dropped.cy.spec.js b/frontend/test/metabase/scenarios/downloads/reproductions/18440-remapped-display-value-dropped.cy.spec.js index f802e5ef44b..b72c70b3834 100644 --- a/frontend/test/metabase/scenarios/downloads/reproductions/18440-remapped-display-value-dropped.cy.spec.js +++ b/frontend/test/metabase/scenarios/downloads/reproductions/18440-remapped-display-value-dropped.cy.spec.js @@ -1,26 +1,28 @@ -import { restore, visitQuestionAdhoc } from "__support__/e2e/cypress"; +import { + restore, + visitQuestionAdhoc, + downloadAndAssert, +} from "__support__/e2e/cypress"; import { SAMPLE_DATASET } from "__support__/e2e/cypress_sample_dataset"; -const xlsx = require("xlsx"); - const { ORDERS, ORDERS_ID, PRODUCTS } = SAMPLE_DATASET; +const query = { "source-table": ORDERS_ID, limit: 5 }; + const questionDetails = { dataset_query: { type: "query", - query: { "source-table": ORDERS_ID, limit: 5 }, + query, database: 1, }, }; -const testCases = [ - { type: "csv", sheetName: "Sheet1" }, - { type: "xlsx", sheetName: "Query result" }, -]; +const testCases = ["csv", "xlsx"]; describe("issue 18440", () => { beforeEach(() => { cy.intercept("POST", "/api/card").as("saveQuestion"); + cy.intercept("POST", "/api/dataset").as("dataset"); restore(); cy.signInAsAdmin(); @@ -31,76 +33,36 @@ describe("issue 18440", () => { type: "external", human_readable_field_id: PRODUCTS.TITLE, }); - - visitQuestionAdhoc(questionDetails); }); - it("export should include a column with remapped values (metabase#18440)", () => { - cy.findByText("Product ID"); - cy.findByText("Awesome Concrete Shoes"); - - cy.icon("download").click(); + testCases.forEach(fileType => { + it(`export should include a column with remapped values for ${fileType} (metabase#18440-1)`, () => { + visitQuestionAdhoc(questionDetails); + cy.wait("@dataset"); - cy.wrap(testCases).each(({ type, sheetName }) => { - cy.log(`downloading a ${type} file for an unsaved question`); + cy.findByText("Product ID"); + cy.findByText("Awesome Concrete Shoes"); - const downloadClassName = `.Icon-${type}`; - const endpoint = `/api/dataset/${type}`; - - cy.get(downloadClassName) - .parent() - .parent() - .get('input[name="query"]') - .invoke("val") - .then(download_query_params => { - cy.request({ - url: endpoint, - method: "POST", - form: true, - body: { query: download_query_params }, - encoding: "binary", - }).then(resp => { - const workbook = xlsx.read(resp.body, { - type: "binary", - raw: true, - }); - - expect(workbook.Sheets[sheetName]["C1"].v).to.eq("Product ID"); - expect(workbook.Sheets[sheetName]["C2"].v).to.eq( - "Awesome Concrete Shoes", - ); - }); - }); + downloadAndAssert({ fileType }, assertion); }); - // Save the question using UI - cy.findByText("Save").click(); - cy.get(".Modal") - .button("Save") - .click(); + it(`export should include a column with remapped values for ${fileType} for a saved question (metabase#18440-2)`, () => { + cy.createQuestion({ query }).then(({ body: { id } }) => { + cy.intercept("POST", `/api/card/${id}/query`).as("cardQuery"); - cy.wait("@saveQuestion").then(({ response: { body: { id } } }) => { - cy.wrap(testCases).each(({ type, sheetName }) => { - cy.log(`downloading a ${type} file for a saved question`); + cy.visit(`/question/${id}`); + cy.wait("@cardQuery"); - const endpoint = `/api/card/${id}/query/${type}`; + cy.findByText("Product ID"); + cy.findByText("Awesome Concrete Shoes"); - cy.request({ - url: endpoint, - method: "POST", - encoding: "binary", - }).then(resp => { - const workbook = xlsx.read(resp.body, { - type: "binary", - raw: true, - }); - - expect(workbook.Sheets[sheetName]["C1"].v).to.eq("Product ID"); - expect(workbook.Sheets[sheetName]["C2"].v).to.eq( - "Awesome Concrete Shoes", - ); - }); + downloadAndAssert({ fileType, questionId: id }, assertion); }); }); }); }); + +function assertion(sheet) { + expect(sheet["C1"].v).to.eq("Product ID"); + expect(sheet["C2"].v).to.eq("Awesome Concrete Shoes"); +} -- GitLab