Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
column-shortcuts.cy.spec.ts 6.78 KiB
import _ from "underscore";

import { SAMPLE_DB_ID } from "e2e/support/cypress_data";
import { SAMPLE_DATABASE } from "e2e/support/cypress_sample_database";
import {
  describeWithSnowplow,
  enterCustomColumnDetails,
  getNotebookStep,
  openNotebook,
  openOrdersTable,
  popover,
  restore,
  visualize,
  createQuestion,
  expectGoodSnowplowEvent,
  resetSnowplow,
  expectNoBadSnowplowEvents,
} from "e2e/support/helpers";

const { PEOPLE, PEOPLE_ID } = SAMPLE_DATABASE;

const DATE_CASES = [
  {
    option: "Hour of day",
    value: "21",
    example: "0, 1",
    expressions: ["get-hour"],
  },
  {
    option: "Day of month",
    value: "11",
    example: "1, 2",
    expressions: ["get-day"],
  },
  {
    option: "Day of week",
    value: "Tuesday",
    example: "Monday, Tuesday",
    expressions: ["day-name", "get-day-of-week"],
  },
  {
    option: "Month of year",
    value: "Feb",
    example: "Jan, Feb",
    expressions: ["month-name", "get-month"],
  },
  {
    option: "Quarter of year",
    value: "Q1",
    example: "Q1, Q2",
    expressions: ["quarter-name", "get-quarter"],
  },
  {
    option: "Year",
    value: "2,025",
    example: "2023, 2024",
    expressions: ["get-year"],
  },
];

const EMAIL_CASES = [
  {
    option: "Domain",
    value: "yahoo",
    example: "example, online",
    expressions: ["domain"],
  },
  {
    option: "Host",
    value: "yahoo.com",
    example: "example.com, online.com",
    expressions: ["host"],
  },
];

const URL_CASES = [
  {
    option: "Domain",
    value: "yahoo",
    example: "example, online",
    expressions: ["domain"],
  },
  {
    option: "Subdomain",
    value: "",
    example: "www, maps",
    expressions: ["subdomain"],
  },
  {
    option: "Host",
    value: "yahoo.com",
    example: "example.com, online.com",
    expressions: ["host"],
  },
];

describeWithSnowplow("extract shortcut", () => {
  beforeEach(() => {
    restore();
    resetSnowplow();

    cy.signInAsAdmin();
  });

  afterEach(() => {
    expectNoBadSnowplowEvents();
  });

  describe("date columns", () => {
    describe("should add a date expression for each option", () => {
      DATE_CASES.forEach(({ option, value, example, expressions }) => {
        it(option, () => {
          openOrdersTable({ limit: 1 });
          extractColumnAndCheck({
            column: "Created At",
            option,
            value,
            example,
          });
          expectGoodSnowplowEvent({
            event: "column_extract_via_plus_modal",
            custom_expressions_used: expressions,
            database_id: SAMPLE_DB_ID,
          });
        });
      });
    });

    it("should handle duplicate expression names", () => {
      openOrdersTable({ limit: 1 });
      extractColumnAndCheck({
        column: "Created At",
        option: "Hour of day",
        newColumn: "Hour of day",
      });
      extractColumnAndCheck({
        column: "Created At",
        option: "Hour of day",
        newColumn: "Hour of day_2",
      });
    });

    it("should be able to modify the expression in the notebook editor", () => {
      openOrdersTable({ limit: 1 });
      extractColumnAndCheck({
        column: "Created At",
        option: "Year",
        value: "2,025",
      });
      openNotebook();
      getNotebookStep("expression").findByText("Year").click();
      enterCustomColumnDetails({ name: "custom formula", formula: "+ 2" });
      popover().button("Update").click();
      visualize();
      cy.findByRole("gridcell", { name: "2,027" }).should("be.visible");
    });
  });

  describe("email columns", () => {
    beforeEach(() => {
      restore();
      cy.signInAsAdmin();
    });

    EMAIL_CASES.forEach(({ option, value, example, expressions }) => {
      it(option, () => {
        createQuestion(
          {
            query: {
              "source-table": PEOPLE_ID,
              limit: 1,
            },
          },
          {
            visitQuestion: true,
          },
        );

        extractColumnAndCheck({
          column: "Email",
          option,
          value,
          example,
        });
        expectGoodSnowplowEvent({
          event: "column_extract_via_plus_modal",
          custom_expressions_used: expressions,
          database_id: SAMPLE_DB_ID,
        });
      });
    });
  });

  describe("url columns", () => {
    beforeEach(() => {
      restore();
      cy.signInAsAdmin();

      // Make the Email column a URL column for these tests, to avoid having to create a new model
      cy.request("PUT", `/api/field/${PEOPLE.EMAIL}`, {
        semantic_type: "type/URL",
      });
    });

    URL_CASES.forEach(({ option, value, example, expressions }) => {
      it(option, () => {
        createQuestion(
          {
            query: {
              "source-table": PEOPLE_ID,
              limit: 1,
            },
          },
          {
            visitQuestion: true,
          },
        );

        extractColumnAndCheck({
          column: "Email",
          option,
          value,
          example,
        });
        expectGoodSnowplowEvent({
          event: "column_extract_via_plus_modal",
          custom_expressions_used: expressions,
          database_id: SAMPLE_DB_ID,
        });
      });
    });
  });

  it("should disable the scroll behaviour after it has been rendered", () => {
    createQuestion(
      {
        query: {
          "source-table": PEOPLE_ID,
          limit: 1,
        },
      },
      {
        visitQuestion: true,
      },
    );

    extractColumnAndCheck({
      column: "Email",
      option: "Host",
    });

    cy.get("#main-data-grid").scrollTo("left", { duration: 2000 / 60 });

    cy.findAllByRole("columnheader", { name: "ID" })
      .should("be.visible")
      .click();

    // Change sort direction
    popover().findAllByRole("button").first().click();

    // ID should still be visible (ie. no scrolling to the end should have happened)
    cy.findAllByRole("columnheader", { name: "ID" }).should("be.visible");
  });
});

function extractColumnAndCheck({
  column,
  option,
  newColumn = option,
  value,
  example,
}: {
  column: string;
  option: string;
  value?: string;
  example?: string;
  newColumn?: string;
}) {
  const requestAlias = _.uniqueId("dataset");
  cy.intercept("POST", "/api/dataset").as(requestAlias);
  cy.findByLabelText("Add column").click();

  popover().findByText("Extract part of column").click();
  popover().findAllByText(column).first().click();

  if (example) {
    popover().findByText(option).parent().should("contain", example);
  }

  popover().findByText(option).click();

  cy.wait(`@${requestAlias}`);

  cy.findAllByRole("columnheader")
    .last()
    .should("have.text", newColumn)
    .should("be.visible");

  cy.findAllByRole("columnheader").last().should("have.text", newColumn);
  if (value) {
    cy.findByRole("gridcell", { name: value }).should("be.visible");
  }
}