From b8e9d9db095492a9cd0e396863d42128e4821b25 Mon Sep 17 00:00:00 2001
From: Jessica DeWitt <58329466+Opalevanescence@users.noreply.github.com>
Date: Wed, 29 Jul 2020 23:27:42 -0500
Subject: [PATCH] E2e to cy/port/metrics (#13028)

* Repro/universal search (#12957)

* repro complete

* Added issue #

* prettier

* Deleted change of table permissions

* done porting metrics, except two qs

* deleted 'metrics.e2e.spec.js'

* edit to comment

* loading problem

* finished metrics
---
 .../metabase/reference/databases.e2e.spec.js  | 249 -----------------
 .../metabase/reference/metrics.e2e.spec.js    | 143 ----------
 .../admin/datamodel/metrics.cy.spec.js        | 254 +++++++++++-------
 3 files changed, 158 insertions(+), 488 deletions(-)
 delete mode 100644 frontend/test/metabase/reference/databases.e2e.spec.js
 delete mode 100644 frontend/test/metabase/reference/metrics.e2e.spec.js

diff --git a/frontend/test/metabase/reference/databases.e2e.spec.js b/frontend/test/metabase/reference/databases.e2e.spec.js
deleted file mode 100644
index 4a232f99466..00000000000
--- a/frontend/test/metabase/reference/databases.e2e.spec.js
+++ /dev/null
@@ -1,249 +0,0 @@
-import { useSharedAdminLogin, createTestStore } from "__support__/e2e";
-import { click, clickButton, setInputValue } from "__support__/enzyme";
-
-import React from "react";
-import { mount } from "enzyme";
-
-import { CardApi, MetabaseApi } from "metabase/services";
-
-import {
-  FETCH_DATABASE_METADATA,
-  FETCH_REAL_DATABASES,
-} from "metabase/redux/metadata";
-
-import { END_LOADING } from "metabase/reference/reference";
-
-import DatabaseListContainer from "metabase/reference/databases/DatabaseListContainer";
-import DatabaseDetailContainer from "metabase/reference/databases/DatabaseDetailContainer";
-import TableListContainer from "metabase/reference/databases/TableListContainer";
-import TableDetailContainer from "metabase/reference/databases/TableDetailContainer";
-import TableQuestionsContainer from "metabase/reference/databases/TableQuestionsContainer";
-import FieldListContainer from "metabase/reference/databases/FieldListContainer";
-import FieldDetailContainer from "metabase/reference/databases/FieldDetailContainer";
-
-import DatabaseList from "metabase/reference/databases/DatabaseList";
-import List from "metabase/components/List";
-import ListItem from "metabase/components/ListItem";
-import ReferenceHeader from "metabase/reference/components/ReferenceHeader";
-import AdminAwareEmptyState from "metabase/components/AdminAwareEmptyState";
-import UsefulQuestions from "metabase/reference/components/UsefulQuestions";
-import Detail from "metabase/reference/components/Detail";
-import QueryButton from "metabase/components/QueryButton";
-import { INITIALIZE_QB, QUERY_COMPLETED } from "metabase/query_builder/actions";
-import { getQuestion } from "metabase/query_builder/selectors";
-import { delay } from "metabase/lib/promise";
-
-describe("The Reference Section", () => {
-  // Test data
-  const cardDef = {
-    name: "A card",
-    display: "scalar",
-    dataset_query: {
-      database: 1,
-      type: "query",
-      query: { "source-table": 1, aggregation: [["count"]] },
-    },
-    visualization_settings: {},
-  };
-
-  // Scaffolding
-  beforeAll(async () => {
-    useSharedAdminLogin();
-  });
-
-  describe("The Data Reference for the Sample Database", async () => {
-    // database list
-    it("should see databases", async () => {
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/");
-      const container = mount(
-        store.connectContainer(<DatabaseListContainer />),
-      );
-      await store.waitForActions([FETCH_REAL_DATABASES, END_LOADING]);
-
-      expect(container.find(ReferenceHeader).length).toBe(1);
-      expect(container.find(DatabaseList).length).toBe(1);
-      expect(container.find(AdminAwareEmptyState).length).toBe(0);
-
-      expect(container.find(List).length).toBe(1);
-      expect(container.find(ListItem).length).toBeGreaterThanOrEqual(1);
-    });
-
-    // database list
-    it("should not see saved questions in the database list", async () => {
-      const card = await CardApi.create(cardDef);
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/");
-      const container = mount(
-        store.connectContainer(<DatabaseListContainer />),
-      );
-      await store.waitForActions([FETCH_REAL_DATABASES, END_LOADING]);
-
-      expect(container.find(ReferenceHeader).length).toBe(1);
-      expect(container.find(DatabaseList).length).toBe(1);
-      expect(container.find(AdminAwareEmptyState).length).toBe(0);
-
-      expect(container.find(List).length).toBe(1);
-      expect(container.find(ListItem).length).toBe(1);
-
-      expect(card.name).toBe(cardDef.name);
-
-      await CardApi.delete({ cardId: card.id });
-    });
-
-    // database detail
-    it("should see a the detail view for the sample database", async () => {
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/1");
-      mount(store.connectContainer(<DatabaseDetailContainer />));
-      await store.waitForActions([FETCH_DATABASE_METADATA, END_LOADING]);
-    });
-
-    // database update
-    it("should update the sample database", async () => {
-      // create a new db by cloning #1
-      const d1 = await MetabaseApi.db_get({ dbId: 1 });
-      const { id } = await MetabaseApi.db_create(d1);
-
-      // go to that db's reference page
-      const store = await createTestStore();
-      store.pushPath(`/reference/databases/${id}`);
-      const app = mount(store.connectContainer(<DatabaseDetailContainer />));
-      await store.waitForActions([FETCH_DATABASE_METADATA, END_LOADING]);
-
-      // switch to edit view
-      const editButton = app.find(".Button");
-
-      clickButton(editButton);
-
-      // update "caveats" and save
-      const textarea = app
-        .find(Detail)
-        .at(2)
-        .find("textarea");
-      setInputValue(textarea, "v important thing");
-
-      const doneButton = app.find(".Button--primary");
-
-      clickButton(doneButton);
-      await store.waitForActions(END_LOADING);
-      // unfortunately this is required?
-      await delay(200);
-
-      // check that the field was updated
-      const savedText = app
-        .find(Detail)
-        .at(2)
-        .find("span")
-        .at(1)
-        .text();
-
-      expect(savedText).toBe("v important thing");
-
-      // clean up
-      await MetabaseApi.db_delete({ dbId: id });
-    });
-
-    // table list
-    it("should see the 4 tables in the sample database", async () => {
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/1/tables");
-      mount(store.connectContainer(<TableListContainer />));
-      await store.waitForActions([FETCH_DATABASE_METADATA, END_LOADING]);
-    });
-    // table detail
-
-    it("should see the Orders table", async () => {
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/1/tables/1");
-      mount(store.connectContainer(<TableDetailContainer />));
-      await store.waitForActions([FETCH_DATABASE_METADATA, END_LOADING]);
-    });
-
-    it("should see the Reviews table", async () => {
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/1/tables/2");
-      mount(store.connectContainer(<TableDetailContainer />));
-      await store.waitForActions([FETCH_DATABASE_METADATA, END_LOADING]);
-    });
-    it("should see the Products table", async () => {
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/1/tables/3");
-      mount(store.connectContainer(<TableDetailContainer />));
-      await store.waitForActions([FETCH_DATABASE_METADATA, END_LOADING]);
-    });
-    it("should see the People table", async () => {
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/1/tables/4");
-      mount(store.connectContainer(<TableDetailContainer />));
-      await store.waitForActions([FETCH_DATABASE_METADATA, END_LOADING]);
-    });
-    // field list
-    it("should see the fields for the orders table", async () => {
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/1/tables/1/fields");
-      mount(store.connectContainer(<FieldListContainer />));
-      await store.waitForActions([FETCH_DATABASE_METADATA, END_LOADING]);
-    });
-    it("should see the questions for the orders tables", async () => {
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/1/tables/1/questions");
-      mount(store.connectContainer(<TableQuestionsContainer />));
-      await store.waitForActions([FETCH_DATABASE_METADATA, END_LOADING]);
-
-      const card = await CardApi.create(cardDef);
-
-      expect(card.name).toBe(cardDef.name);
-
-      await CardApi.delete({ cardId: card.id });
-    });
-
-    // field detail
-
-    it("should see the orders created_at timestamp field", async () => {
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/1/tables/1/fields/1");
-      mount(store.connectContainer(<FieldDetailContainer />));
-      await store.waitForActions([FETCH_DATABASE_METADATA, END_LOADING]);
-    });
-
-    it("should let you open a potentially useful question for created_at field without errors", async () => {
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/1/tables/1/fields/1");
-
-      const app = mount(store.getAppContainer());
-
-      await store.waitForActions([FETCH_DATABASE_METADATA, END_LOADING]);
-      const fieldDetails = app.find(FieldDetailContainer);
-      expect(fieldDetails.length).toBe(1);
-
-      const usefulQuestionLink = fieldDetails
-        .find(UsefulQuestions)
-        .find(QueryButton)
-        .first()
-        .find("a");
-      expect(usefulQuestionLink.text()).toBe(
-        "Number of Orders grouped by Created At",
-      );
-      click(usefulQuestionLink);
-
-      await store.waitForActions([INITIALIZE_QB, QUERY_COMPLETED]);
-
-      const qbQuery = getQuestion(store.getState()).query();
-
-      // the granularity/subdimension should be applied correctly to the breakout
-      expect(JSON.stringify(qbQuery.breakouts())).toEqual(
-        JSON.stringify([
-          ["datetime-field", ["field-id", 1], "month"], // depends on the date range
-        ]),
-      );
-    });
-
-    it("should see the orders id field", async () => {
-      const store = await createTestStore();
-      store.pushPath("/reference/databases/1/tables/1/fields/25");
-      mount(store.connectContainer(<FieldDetailContainer />));
-      await store.waitForActions([FETCH_DATABASE_METADATA, END_LOADING]);
-    });
-  });
-});
diff --git a/frontend/test/metabase/reference/metrics.e2e.spec.js b/frontend/test/metabase/reference/metrics.e2e.spec.js
deleted file mode 100644
index a6b8a89865a..00000000000
--- a/frontend/test/metabase/reference/metrics.e2e.spec.js
+++ /dev/null
@@ -1,143 +0,0 @@
-import { useSharedAdminLogin, createTestStore } from "__support__/e2e";
-
-import React from "react";
-import { mount } from "enzyme";
-import { assocIn } from "icepick";
-
-import { CardApi, MetricApi } from "metabase/services";
-
-import {
-  FETCH_METRICS,
-  FETCH_METRIC_TABLE,
-  FETCH_METRIC_REVISIONS,
-} from "metabase/redux/metadata";
-
-import { FETCH_GUIDE } from "metabase/reference/reference";
-
-import MetricListContainer from "metabase/reference/metrics/MetricListContainer";
-import MetricDetailContainer from "metabase/reference/metrics/MetricDetailContainer";
-import MetricQuestionsContainer from "metabase/reference/metrics/MetricQuestionsContainer";
-import MetricRevisionsContainer from "metabase/reference/metrics/MetricRevisionsContainer";
-
-// NOTE: database/table_id/source-table are hard-coded, this might be a problem at some point
-
-describe("The Reference Section", () => {
-  // Test data
-  const metricDef = {
-    name: "A Metric",
-    description: "I did it!",
-    table_id: 1,
-    show_in_getting_started: true,
-    definition: { aggregation: [["count"]] },
-  };
-
-  const anotherMetricDef = {
-    name: "Another Metric",
-    description: "I did it again!",
-    table_id: 1,
-    show_in_getting_started: true,
-    definition: { aggregation: [["count"]] },
-  };
-
-  const metricCardDef = {
-    name: "A card",
-    display: "scalar",
-    dataset_query: {
-      database: 1,
-      type: "query",
-      query: { "source-table": 1, aggregation: [["metric", 1]] },
-    },
-    visualization_settings: {},
-  };
-
-  // Scaffolding
-  beforeAll(async () => {
-    useSharedAdminLogin();
-  });
-
-  describe("The Metrics section of the Data Reference", async () => {
-    describe("Empty State", async () => {
-      it("Should show no metrics in the list", async () => {
-        const store = await createTestStore();
-        store.pushPath("/reference/metrics");
-        mount(store.connectContainer(<MetricListContainer />));
-        await store.waitForActions([FETCH_METRICS]);
-      });
-    });
-
-    describe("With Metrics State", async () => {
-      const metricIds = [];
-
-      beforeAll(async () => {
-        // Create some metrics to have something to look at
-        const metric = await MetricApi.create(metricDef);
-        const metric2 = await MetricApi.create(anotherMetricDef);
-
-        metricIds.push(metric.id);
-        metricIds.push(metric2.id);
-      });
-
-      afterAll(async () => {
-        // Delete the guide we created
-        // remove the metrics we created
-        // This is a bit messy as technically these are just archived
-        for (const id of metricIds) {
-          await MetricApi.delete({ metricId: id, revision_message: "Please" });
-        }
-      });
-      // metrics list
-      it("Should show no metrics in the list", async () => {
-        const store = await createTestStore();
-        store.pushPath("/reference/metrics");
-        mount(store.connectContainer(<MetricListContainer />));
-        await store.waitForActions([FETCH_METRICS]);
-      });
-      // metric detail
-      it("Should show the metric detail view for a specific id", async () => {
-        const store = await createTestStore();
-        store.pushPath("/reference/metrics/" + metricIds[0]);
-        mount(store.connectContainer(<MetricDetailContainer />));
-        await store.waitForActions([FETCH_METRIC_TABLE, FETCH_GUIDE]);
-      });
-      // metrics questions
-      it("Should show no questions based on a new metric", async () => {
-        const store = await createTestStore();
-        store.pushPath("/reference/metrics/" + metricIds[0] + "/questions");
-        mount(store.connectContainer(<MetricQuestionsContainer />));
-        await store.waitForActions([FETCH_METRICS, FETCH_METRIC_TABLE]);
-      });
-      // metrics revisions
-      it("Should show revisions", async () => {
-        const store = await createTestStore();
-        store.pushPath("/reference/metrics/" + metricIds[0] + "/revisions");
-        mount(store.connectContainer(<MetricRevisionsContainer />));
-        await store.waitForActions([FETCH_METRICS, FETCH_METRIC_REVISIONS]);
-      });
-
-      it("Should see a newly asked question in its questions list", async () => {
-        let card;
-        try {
-          const cardDef = assocIn(
-            metricCardDef,
-            ["dataset_query", "query", "aggregation", 0, 1],
-            metricIds[0],
-          );
-          card = await CardApi.create(cardDef);
-          expect(card.name).toBe(metricCardDef.name);
-
-          // see that there is a new question on the metric's questions page
-          const store = await createTestStore();
-
-          store.pushPath("/reference/metrics/" + metricIds[0] + "/questions");
-          mount(store.connectContainer(<MetricQuestionsContainer />));
-          await store.waitForActions([FETCH_METRICS, FETCH_METRIC_TABLE]);
-        } finally {
-          if (card) {
-            // even if the code above results in an exception, try to delete the question
-            await CardApi.delete({ cardId: card.id });
-          }
-        }
-      });
-    });
-  });
-});
diff --git a/frontend/test/metabase/scenarios/admin/datamodel/metrics.cy.spec.js b/frontend/test/metabase/scenarios/admin/datamodel/metrics.cy.spec.js
index 47fc9772a18..69ef7020c0d 100644
--- a/frontend/test/metabase/scenarios/admin/datamodel/metrics.cy.spec.js
+++ b/frontend/test/metabase/scenarios/admin/datamodel/metrics.cy.spec.js
@@ -7,103 +7,165 @@ describe("scenarios > admin > datamodel > metrics", () => {
     cy.viewport(1400, 860);
   });
 
-  it("should create a metric", () => {
-    cy.visit("/admin");
-    cy.contains("Data Model").click();
-    cy.contains("Metrics").click();
-    cy.contains("New metric").click();
-    cy.contains("Select a table").click();
-    popover()
-      .contains("Orders")
-      .click({ force: true }); // this shouldn't be needed, but there were issues with reordering as loads happeend
-
-    cy.url().should("match", /metric\/create$/);
-    cy.contains("Create Your Metric");
-
-    // filter to orders with total under 100
-    cy.contains("Add filters").click();
-    cy.contains("Total").click();
-    cy.contains("Equal to").click();
-    cy.contains("Less than").click();
-    cy.get('[placeholder="Enter a number"]').type("100");
-    popover()
-      .contains("Add filter")
-      .click();
-
-    //
-    cy.contains("Result: 12765");
-
-    // fill in name/description
-    cy.get('[name="name"]').type("orders <100");
-    cy.get('[name="description"]').type(
-      "Count of orders with a total under $100.",
-    );
-
-    // saving bounces you back and you see new metric in the list
-    cy.contains("Save changes").click();
-    cy.url().should("match", /datamodel\/metrics$/);
-    cy.contains("orders <100");
-    cy.contains("Count, Filtered by Total");
+  describe("with no metrics", () => {
+    it("should show no metrics in the list", () => {
+      cy.visit("/admin/datamodel/metrics");
+      cy.findByText(
+        "Create metrics to add them to the Summarize dropdown in the query builder",
+      );
+    });
+
+    it("should show how to create metrics", () => {
+      cy.visit("/reference/metrics");
+      cy.findByText(
+        "Metrics are the official numbers that your team cares about",
+      );
+      cy.findByText("Learn how to create metrics");
+    });
   });
 
-  it("should update that metric", () => {
-    cy.visit("/admin");
-    cy.contains("Data Model").click();
-    cy.contains("Metrics").click();
-
-    cy.contains("orders <100")
-      .parent()
-      .parent()
-      .find(".Icon-ellipsis")
-      .click();
-    cy.contains("Edit Metric").click();
-
-    // update the filter from "< 100" to "> 10"
-    cy.url().should("match", /metric\/1$/);
-    cy.contains("Edit Your Metric");
-    cy.contains(/Total\s+is less than/).click();
-    popover()
-      .contains("Less than")
-      .click();
-    popover()
-      .contains("Greater than")
-      .click();
-    popover()
-      .find("input")
-      .type("{SelectAll}10");
-    popover()
-      .contains("Update filter")
-      .click();
-
-    // confirm that the preview updated
-    cy.contains("Result: 18703");
-
-    // update name and description, set a revision note, and save the update
-    cy.get('[name="name"]')
-      .clear()
-      .type("orders >10");
-    cy.get('[name="description"]')
-      .clear()
-      .type("Count of orders with a total over $10.");
-    cy.get('[name="revision_message"]').type("time for a change");
-    cy.contains("Save changes").click();
-
-    // get redirected to previous page and see the new metric name
-    cy.url().should("match", /datamodel\/metrics$/);
-    cy.contains("orders >10");
-
-    // clean up
-    cy.contains("orders >10")
-      .parent()
-      .parent()
-      .find(".Icon-ellipsis")
-      .click();
-    cy.contains("Retire Metric").click();
-    modal()
-      .find("textarea")
-      .type("delete it");
-    modal()
-      .contains("button", "Retire")
-      .click();
+  describe("with metrics", () => {
+    before(() => {
+      // CREATE METRIC
+      signInAsAdmin();
+      cy.visit("/admin");
+      cy.contains("Data Model").click();
+      cy.contains("Metrics").click();
+      cy.contains("New metric").click();
+      cy.contains("Select a table").click();
+      popover()
+        .contains("Orders")
+        .click({ force: true }); // this shouldn't be needed, but there were issues with reordering as loads happeend
+
+      cy.url().should("match", /metric\/create$/);
+      cy.contains("Create Your Metric");
+
+      // filter to orders with total under 100
+      cy.contains("Add filters").click();
+      cy.contains("Total").click();
+      cy.contains("Equal to").click();
+      cy.contains("Less than").click();
+      cy.get('[placeholder="Enter a number"]').type("100");
+      popover()
+        .contains("Add filter")
+        .click();
+
+      //
+      cy.contains("Result: 12765");
+
+      // fill in name/description
+      cy.get('[name="name"]').type("orders <100");
+      cy.get('[name="description"]').type(
+        "Count of orders with a total under $100.",
+      );
+
+      // saving bounces you back and you see new metric in the list
+      cy.contains("Save changes").click();
+      cy.url().should("match", /datamodel\/metrics$/);
+      cy.contains("orders <100");
+      cy.contains("Count, Filtered by Total");
+    });
+
+    it("should show no questions based on a new metric", () => {
+      cy.visit("/reference/metrics/1/questions");
+      cy.findAllByText("Questions about orders <100");
+      cy.findByText("Loading...");
+      cy.findByText("Loading...").should("not.exist");
+      cy.findByText(
+        "Questions about this metric will appear here as they're added",
+      );
+    });
+
+    it("should see a newly asked question in its questions list", () => {
+      // Ask a new qustion
+      cy.visit("/reference/metrics/1/questions");
+      cy.get(".full")
+        .find(".Button")
+        .click();
+      cy.findByText("Filter").click();
+      cy.findByText("Total").click();
+      cy.findByText("Equal to").click();
+      cy.findByText("Greater than").click();
+      cy.findByPlaceholderText("Enter a number").type("50");
+      cy.findByText("Add filter").click();
+      cy.findByText("Save").click();
+      cy.findAllByText("Save")
+        .last()
+        .click();
+      cy.findByText("Not now").click();
+
+      // Check the list
+      cy.visit("/reference/metrics/1/questions");
+      cy.findByText("Our analysis").should("not.exist");
+      cy.findAllByText("Questions about orders <100");
+      cy.findByText("Orders, orders <100, Filtered by Total");
+    });
+
+    it("should show the metric detail view for a specific id", () => {
+      cy.visit("/admin/datamodel/metric/1");
+      cy.findByText("Edit Your Metric");
+      cy.findByText("Preview");
+    });
+
+    it("should update that metric", () => {
+      cy.visit("/admin");
+      cy.contains("Data Model").click();
+      cy.contains("Metrics").click();
+
+      cy.contains("orders <100")
+        .parent()
+        .parent()
+        .find(".Icon-ellipsis")
+        .click();
+      cy.contains("Edit Metric").click();
+
+      // update the filter from "< 100" to "> 10"
+      cy.url().should("match", /metric\/1$/);
+      cy.contains("Edit Your Metric");
+      cy.contains(/Total\s+is less than/).click();
+      popover()
+        .contains("Less than")
+        .click();
+      popover()
+        .contains("Greater than")
+        .click();
+      popover()
+        .find("input")
+        .type("{SelectAll}10");
+      popover()
+        .contains("Update filter")
+        .click();
+
+      // confirm that the preview updated
+      cy.contains("Result: 18703");
+
+      // update name and description, set a revision note, and save the update
+      cy.get('[name="name"]')
+        .clear()
+        .type("orders >10");
+      cy.get('[name="description"]')
+        .clear()
+        .type("Count of orders with a total over $10.");
+      cy.get('[name="revision_message"]').type("time for a change");
+      cy.contains("Save changes").click();
+
+      // get redirected to previous page and see the new metric name
+      cy.url().should("match", /datamodel\/metrics$/);
+      cy.contains("orders >10");
+
+      // clean up
+      cy.contains("orders >10")
+        .parent()
+        .parent()
+        .find(".Icon-ellipsis")
+        .click();
+      cy.contains("Retire Metric").click();
+      modal()
+        .find("textarea")
+        .type("delete it");
+      modal()
+        .contains("button", "Retire")
+        .click();
+    });
   });
 });
-- 
GitLab