Cypress touch-ups (#5109)

* allow non-sequential IDs for DataSources in Cypress tests

* refactor redash-api to a set of Cypress commands

* support mounting Redash endpoints in Cypress routes

* fix some parameter specs by waiting for schema to load

* extract baseUrl from cypress.json

* Restyled by prettier (#5110)

Co-authored-by: Restyled.io <commits@restyled.io>

Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
Co-authored-by: Restyled.io <commits@restyled.io>
This commit is contained in:
Omer Lachish 2020-08-19 21:00:06 +03:00 committed by GitHub
parent a596d6558c
commit de052ff02b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 153 additions and 175 deletions

View File

@ -4,9 +4,16 @@ const atob = require("atob");
const { execSync } = require("child_process");
const { get, post } = require("request").defaults({ jar: true });
const { seedData } = require("./seed-data");
const fs = require("fs");
var Cookie = require("request-cookies").Cookie;
const baseUrl = process.env.CYPRESS_baseUrl || "http://localhost:5000";
let cypressConfigBaseUrl;
try {
const cypressConfig = JSON.parse(fs.readFileSync("cypress.json"));
cypressConfigBaseUrl = cypressConfig.baseUrl;
} catch (e) {}
const baseUrl = process.env.CYPRESS_baseUrl || cypressConfigBaseUrl || "http://localhost:5000";
function seedDatabase(seedValues) {
get(baseUrl + "/login", (_, { headers }) => {

View File

@ -1,5 +1,3 @@
import { createQuery } from "../../support/redash-api";
describe("Create Alert", () => {
beforeEach(() => {
cy.login();
@ -12,7 +10,7 @@ describe("Create Alert", () => {
});
it("selects query and takes a screenshot", () => {
createQuery({ name: "Create Alert Query" }).then(({ id: queryId }) => {
cy.createQuery({ name: "Create Alert Query" }).then(({ id: queryId }) => {
cy.visit("/alerts/new");
cy.getByTestId("QuerySelector")
.click()

View File

@ -1,13 +1,11 @@
import { createAlert, createQuery } from "../../support/redash-api";
describe("Edit Alert", () => {
beforeEach(() => {
cy.login();
});
it("renders the page and takes a screenshot", () => {
createQuery({ query: "select 1 as col_name" })
.then(({ id: queryId }) => createAlert(queryId, { column: "col_name" }))
cy.createQuery({ query: "select 1 as col_name" })
.then(({ id: queryId }) => cy.createAlert(queryId, { column: "col_name" }))
.then(({ id: alertId }) => {
cy.visit(`/alerts/${alertId}/edit`);
cy.getByTestId("Criteria").should("exist");
@ -16,8 +14,8 @@ describe("Edit Alert", () => {
});
it("edits the notification template and takes a screenshot", () => {
createQuery()
.then(({ id: queryId }) => createAlert(queryId, { custom_subject: "FOO", custom_body: "BAR" }))
cy.createQuery()
.then(({ id: queryId }) => cy.createAlert(queryId, { custom_subject: "FOO", custom_body: "BAR" }))
.then(({ id: alertId }) => {
cy.visit(`/alerts/${alertId}/edit`);
cy.getByTestId("AlertCustomTemplate").should("exist");
@ -33,8 +31,8 @@ describe("Edit Alert", () => {
custom_body: "{{ ALERT_THRESHOLD }}",
};
createQuery()
.then(({ id: queryId }) => createAlert(queryId, options))
cy.createQuery()
.then(({ id: queryId }) => cy.createAlert(queryId, options))
.then(({ id: alertId }) => {
cy.visit(`/alerts/${alertId}/edit`);
cy.get(".alert-template-preview").click();

View File

@ -1,14 +1,13 @@
import { createAlert, createQuery, createUser, addDestinationSubscription } from "../../support/redash-api";
describe("View Alert", () => {
beforeEach(function() {
cy.login();
createQuery({ query: "select 1 as col_name" })
.then(({ id: queryId }) => createAlert(queryId, { column: "col_name" }))
.then(({ id: alertId }) => {
this.alertId = alertId;
this.alertUrl = `/alerts/${alertId}`;
});
cy.login().then(() => {
cy.createQuery({ query: "select 1 as col_name" })
.then(({ id: queryId }) => cy.createAlert(queryId, { column: "col_name" }))
.then(({ id: alertId }) => {
this.alertId = alertId;
this.alertUrl = `/alerts/${alertId}`;
});
});
});
it("renders the page and takes a screenshot", function() {
@ -24,8 +23,8 @@ describe("View Alert", () => {
.should("not.exist");
cy.server();
cy.route("GET", "api/destinations").as("Destinations");
cy.route("GET", "api/alerts/*/subscriptions").as("Subscriptions");
cy.route("GET", "**/api/destinations").as("Destinations");
cy.route("GET", "**/api/alerts/*/subscriptions").as("Subscriptions");
cy.visit(this.alertUrl);
@ -42,7 +41,7 @@ describe("View Alert", () => {
describe("Alert Destination permissions", () => {
before(() => {
cy.login();
createUser({
cy.createUser({
name: "Example User",
email: "user@redash.io",
password: "password",
@ -51,11 +50,11 @@ describe("View Alert", () => {
it("hides remove button from non-author", function() {
cy.server();
cy.route("GET", "api/alerts/*/subscriptions").as("Subscriptions");
cy.route("GET", "**/api/alerts/*/subscriptions").as("Subscriptions");
cy.logout()
.then(() => cy.login()) // as admin
.then(() => addDestinationSubscription(this.alertId, "Test Email Destination"))
.then(() => cy.addDestinationSubscription(this.alertId, "Test Email Destination"))
.then(() => {
cy.visit(this.alertUrl);
@ -83,11 +82,11 @@ describe("View Alert", () => {
it("shows remove button for non-author admin", function() {
cy.server();
cy.route("GET", "api/alerts/*/subscriptions").as("Subscriptions");
cy.route("GET", "**/api/alerts/*/subscriptions").as("Subscriptions");
cy.logout()
.then(() => cy.login("user@redash.io", "password"))
.then(() => addDestinationSubscription(this.alertId, "Test Email Destination"))
.then(() => cy.addDestinationSubscription(this.alertId, "Test Email Destination"))
.then(() => {
cy.visit(this.alertUrl);

View File

@ -1,6 +1,5 @@
/* global cy, Cypress */
import { createDashboard, addTextbox } from "../../support/redash-api";
import { getWidgetTestId } from "../../support/dashboard";
const menuWidth = 80;
@ -16,7 +15,7 @@ describe("Dashboard", () => {
cy.getByTestId("CreateDashboardMenuItem").click();
cy.server();
cy.route("POST", "api/dashboards").as("NewDashboard");
cy.route("POST", "**/api/dashboards").as("NewDashboard");
cy.getByTestId("CreateDashboardDialog").within(() => {
cy.getByTestId("DashboardSaveButton").should("be.disabled");
@ -36,7 +35,7 @@ describe("Dashboard", () => {
});
it("archives dashboard", () => {
createDashboard("Foo Bar").then(({ id }) => {
cy.createDashboard("Foo Bar").then(({ id }) => {
cy.visit(`/dashboards/${id}`);
cy.getByTestId("DashboardMoreButton").click();
@ -59,8 +58,8 @@ describe("Dashboard", () => {
it("is accessible through multiple urls", () => {
cy.server();
cy.route("GET", "api/dashboards/*").as("LoadDashboard");
createDashboard("Dashboard multiple urls").then(({ id, slug }) => {
cy.route("GET", "**/api/dashboards/*").as("LoadDashboard");
cy.createDashboard("Dashboard multiple urls").then(({ id, slug }) => {
[`/dashboards/${id}`, `/dashboards/${id}-anything-here`, `/dashboard/${slug}`].forEach(url => {
cy.visit(url);
cy.wait("@LoadDashboard");
@ -75,11 +74,11 @@ describe("Dashboard", () => {
context("viewport width is at 800px", () => {
before(function() {
cy.login();
createDashboard("Foo Bar")
cy.createDashboard("Foo Bar")
.then(({ id }) => {
this.dashboardUrl = `/dashboards/${id}`;
this.dashboardEditUrl = `/dashboards/${id}?edit`;
return addTextbox(id, "Hello World!").then(getWidgetTestId);
return cy.addTextbox(id, "Hello World!").then(getWidgetTestId);
})
.then(elTestId => {
cy.visit(this.dashboardUrl);
@ -132,7 +131,7 @@ describe("Dashboard", () => {
context("viewport width is at 767px", () => {
before(function() {
cy.login();
createDashboard("Foo Bar").then(({ id }) => {
cy.createDashboard("Foo Bar").then(({ id }) => {
this.dashboardUrl = `/dashboards/${id}`;
});
});

View File

@ -1,15 +1,14 @@
import { createDashboard } from "../../support/redash-api";
import { expectTagsToContain, typeInTagsSelectAndSave } from "../../support/tags";
describe("Dashboard Tags", () => {
beforeEach(function() {
cy.login();
createDashboard("Foo Bar").then(({ id }) => cy.visit(`/dashboards/${id}`));
cy.createDashboard("Foo Bar").then(({ id }) => cy.visit(`/dashboards/${id}`));
});
it("is possible to add and edit tags", () => {
cy.server();
cy.route("POST", "api/dashboards/*").as("DashboardSave");
cy.route("POST", "**/api/dashboards/*").as("DashboardSave");
cy.getByTestId("TagsControl").contains(".label", "Unpublished");

View File

@ -1,4 +1,3 @@
import { createDashboard } from "../../support/redash-api";
import { createQueryAndAddWidget, editDashboard } from "../../support/dashboard";
import { expectTableToHaveLength, expectFirstColumnToHaveMembers } from "../../support/visualizations/table";
@ -24,7 +23,7 @@ describe("Dashboard Filters", () => {
name: "Query Filters",
query: `SELECT stage1 AS "stage1::filter", stage2, value FROM (${SQL}) q`,
};
createDashboard("Dashboard Filters").then(dashboard => {
cy.createDashboard("Dashboard Filters").then(dashboard => {
createQueryAndAddWidget(dashboard.id, queryData)
.as("widget1TestId")
.then(() => createQueryAndAddWidget(dashboard.id, queryData, { position: { col: 4 } }))

View File

@ -1,6 +1,5 @@
/* global cy */
import { createDashboard, addTextbox } from "../../support/redash-api";
import { getWidgetTestId, editDashboard, resizeBy } from "../../support/dashboard";
const menuWidth = 80;
@ -9,10 +8,10 @@ describe("Grid compliant widgets", () => {
beforeEach(function() {
cy.login();
cy.viewport(1215 + menuWidth, 800);
createDashboard("Foo Bar")
cy.createDashboard("Foo Bar")
.then(({ id }) => {
this.dashboardUrl = `/dashboards/${id}`;
return addTextbox(id, "Hello World!").then(getWidgetTestId);
return cy.addTextbox(id, "Hello World!").then(getWidgetTestId);
})
.then(elTestId => {
cy.visit(this.dashboardUrl);
@ -50,7 +49,7 @@ describe("Grid compliant widgets", () => {
it("auto saves after drag", () => {
cy.server();
cy.route("POST", "api/widgets/*").as("WidgetSave");
cy.route("POST", "**/api/widgets/*").as("WidgetSave");
editDashboard();
cy.get("@textboxEl").dragBy(330);
@ -118,7 +117,7 @@ describe("Grid compliant widgets", () => {
it("auto saves after resize", () => {
cy.server();
cy.route("POST", "api/widgets/*").as("WidgetSave");
cy.route("POST", "**/api/widgets/*").as("WidgetSave");
editDashboard();
resizeBy(cy.get("@textboxEl"), 200);

View File

@ -1,10 +1,9 @@
import { createDashboard } from "../../support/redash-api";
import { createQueryAndAddWidget } from "../../support/dashboard";
describe("Parameter Mapping", () => {
beforeEach(function() {
cy.login();
createDashboard("Foo Bar")
cy.createDashboard("Foo Bar")
.then(({ id }) => {
this.dashboardId = id;
this.dashboardUrl = `/dashboards/${id}`;

View File

@ -1,12 +1,11 @@
/* global cy */
import { createDashboard, createQuery } from "../../support/redash-api";
import { editDashboard, shareDashboard, createQueryAndAddWidget } from "../../support/dashboard";
describe("Dashboard Sharing", () => {
beforeEach(function() {
cy.login();
createDashboard("Foo Bar").then(({ id }) => {
cy.createDashboard("Foo Bar").then(({ id }) => {
this.dashboardId = id;
this.dashboardUrl = `/dashboards/${id}`;
});
@ -23,7 +22,7 @@ describe("Dashboard Sharing", () => {
};
const dashboardUrl = this.dashboardUrl;
createQuery({ options }).then(({ id: queryId }) => {
cy.createQuery({ options }).then(({ id: queryId }) => {
cy.visit(dashboardUrl);
editDashboard();
cy.getByTestId("AddWidgetButton").click();
@ -148,7 +147,7 @@ describe("Dashboard Sharing", () => {
};
const dashboardUrl = this.dashboardUrl;
createQuery({ options }).then(({ id: queryId }) => {
cy.createQuery({ options }).then(({ id: queryId }) => {
cy.visit(dashboardUrl);
editDashboard();
cy.getByTestId("AddWidgetButton").click();

View File

@ -1,12 +1,11 @@
/* global cy */
import { createDashboard, addTextbox } from "../../support/redash-api";
import { getWidgetTestId, editDashboard } from "../../support/dashboard";
describe("Textbox", () => {
beforeEach(function() {
cy.login();
createDashboard("Foo Bar").then(({ id }) => {
cy.createDashboard("Foo Bar").then(({ id }) => {
this.dashboardId = id;
this.dashboardUrl = `/dashboards/${id}`;
});
@ -31,7 +30,7 @@ describe("Textbox", () => {
});
it("removes textbox by X button", function() {
addTextbox(this.dashboardId, "Hello World!")
cy.addTextbox(this.dashboardId, "Hello World!")
.then(getWidgetTestId)
.then(elTestId => {
cy.visit(this.dashboardUrl);
@ -47,7 +46,7 @@ describe("Textbox", () => {
});
it("removes textbox by menu", function() {
addTextbox(this.dashboardId, "Hello World!")
cy.addTextbox(this.dashboardId, "Hello World!")
.then(getWidgetTestId)
.then(elTestId => {
cy.visit(this.dashboardUrl);
@ -65,11 +64,11 @@ describe("Textbox", () => {
it("allows opening menu after removal", function() {
let elTestId1;
addTextbox(this.dashboardId, "txb 1")
cy.addTextbox(this.dashboardId, "txb 1")
.then(getWidgetTestId)
.then(elTestId => {
elTestId1 = elTestId;
return addTextbox(this.dashboardId, "txb 2").then(getWidgetTestId);
return cy.addTextbox(this.dashboardId, "txb 2").then(getWidgetTestId);
})
.then(elTestId2 => {
cy.visit(this.dashboardUrl);
@ -99,7 +98,7 @@ describe("Textbox", () => {
});
it("edits textbox", function() {
addTextbox(this.dashboardId, "Hello World!")
cy.addTextbox(this.dashboardId, "Hello World!")
.then(getWidgetTestId)
.then(elTestId => {
cy.visit(this.dashboardUrl);
@ -133,8 +132,8 @@ describe("Textbox", () => {
const txb2Pos = { col: 1, row: 1, sizeX: 3, sizeY: 4 };
cy.viewport(1215, 800);
addTextbox(id, "x", { position: txb1Pos })
.then(() => addTextbox(id, "x", { position: txb2Pos }))
cy.addTextbox(id, "x", { position: txb1Pos })
.then(() => cy.addTextbox(id, "x", { position: txb2Pos }))
.then(getWidgetTestId)
.then(elTestId => {
cy.visit(this.dashboardUrl);

View File

@ -1,12 +1,11 @@
/* global cy */
import { createDashboard, createQuery } from "../../support/redash-api";
import { createQueryAndAddWidget, editDashboard, resizeBy } from "../../support/dashboard";
describe("Widget", () => {
beforeEach(function() {
cy.login();
createDashboard("Foo Bar").then(({ id }) => {
cy.createDashboard("Foo Bar").then(({ id }) => {
this.dashboardId = id;
this.dashboardUrl = `/dashboards/${id}`;
});
@ -19,7 +18,7 @@ describe("Widget", () => {
};
it("adds widget", function() {
createQuery().then(({ id: queryId }) => {
cy.createQuery().then(({ id: queryId }) => {
cy.visit(this.dashboardUrl);
editDashboard();
cy.getByTestId("AddWidgetButton").click();
@ -104,7 +103,7 @@ describe("Widget", () => {
it("grows when dynamically adding table rows", () => {
// listen to results
cy.server();
cy.route("GET", "api/query_results/*").as("FreshResults");
cy.route("GET", "**/api/query_results/*").as("FreshResults");
// start with 1 table row
cy.get("@paramInput")
@ -132,7 +131,7 @@ describe("Widget", () => {
it("revokes auto height after manual height adjustment", () => {
// listen to results
cy.server();
cy.route("GET", "api/query_results/*").as("FreshResults");
cy.route("GET", "**/api/query_results/*").as("FreshResults");
editDashboard();

View File

@ -6,7 +6,7 @@ describe("Create Data Source", () => {
it("renders the page and takes a screenshot", function() {
cy.server();
cy.route("api/data_sources/types").as("DataSourceTypesRequest");
cy.route("**/api/data_sources/types").as("DataSourceTypesRequest");
cy.wait("@DataSourceTypesRequest")
.then(({ response }) => response.body.filter(type => type.deprecated))

View File

@ -1,5 +1,3 @@
import { createDestination } from "../../support/redash-api";
describe("Create Destination", () => {
beforeEach(() => {
cy.login();
@ -8,7 +6,7 @@ describe("Create Destination", () => {
it("renders the page and takes a screenshot", function() {
cy.visit("/destinations/new");
cy.server();
cy.route("api/destinations/types").as("DestinationTypesRequest");
cy.route("**/api/destinations/types").as("DestinationTypesRequest");
cy.wait("@DestinationTypesRequest")
.then(({ response }) => response.body.filter(type => type.deprecated))
@ -25,7 +23,7 @@ describe("Create Destination", () => {
});
it("shows a custom error message when destination name is already taken", () => {
createDestination("Slack Destination", "slack").then(() => {
cy.createDestination("Slack Destination", "slack").then(() => {
cy.visit("/destinations/new");
cy.getByTestId("SearchSource").type("Slack");

View File

@ -1,12 +1,10 @@
import { createQuery } from "../../support/redash-api";
describe("Embedded Queries", () => {
beforeEach(() => {
cy.login();
});
it("can be shared without parameters", () => {
createQuery({ query: "select name from users order by name" }).then(query => {
cy.createQuery({ query: "select name from users order by name" }).then(query => {
cy.visit(`/queries/${query.id}/source`);
cy.getByTestId("ExecuteButton").click();
cy.getByTestId("QueryPageVisualizationTabs", { timeout: 10000 }).should("exist");

View File

@ -7,7 +7,7 @@ describe("Create Query", () => {
it("executes and saves a query", () => {
cy.clickThrough(`
SelectDataSource
SelectDataSource1
SelectDataSource${Cypress.env("dataSourceId")}
`);
cy.getByTestId("QueryEditor")
@ -22,6 +22,6 @@ describe("Create Query", () => {
cy.percySnapshot("Edit Query");
cy.getByTestId("SaveButton").click();
cy.url().should("match", /\/queries\/\d+\/source/);
cy.url().should("match", /\/queries\/.+\/source/);
});
});

View File

@ -1,4 +1,3 @@
import { createQuery } from "../../support/redash-api";
import { expectTableToHaveLength, expectFirstColumnToHaveMembers } from "../../support/visualizations/table";
const SQL = `
@ -27,7 +26,7 @@ describe("Query Filters", () => {
query: `SELECT stage1 AS "stage1::filter", stage2, value FROM (${SQL}) q`,
};
createQuery(queryData).then(({ id }) => cy.visit(`/queries/${id}`));
cy.createQuery(queryData).then(({ id }) => cy.visit(`/queries/${id}`));
cy.getByTestId("ExecuteButton").click();
});
@ -57,7 +56,7 @@ describe("Query Filters", () => {
query: `SELECT stage1 AS "stage1::multi-filter", stage2, value FROM (${SQL}) q`,
};
createQuery(queryData).then(({ id }) => cy.visit(`/queries/${id}`));
cy.createQuery(queryData).then(({ id }) => cy.visit(`/queries/${id}`));
cy.getByTestId("ExecuteButton").click();
});

View File

@ -1,5 +1,3 @@
import { createQuery } from "../../support/redash-api";
describe("Parameter", () => {
const expectDirtyStateChange = edit => {
cy.getByTestId("ParameterName-test-parameter")
@ -31,7 +29,7 @@ describe("Parameter", () => {
},
};
createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}`));
cy.createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}`));
});
it("updates the results after clicking Apply", () => {
@ -63,7 +61,7 @@ describe("Parameter", () => {
},
};
createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}`));
cy.createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}`));
});
it("updates the results after clicking Apply", () => {
@ -105,7 +103,7 @@ describe("Parameter", () => {
},
};
createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
cy.createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
});
it("updates the results after selecting a value", () => {
@ -167,7 +165,7 @@ describe("Parameter", () => {
name: "Dropdown Query",
query: "",
};
createQuery(dropdownQueryData, true).then(dropdownQuery => {
cy.createQuery(dropdownQueryData, true).then(dropdownQuery => {
const queryData = {
name: "Query Based Dropdown Parameter",
query: "SELECT '{{test-parameter}}' AS parameter",
@ -178,7 +176,7 @@ describe("Parameter", () => {
},
};
createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
cy.createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
});
});
@ -199,7 +197,7 @@ describe("Parameter", () => {
SELECT 'value2' AS name, 2 AS value UNION ALL
SELECT 'value3' AS name, 3 AS value`,
};
createQuery(dropdownQueryData, true).then(dropdownQuery => {
cy.createQuery(dropdownQueryData, true).then(dropdownQuery => {
const queryData = {
name: "Query Based Dropdown Parameter",
query: "SELECT '{{test-parameter}}' AS parameter",
@ -217,7 +215,7 @@ describe("Parameter", () => {
.and("contain", "value2")
.and("contain", "value3");
createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
cy.createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
});
});
@ -274,7 +272,7 @@ describe("Parameter", () => {
cy.wrap(now.getTime()).as("now");
cy.clock(now.getTime(), ["Date"]);
createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}`));
cy.createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}`));
});
afterEach(() => {
@ -321,7 +319,7 @@ describe("Parameter", () => {
cy.wrap(now.getTime()).as("now");
cy.clock(now.getTime(), ["Date"]);
createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}`));
cy.createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}`));
});
afterEach(() => {
@ -415,7 +413,7 @@ describe("Parameter", () => {
cy.wrap(now.getTime()).as("now");
cy.clock(now.getTime(), ["Date"]);
createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
cy.createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
});
afterEach(() => {
@ -469,7 +467,7 @@ describe("Parameter", () => {
cy.location("search").should("not.contain", "Redash");
cy.server();
cy.route("POST", "api/queries/*/results").as("Results");
cy.route("POST", "**/api/queries/*/results").as("Results");
apply(cy.get("@Input"));
@ -489,7 +487,12 @@ describe("Parameter", () => {
},
};
createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
cy.server();
cy.route("GET", "**/api/data_sources/*/schema").as("Schema");
cy.createQuery(queryData, false)
.then(({ id }) => cy.visit(`/queries/${id}/source`))
.then(() => cy.wait("@Schema"));
});
it("shows and hides according to parameter dirty state", () => {
@ -564,7 +567,7 @@ describe("Parameter", () => {
},
};
createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
cy.createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
cy.get(".parameter-block")
.first()
@ -586,7 +589,7 @@ describe("Parameter", () => {
it("is possible to rearrange parameters", function() {
cy.server();
cy.route("POST", "api/queries/*").as("QuerySave");
cy.route("POST", "**/api/queries/*").as("QuerySave");
dragParam("param1", this.paramWidth, 1);
cy.wait("@QuerySave");
@ -610,7 +613,7 @@ describe("Parameter", () => {
},
};
createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
cy.createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}/source`));
cy.getByTestId("ParameterSettings-parameter").click();
});

View File

@ -1,4 +1,3 @@
import { createQuery } from "../../support/redash-api";
import { expectTagsToContain, typeInTagsSelectAndSave } from "../../support/tags";
describe("Query Tags", () => {
@ -10,12 +9,12 @@ describe("Query Tags", () => {
query: "SELECT 1 as value",
};
createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}`));
cy.createQuery(queryData, false).then(({ id }) => cy.visit(`/queries/${id}`));
});
it("is possible to add and edit tags", () => {
cy.server();
cy.route("POST", "api/queries/*").as("QuerySave");
cy.route("POST", "**/api/queries/*").as("QuerySave");
cy.getByTestId("TagsControl").contains(".label", "Unpublished");

View File

@ -1,5 +1,3 @@
import { createUser } from "../../support/redash-api";
describe("Settings Tabs", () => {
const regularUser = {
name: "Example User",
@ -17,7 +15,7 @@ describe("Settings Tabs", () => {
});
before(() => {
cy.login().then(() => createUser(regularUser));
cy.login().then(() => cy.createUser(regularUser));
});
describe("For admin user", () => {

View File

@ -1,7 +1,5 @@
/* global cy, Cypress */
import { createQuery, createVisualization } from "../../support/redash-api";
const SQL = `
SELECT 12 AS mn, 4967 AS mx UNION ALL
SELECT 10 AS mn, 19430 AS mx UNION ALL
@ -42,8 +40,8 @@ describe("Box Plot", () => {
beforeEach(() => {
cy.login();
createQuery({ query: SQL })
.then(({ id }) => createVisualization(id, "BOXPLOT", "Boxplot (Deprecated)", {}))
cy.createQuery({ query: SQL })
.then(({ id }) => cy.createVisualization(id, "BOXPLOT", "Boxplot (Deprecated)", {}))
.then(({ id: visualizationId, query_id: queryId }) => {
cy.visit(`queries/${queryId}/source#${visualizationId}`);
cy.getByTestId("ExecuteButton").click();

View File

@ -1,7 +1,5 @@
/* global cy */
import { createQuery } from "../../support/redash-api";
const SQL = `
SELECT 'AR' AS "code", 'Argentina' AS "name", 37.62 AS "value" UNION ALL
SELECT 'AU' AS "code", 'Australia' AS "name", 37.62 AS "value" UNION ALL
@ -34,7 +32,7 @@ describe("Choropleth", () => {
beforeEach(() => {
cy.login();
createQuery({ query: SQL }).then(({ id }) => {
cy.createQuery({ query: SQL }).then(({ id }) => {
cy.visit(`queries/${id}/source`);
cy.getByTestId("ExecuteButton").click();
});

View File

@ -1,7 +1,5 @@
/* global cy, Cypress */
import { createQuery } from "../../support/redash-api";
const SQL = `
SELECT '2019-01-01' AS "date", 21 AS "bucket", 5 AS "value", 1 AS "stage" UNION ALL
SELECT '2019-01-01' AS "date", 21 AS "bucket", 8 AS "value", 2 AS "stage" UNION ALL
@ -24,7 +22,7 @@ describe("Cohort", () => {
beforeEach(() => {
cy.login();
createQuery({ query: SQL }).then(({ id }) => {
cy.createQuery({ query: SQL }).then(({ id }) => {
cy.visit(`queries/${id}/source`);
cy.getByTestId("ExecuteButton").click();
});

View File

@ -1,7 +1,5 @@
/* global cy, Cypress */
import { createQuery } from "../../support/redash-api";
const SQL = `
SELECT 27182.8182846 AS a, 20000 AS b, 'lorem' AS c UNION ALL
SELECT 31415.9265359 AS a, 40000 AS b, 'ipsum' AS c
@ -12,7 +10,7 @@ describe("Counter", () => {
beforeEach(() => {
cy.login();
createQuery({ query: SQL }).then(({ id }) => {
cy.createQuery({ query: SQL }).then(({ id }) => {
cy.visit(`queries/${id}/source`);
cy.getByTestId("ExecuteButton").click();
});

View File

@ -1,11 +1,9 @@
/* global cy */
import { createQuery } from "../../support/redash-api";
describe("Edit visualization dialog", () => {
beforeEach(() => {
cy.login();
createQuery().then(({ id }) => {
cy.createQuery().then(({ id }) => {
cy.visit(`queries/${id}/source`);
cy.getByTestId("ExecuteButton").click();
});

View File

@ -1,7 +1,5 @@
/* global cy, Cypress */
import { createQuery } from "../../support/redash-api";
const SQL = `
SELECT 'a.01' AS a, 1.758831600227 AS b UNION ALL
SELECT 'a.02' AS a, 613.4456936572 AS b UNION ALL
@ -25,7 +23,7 @@ describe("Funnel", () => {
beforeEach(() => {
cy.login();
createQuery({ query: SQL }).then(({ id }) => {
cy.createQuery({ query: SQL }).then(({ id }) => {
cy.visit(`queries/${id}/source`);
cy.getByTestId("ExecuteButton").click();
});

View File

@ -1,7 +1,5 @@
/* global cy */
import { createQuery, createVisualization } from "../../support/redash-api";
const SQL = `
SELECT 'Israel' AS country, 32.0808800 AS lat, 34.7805700 AS lng UNION ALL
SELECT 'Israel' AS country, 31.7690400 AS lat, 35.2163300 AS lng UNION ALL
@ -22,8 +20,8 @@ describe("Map (Markers)", () => {
const mapTileUrl = "/static/images/fixtures/map-tile.png";
createQuery({ query: SQL })
.then(({ id }) => createVisualization(id, "MAP", "Map (Markers)", { mapTileUrl }))
cy.createQuery({ query: SQL })
.then(({ id }) => cy.createVisualization(id, "MAP", "Map (Markers)", { mapTileUrl }))
.then(({ id: visualizationId, query_id: queryId }) => {
cy.visit(`queries/${queryId}/source#${visualizationId}`);
cy.getByTestId("ExecuteButton").click();

View File

@ -1,6 +1,5 @@
/* global cy, Cypress */
import { createQuery, createVisualization, createDashboard, addWidget } from "../../support/redash-api";
import { getWidgetTestId } from "../../support/dashboard";
const { get } = Cypress._;
@ -44,7 +43,7 @@ function createPivotThroughUI(visualizationName, options = {}) {
describe("Pivot", () => {
beforeEach(() => {
cy.login();
createQuery({ name: "Pivot Visualization", query: SQL })
cy.createQuery({ name: "Pivot Visualization", query: SQL })
.its("id")
.as("queryId");
});
@ -68,7 +67,7 @@ describe("Pivot", () => {
const visualizationName = "Pivot";
cy.server();
cy.route("POST", "api/visualizations").as("SaveVisualization");
cy.route("POST", "**/api/visualizations").as("SaveVisualization");
createPivotThroughUI(visualizationName, { hideControls: true });
@ -92,7 +91,7 @@ describe("Pivot", () => {
vals: ["value"],
};
createVisualization(this.queryId, "PIVOT", "Pivot", options).then(visualization => {
cy.createVisualization(this.queryId, "PIVOT", "Pivot", options).then(visualization => {
cy.visit(`queries/${this.queryId}/source#${visualization.id}`);
cy.getByTestId("ExecuteButton").click();
@ -141,14 +140,14 @@ describe("Pivot", () => {
},
];
createDashboard("Pivot Visualization")
cy.createDashboard("Pivot Visualization")
.then(dashboard => {
this.dashboardUrl = `/dashboards/${dashboard.id}`;
return cy.all(
pivotTables.map(pivot => () =>
createVisualization(this.queryId, "PIVOT", pivot.name, pivot.options).then(visualization =>
addWidget(dashboard.id, visualization.id, { position: pivot.position })
)
cy
.createVisualization(this.queryId, "PIVOT", pivot.name, pivot.options)
.then(visualization => cy.addWidget(dashboard.id, visualization.id, { position: pivot.position }))
)
);
})

View File

@ -1,6 +1,5 @@
/* global cy */
import { createQuery, createDashboard, createVisualization, addWidget } from "../../support/redash-api";
import { getWidgetTestId } from "../../support/dashboard";
const SQL = `
@ -24,7 +23,7 @@ describe("Sankey and Sunburst", () => {
describe("Creation through UI", () => {
beforeEach(() => {
createQuery({ query: SQL }).then(({ id }) => {
cy.createQuery({ query: SQL }).then(({ id }) => {
cy.visit(`queries/${id}/source`);
cy.getByTestId("ExecuteButton").click();
});
@ -98,14 +97,15 @@ describe("Sankey and Sunburst", () => {
];
it("takes a snapshot with Sunburst (1 - 5 stages)", function() {
createDashboard("Sunburst Visualization").then(dashboard => {
cy.createDashboard("Sunburst Visualization").then(dashboard => {
this.dashboardUrl = `/dashboards/${dashboard.id}`;
return cy
.all(
STAGES_WIDGETS.map(sunburst => () =>
createQuery({ name: `Sunburst with ${sunburst.name}`, query: sunburst.query })
.then(queryData => createVisualization(queryData.id, "SUNBURST_SEQUENCE", "Sunburst", {}))
.then(visualization => addWidget(dashboard.id, visualization.id, { position: sunburst.position }))
cy
.createQuery({ name: `Sunburst with ${sunburst.name}`, query: sunburst.query })
.then(queryData => cy.createVisualization(queryData.id, "SUNBURST_SEQUENCE", "Sunburst", {}))
.then(visualization => cy.addWidget(dashboard.id, visualization.id, { position: sunburst.position }))
)
)
.then(widgets => {
@ -122,14 +122,15 @@ describe("Sankey and Sunburst", () => {
});
it("takes a snapshot with Sankey (1 - 5 stages)", function() {
createDashboard("Sankey Visualization").then(dashboard => {
cy.createDashboard("Sankey Visualization").then(dashboard => {
this.dashboardUrl = `/dashboards/${dashboard.id}`;
return cy
.all(
STAGES_WIDGETS.map(sankey => () =>
createQuery({ name: `Sankey with ${sankey.name}`, query: sankey.query })
.then(queryData => createVisualization(queryData.id, "SANKEY", "Sankey", {}))
.then(visualization => addWidget(dashboard.id, visualization.id, { position: sankey.position }))
cy
.createQuery({ name: `Sankey with ${sankey.name}`, query: sankey.query })
.then(queryData => cy.createVisualization(queryData.id, "SANKEY", "Sankey", {}))
.then(visualization => cy.addWidget(dashboard.id, visualization.id, { position: sankey.position }))
)
)
.then(widgets => {

View File

@ -4,15 +4,15 @@
This test suite relies on Percy (does not validate rendered visualizations)
*/
import { createQuery, createVisualization } from "../../../support/redash-api";
import * as AllCellTypes from "./.mocks/all-cell-types";
import * as MultiColumnSort from "./.mocks/multi-column-sort";
import * as SearchInData from "./.mocks/search-in-data";
import * as LargeDataset from "./.mocks/large-dataset";
function prepareVisualization(query, type, name, options) {
return createQuery({ query })
.then(({ id }) => createVisualization(id, type, name, options))
return cy
.createQuery({ query })
.then(({ id }) => cy.createVisualization(id, type, name, options))
.then(({ id: visualizationId, query_id: queryId }) => {
// use data-only view because we don't need editor features, but it will
// free more space for visualizations. Also, we'll hide schema browser (via shortcut)

View File

@ -1,7 +1,5 @@
/* global cy, Cypress */
import { createQuery } from "../../support/redash-api";
const { map } = Cypress._;
const SQL = `
@ -64,7 +62,7 @@ describe("Word Cloud", () => {
beforeEach(() => {
cy.login();
createQuery({ query: SQL }).then(({ id }) => {
cy.createQuery({ query: SQL }).then(({ id }) => {
cy.visit(`queries/${id}/source`);
cy.getByTestId("ExecuteButton").click();
});

View File

@ -1,7 +1,5 @@
/* global cy */
import { createQuery, addWidget } from "../redash-api";
const { get } = Cypress._;
const RESIZE_HANDLE_SELECTOR = ".react-resizable-handle";
@ -10,11 +8,12 @@ export function getWidgetTestId(widget) {
}
export function createQueryAndAddWidget(dashboardId, queryData = {}, widgetOptions = {}) {
return createQuery(queryData)
return cy
.createQuery(queryData)
.then(query => {
const visualizationId = get(query, "visualizations.0.id");
assert.isDefined(visualizationId, "Query api call returns at least one visualization with id");
return addWidget(dashboardId, visualizationId, widgetOptions);
return cy.addWidget(dashboardId, visualizationId, widgetOptions);
})
.then(getWidgetTestId);
}

View File

@ -1 +1,6 @@
/* global Cypress */
import "./commands";
import "./redash-api/index.js";
Cypress.env("dataSourceId", 1);

View File

@ -7,16 +7,16 @@ const post = options =>
.getCookie("csrf_token")
.then(csrf => cy.request({ ...options, method: "POST", headers: { "X-CSRF-TOKEN": csrf.value } }));
export function createDashboard(name) {
Cypress.Commands.add("createDashboard", name => {
return post({ url: "api/dashboards", body: { name } }).then(({ body }) => body);
}
});
export function createQuery(data, shouldPublish = true) {
Cypress.Commands.add("createQuery", (data, shouldPublish = true) => {
const merged = extend(
{
name: "Test Query",
query: "select 1",
data_source_id: 1,
data_source_id: Cypress.env("dataSourceId"),
options: {
parameters: [],
},
@ -34,17 +34,17 @@ export function createQuery(data, shouldPublish = true) {
}
return request;
}
});
export function createVisualization(queryId, type, name, options) {
Cypress.Commands.add("createVisualization", (queryId, type, name, options) => {
const data = { query_id: queryId, type, name, options };
return post({ url: "/api/visualizations", body: data }).then(({ body }) => ({
query_id: queryId,
...body,
}));
}
});
export function addTextbox(dashboardId, text = "text", options = {}) {
Cypress.Commands.add("addTextbox", (dashboardId, text = "text", options = {}) => {
const defaultOptions = {
position: { col: 0, row: 0, sizeX: 3, sizeY: 3 },
};
@ -62,9 +62,9 @@ export function addTextbox(dashboardId, text = "text", options = {}) {
assert.isDefined(id, "Widget api call returns widget id");
return body;
});
}
});
export function addWidget(dashboardId, visualizationId, options = {}) {
Cypress.Commands.add("addWidget", (dashboardId, visualizationId, options = {}) => {
const defaultOptions = {
position: { col: 0, row: 0, sizeX: 3, sizeY: 3 },
};
@ -81,9 +81,9 @@ export function addWidget(dashboardId, visualizationId, options = {}) {
assert.isDefined(id, "Widget api call returns widget id");
return body;
});
}
});
export function createAlert(queryId, options = {}, name) {
Cypress.Commands.add("createAlert", (queryId, options = {}, name) => {
const defaultOptions = {
column: "?column?",
op: "greater than",
@ -102,9 +102,9 @@ export function createAlert(queryId, options = {}, name) {
assert.isDefined(id, "Alert api call retu ns alert id");
return body;
});
}
});
export function createUser({ name, email, password }) {
Cypress.Commands.add("createUser", ({ name, email, password }) => {
return post({
url: "api/users?no_invite=yes",
body: { name, email },
@ -129,22 +129,23 @@ export function createUser({ name, email, password }) {
body: { password },
});
});
}
});
export function createDestination(name, type, options = {}) {
Cypress.Commands.add("createDestination", (name, type, options = {}) => {
return post({
url: "api/destinations",
body: { name, type, options },
failOnStatusCode: false,
});
}
});
export function getDestinations() {
Cypress.Commands.add("getDestinations", () => {
return cy.request("GET", "api/destinations").then(({ body }) => body);
}
});
export function addDestinationSubscription(alertId, destinationName) {
return getDestinations()
Cypress.Commands.add("addDestinationSubscription", (alertId, destinationName) => {
return cy
.getDestinations()
.then(destinations => {
const destination = find(destinations, { name: destinationName });
if (!destination) {
@ -163,4 +164,4 @@ export function addDestinationSubscription(alertId, destinationName) {
assert.isDefined(id, "Subscription api call returns subscription id");
return body;
});
}
});