Skip to content
Snippets Groups Projects
Unverified Commit 46af3b4c authored by Kamil Mielnik's avatar Kamil Mielnik Committed by GitHub
Browse files

Refactor remaining e2e API commands to TS helper functions (#48672)

* Refactor createDashboardWithQuestions, createQuestionAndAddToDashboard and editDashboardCard to TS function helpers

* Fix createNativeQuestionAndDashboard that got out of sync
parent 1a2a9c81
No related branches found
No related tags found
No related merge requests found
import "./commands/ui/button";
import "./commands/ui/icon";
import "./commands/api/index";
import "./commands/api/dashboardCard";
import "./commands/api/composite/createNativeQuestionAndDashboard";
import "./commands/api/composite/createQuestionAndAddToDashboard";
import "./commands/api/composite/createDashboardWithQuestions";
import "./commands/api";
import "./commands/user/createUser";
import "./commands/user/authentication";
......
......@@ -3,9 +3,13 @@ import {
archiveDashboard,
createCollection,
createDashboard,
createDashboardWithQuestions,
createNativeQuestion,
createNativeQuestionAndDashboard,
createQuestion,
createQuestionAndAddToDashboard,
createQuestionAndDashboard,
editDashboardCard,
} from "e2e/support/helpers";
declare global {
......@@ -43,6 +47,14 @@ declare global {
*/
createDashboard: typeof createDashboard;
/**
* @deprecated Use function helper instead, i.e.
* ```
* import { createDashboardWithQuestions } from "e2e/support/helpers"
* ```
*/
createDashboardWithQuestions: typeof createDashboardWithQuestions;
/**
* @deprecated Use function helper instead, i.e.
* ```
......@@ -51,6 +63,14 @@ declare global {
*/
createNativeQuestion: typeof createNativeQuestion;
/**
* @deprecated Use function helper instead, i.e.
* ```
* import { createNativeQuestionAndDashboard } from "e2e/support/helpers"
* ```
*/
createNativeQuestionAndDashboard: typeof createNativeQuestionAndDashboard;
/**
* @deprecated Use function helper instead, i.e.
* ```
......@@ -59,6 +79,14 @@ declare global {
*/
createQuestion: typeof createQuestion;
/**
* @deprecated Use function helper instead, i.e.
* ```
* import { createQuestionAndAddToDashboard } from "e2e/support/helpers"
* ```
*/
createQuestionAndAddToDashboard: typeof createQuestionAndAddToDashboard;
/**
* @deprecated Use function helper instead, i.e.
* ```
......@@ -66,6 +94,14 @@ declare global {
* ```
*/
createQuestionAndDashboard: typeof createQuestionAndDashboard;
/**
* @deprecated Use function helper instead, i.e.
* ```
* import { editDashboardCard } from "e2e/support/helpers"
* ```
*/
editDashboardCard: typeof editDashboardCard;
}
}
}
......@@ -74,6 +110,19 @@ Cypress.Commands.add("archiveCollection", archiveCollection);
Cypress.Commands.add("archiveDashboard", archiveDashboard);
Cypress.Commands.add("createCollection", createCollection);
Cypress.Commands.add("createDashboard", createDashboard);
Cypress.Commands.add(
"createDashboardWithQuestions",
createDashboardWithQuestions,
);
Cypress.Commands.add("createNativeQuestion", createNativeQuestion);
Cypress.Commands.add(
"createNativeQuestionAndDashboard",
createNativeQuestionAndDashboard,
);
Cypress.Commands.add("createQuestion", createQuestion);
Cypress.Commands.add(
"createQuestionAndAddToDashboard",
createQuestionAndAddToDashboard,
);
Cypress.Commands.add("createQuestionAndDashboard", createQuestionAndDashboard);
Cypress.Commands.add("editDashboardCard", editDashboardCard);
import { cypressWaitAll } from "e2e/support/helpers";
Cypress.Commands.add(
"createDashboardWithQuestions",
({ dashboardName, dashboardDetails, questions, cards }) => {
return cy
.createDashboard({ name: dashboardName, ...dashboardDetails })
.then(({ body: dashboard }) => {
return cypressWaitAll(
questions.map((query, index) =>
cy.createQuestionAndAddToDashboard(
query,
dashboard.id,
cards ? cards[index] : undefined,
),
),
).then(dashcardResponses => {
const questions = dashcardResponses.map(
dashcardResponse => dashcardResponse.body.card,
);
return {
questions,
dashboard,
};
});
});
},
);
Cypress.Commands.add(
"createNativeQuestionAndDashboard",
({ questionDetails, dashboardDetails } = {}) => {
const tabs = dashboardDetails?.tabs ?? [];
const defaultTabId = tabs[0]?.id ?? null;
cy.createNativeQuestion(questionDetails).then(
({ body: { id: questionId } }) => {
cy.createDashboard(dashboardDetails).then(
({ body: { id: dashboardId } }) => {
cy.request("PUT", `/api/dashboard/${dashboardId}`, {
tabs,
dashcards: [
{
id: -1,
card_id: questionId,
dashboard_tab_id: defaultTabId,
// Add sane defaults for the dashboard card size and position
row: 0,
col: 0,
size_x: 11,
size_y: 6,
},
],
}).then(response => ({
...response,
dashboardId,
dashboardTabs: response.body.tabs,
body: response.body.dashcards[0],
questionId,
}));
},
);
},
);
},
);
import type { Card, Dashboard } from "metabase-types/api";
import { cypressWaitAll } from "../e2e-misc-helpers";
import { type DashboardDetails, createDashboard } from "./createDashboard";
import type { NativeQuestionDetails } from "./createNativeQuestion";
import type { StructuredQuestionDetails } from "./createQuestion";
import { createQuestionAndAddToDashboard } from "./createQuestionAndAddToDashboard";
export const createDashboardWithQuestions = ({
dashboardName,
dashboardDetails,
questions,
cards,
}: {
dashboardName?: string;
dashboardDetails?: DashboardDetails;
questions: (NativeQuestionDetails | StructuredQuestionDetails)[];
cards?: Partial<Card>[];
}): Cypress.Chainable<
Cypress.Response<{
dashboard: Dashboard;
questions: Card;
}>
> => {
// @ts-expect-error - Cypress typings don't account for what happens in then() here
return createDashboard({ name: dashboardName, ...dashboardDetails }).then(
({ body: dashboard }) => {
return cypressWaitAll(
questions.map((query, index) =>
createQuestionAndAddToDashboard(
query,
dashboard.id,
cards ? cards[index] : undefined,
),
),
).then(dashcardResponses => {
const questions = dashcardResponses.map(
dashcardResponse => dashcardResponse.body.card,
);
return {
questions,
dashboard,
};
});
},
);
};
import { createNativeQuestion } from "e2e/support/helpers";
import type { CardId, Dashboard, DashboardCard } from "metabase-types/api";
import type {
CardId,
Dashboard,
DashboardCard,
DashboardId,
} from "metabase-types/api";
import { type DashboardDetails, createDashboard } from "./createDashboard";
import type { NativeQuestionDetails } from "./createQuestion";
......@@ -13,32 +18,42 @@ export const createNativeQuestionAndDashboard = ({
dashboardDetails?: DashboardDetails;
cardDetails?: Partial<DashboardCard>;
}): Cypress.Chainable<
Cypress.Response<DashboardCard> & { questionId: CardId }
Cypress.Response<DashboardCard> & {
dashboardId: DashboardId;
dashboardTabs: Dashboard["tabs"];
questionId: CardId;
}
> => {
const tabs = dashboardDetails?.tabs ?? [];
const defaultTabId = tabs[0]?.id ?? null;
// @ts-expect-error - Cypress typings don't account for what happens in then() here
return createNativeQuestion(questionDetails).then(
({ body: { id: questionId } }) => {
return createDashboard(dashboardDetails).then(
createDashboard(dashboardDetails).then(
({ body: { id: dashboardId } }) => {
return cy
.request<Dashboard>("PUT", `/api/dashboard/${dashboardId}`, {
dashcards: [
{
id: -1,
card_id: questionId,
// Add sane defaults for the dashboard card size
row: 0,
col: 0,
size_x: 11,
size_y: 6,
...cardDetails,
},
],
})
.then(response => ({
...response,
body: response.body.dashcards[0],
questionId,
}));
cy.request("PUT", `/api/dashboard/${dashboardId}`, {
tabs,
dashcards: [
{
id: -1,
card_id: questionId,
dashboard_tab_id: defaultTabId,
// Add sane defaults for the dashboard card size and position
row: 0,
col: 0,
size_x: 11,
size_y: 6,
...cardDetails,
},
],
}).then(response => ({
...response,
dashboardId,
dashboardTabs: response.body.tabs,
body: response.body.dashcards[0],
questionId,
}));
},
);
},
......
Cypress.Commands.add(
"createQuestionAndAddToDashboard",
(query, dashboardId, card) =>
(query.native
? cy.createNativeQuestion(query)
: cy.createQuestion(query)
).then(({ body: { id: card_id } }) =>
import type { Card, DashboardCard, DashboardId } from "metabase-types/api";
import {
type NativeQuestionDetails,
createNativeQuestion,
} from "./createNativeQuestion";
import {
type StructuredQuestionDetails,
createQuestion,
} from "./createQuestion";
export const createQuestionAndAddToDashboard = (
query: NativeQuestionDetails | StructuredQuestionDetails,
dashboardId: DashboardId,
card?: Partial<Card>,
): Cypress.Chainable<Cypress.Response<DashboardCard>> =>
(isNative(query) ? createNativeQuestion(query) : createQuestion(query)).then(
({ body: { id: card_id } }) =>
cy
.request(`/api/dashboard/${dashboardId}`)
.then(({ body: { dashcards } }) =>
......@@ -29,5 +40,10 @@ Cypress.Commands.add(
body: response.body.dashcards.at(-1),
})),
),
),
);
);
const isNative = (
query: NativeQuestionDetails | StructuredQuestionDetails,
): query is NativeQuestionDetails => {
return "native" in query;
};
import _ from "underscore";
Cypress.Commands.add(
"editDashboardCard",
(dashboardCard, updatedProperties) => {
const { id, dashboard_id } = dashboardCard;
import type { Dashboard, DashboardCard } from "metabase-types/api";
const cleanCard = sanitizeCard(dashboardCard);
export const editDashboardCard = (
dashboardCard: DashboardCard,
updatedProperties: Partial<DashboardCard>,
): Cypress.Chainable<Cypress.Response<Dashboard>> => {
const { id, dashboard_id } = dashboardCard;
const updatedCard = Object.assign({}, cleanCard, updatedProperties);
const cleanCard = sanitizeCard(dashboardCard);
cy.log(`Edit dashboard card ${id}`);
cy.request("PUT", `/api/dashboard/${dashboard_id}`, {
dashcards: [updatedCard],
});
},
);
const updatedCard = Object.assign({}, cleanCard, updatedProperties);
cy.log(`Edit dashboard card ${id}`);
return cy.request("PUT", `/api/dashboard/${dashboard_id}`, {
dashcards: [updatedCard],
});
};
/**
* Remove `created_at` and `updated_at` fields from the dashboard card that was previously added to the dashboard.
* We don't want to hard code these fields in the next request that we'll pass the card object to.
*
* @param {Object} card - "Old", or the existing dashboard card.
* @returns {Object}
* @param card - "Old", or the existing dashboard card.
*/
function sanitizeCard(card) {
function sanitizeCard(card: DashboardCard) {
return _.omit(card, ["created_at", "updated_at"]);
}
......@@ -7,6 +7,7 @@ export { createApiKey } from "./createApiKey";
export { createCollection } from "./createCollection";
export { createDashboard } from "./createDashboard";
export type { DashboardDetails } from "./createDashboard";
export { createDashboardWithQuestions } from "./createDashboardWithQuestions";
export { createDashboardWithTabs } from "./createDashboardWithTabs";
export { createModerationReview } from "./createModerationReview";
export { createNativeQuestion } from "./createNativeQuestion";
......@@ -18,10 +19,12 @@ export type {
QuestionDetails,
StructuredQuestionDetails,
} from "./createQuestion";
export { createQuestionAndAddToDashboard } from "./createQuestionAndAddToDashboard";
export { createQuestionAndDashboard } from "./createQuestionAndDashboard";
export { createTimeline } from "./createTimeline";
export { createTimelineEvent } from "./createTimelineEvent";
export { createTimelineWithEvents } from "./createTimelineWithEvents";
export { editDashboardCard } from "./editDashboardCard";
export { getCurrentUser } from "./getCurrentUser";
export { remapDisplayValueToFK } from "./remapDisplayValueToFK";
export { updateDashboardCards } from "./updateDashboardCards";
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment