diff --git a/frontend/src/metabase/dashboards/components/DashboardList.jsx b/frontend/src/metabase/dashboards/components/DashboardList.jsx index 7e8ab788f08034e4386b39ef10369fdb71d97fa9..12b26bc32713a0603ca2de62b63f01400e181843 100644 --- a/frontend/src/metabase/dashboards/components/DashboardList.jsx +++ b/frontend/src/metabase/dashboards/components/DashboardList.jsx @@ -20,7 +20,7 @@ type DashboardListItemProps = { setArchived: (dashId: number, archived: boolean) => void } -class DashboardListItem extends Component { +export class DashboardListItem extends Component { props: DashboardListItemProps state = { diff --git a/frontend/test/dashboards/dashboards.integ.spec.js b/frontend/test/dashboards/dashboards.integ.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..6df983d47973ee0dafef2950506b7a115d4e18e9 --- /dev/null +++ b/frontend/test/dashboards/dashboards.integ.spec.js @@ -0,0 +1,122 @@ +import { + createTestStore, + login +} from "__support__/integrated_tests"; +import { + click, + clickButton, + setInputValue +} from "__support__/enzyme_utils" + +import { mount } from "enzyme"; +import { FETCH_ARCHIVE, FETCH_DASHBOARDS, SET_ARCHIVED, SET_FAVORITED } from "metabase/dashboards/dashboards"; +import CreateDashboardModal from "metabase/components/CreateDashboardModal"; +import { FETCH_DASHBOARD } from "metabase/dashboard/dashboard"; +import { DashboardApi } from "metabase/services"; +import { DashboardListItem } from "metabase/dashboards/components/DashboardList"; +import SearchHeader from "metabase/components/SearchHeader"; +import EmptyState from "metabase/components/EmptyState"; +import Dashboard from "metabase/dashboard/components/Dashboard"; +import ListFilterWidget from "metabase/components/ListFilterWidget"; +import ArchivedItem from "metabase/components/ArchivedItem"; + +describe("dashboards list", () => { + beforeAll(async () => { + await login(); + }) + + afterAll(async () => { + const dashboardIds = (await DashboardApi.list()) + .filter((dash) => !dash.archived) + .map((dash) => dash.id) + + await Promise.all(dashboardIds.map((id) => DashboardApi.update({ id, archived: true }))) + }) + + it("should let you create a dashboard when there are no existing dashboards", async () => { + const store = await createTestStore(); + store.pushPath("/dashboards") + const app = mount(store.getAppContainer()); + + await store.waitForActions([FETCH_DASHBOARDS]) + + // // Create a new dashboard in the empty state (EmptyState react component) + click(app.find(".Button.Button--primary")) + // click(app.find(".Icon.Icon-add")) + + const modal = app.find(CreateDashboardModal) + + setInputValue(modal.find('input[name="name"]'), "Customer Feedback Analysis") + setInputValue(modal.find('input[name="description"]'), "For seeing the usual response times, feedback topics, our response rate, how often customers are directed to our knowledge base instead of providing a customized response") + clickButton(modal.find(".Button--primary")) + + // should navigate to dashboard page + await store.waitForActions(FETCH_DASHBOARD) + expect(app.find(Dashboard).length).toBe(1) + }) + + it("should let you create a dashboard when there are existing dashboards", async () => { + // Return to the dashboard list and check that we see an expected list item + const store = await createTestStore(); + store.pushPath("/dashboards") + const app = mount(store.getAppContainer()); + + await store.waitForActions([FETCH_DASHBOARDS]) + expect(app.find(DashboardListItem).length).toBe(1) + + // Create another one + click(app.find(".Icon.Icon-add")) + const modal2 = app.find(CreateDashboardModal) + setInputValue(modal2.find('input[name="name"]'), "Some Excessively Long Dashboard Title Just For Fun") + setInputValue(modal2.find('input[name="description"]'), "") + clickButton(modal2.find(".Button--primary")) + + await store.waitForActions(FETCH_DASHBOARD) + }) + + it("should let you search form both title and description", async () => { + const store = await createTestStore(); + store.pushPath("/dashboards") + const app = mount(store.getAppContainer()); + await store.waitForActions([FETCH_DASHBOARDS]) + + setInputValue(app.find(SearchHeader).find("input"), "this should produce no results") + expect(app.find(EmptyState).length).toBe(1) + + // Should search from both title and description + setInputValue(app.find(SearchHeader).find("input"), "usual response times") + expect(app.find(DashboardListItem).text()).toMatch(/Customer Feedback Analysis/) + }) + + it("should let you favorite and unfavorite dashboards", async () => { + const store = await createTestStore(); + store.pushPath("/dashboards") + const app = mount(store.getAppContainer()); + await store.waitForActions([FETCH_DASHBOARDS]) + + click(app.find(DashboardListItem).first().find(".Icon-staroutline")); + await store.waitForActions([SET_FAVORITED]) + click(app.find(ListFilterWidget)) + + click(app.find(".TestPopover").find('h4[children="Favorites"]')) + + click(app.find(DashboardListItem).first().find(".Icon-star").first()); + await store.waitForActions([SET_FAVORITED]) + expect(app.find(EmptyState).length).toBe(1) + }) + + it("should let you archive and unarchive dashboards", async () => { + const store = await createTestStore(); + store.pushPath("/dashboards") + const app = mount(store.getAppContainer()); + await store.waitForActions([FETCH_DASHBOARDS]) + + click(app.find(DashboardListItem).first().find(".Icon-archive")); + await store.waitForActions([SET_ARCHIVED]) + + click(app.find(".Icon-viewArchive")) + await store.waitForActions([FETCH_ARCHIVE]) + expect(app.find(ArchivedItem).length).toBeGreaterThan(0) + }); + +}); diff --git a/frontend/test/legacy-selenium/dashboards/dashboards.spec.js b/frontend/test/legacy-selenium/dashboards/dashboards.spec.js deleted file mode 100644 index 673cd3870032a4bbcd61c7d8412aa387df864ad9..0000000000000000000000000000000000000000 --- a/frontend/test/legacy-selenium/dashboards/dashboards.spec.js +++ /dev/null @@ -1,78 +0,0 @@ -/* eslint-disable */ -// NOTE Atte Keinänen 28/8/17: Should be converted to Jest/Enzyme, should be pretty straight-forward. -import { - ensureLoggedIn, - describeE2E -} from "../support/utils"; - -import { - createDashboardInEmptyState, getLatestDashboardUrl, getPreviousDashboardUrl, - incrementDashboardCount, removeCurrentDash -} from "./dashboards.utils" - -jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000; - -describeE2E("dashboards/dashboards", () => { - describe("dashboards list", () => { - beforeEach(async () => { - await ensureLoggedIn(server, driver, "bob@metabase.com", "12341234"); - }); - - // TODO Atte Keinänen 6/22/17: Failing test, disabled until converted to use Jest and Enzyme - xit("should let you create new dashboards, see them, filter them and enter them", async () => { - await d.get("/dashboards"); - await d.screenshot("screenshots/dashboards.png"); - - await createDashboardInEmptyState(); - - // Return to the dashboard list and re-enter the card through the list item - await driver.get(`${server.host}/dashboards`); - await d.select(".Grid-cell > a").wait().click(); - await d.waitUrl(getLatestDashboardUrl()); - - // Create another one - await d.get(`${server.host}/dashboards`); - await d.select(".Icon.Icon-add").wait().click(); - await d.select("#CreateDashboardModal input[name='name']").wait().sendKeys("Some Excessively Long Dashboard Title Just For Fun"); - await d.select("#CreateDashboardModal input[name='description']").wait().sendKeys(""); - await d.select("#CreateDashboardModal .Button--primary").wait().click(); - incrementDashboardCount(); - await d.waitUrl(getLatestDashboardUrl()); - - // Test filtering - await d.get(`${server.host}/dashboards`); - await d.select("input[type='text']").wait().sendKeys("this should produce no results"); - await d.select("img[src*='empty_dashboard']"); - - // Should search from both title and description - await d.select("input[type='text']").wait().clear().sendKeys("usual response times"); - await d.select(".Grid-cell > a").wait().click(); - await d.waitUrl(getPreviousDashboardUrl(1)); - - // Should be able to favorite and unfavorite dashboards - await d.get("/dashboards") - await d.select(".Grid-cell > a .favoriting-button").wait().click(); - - await d.select(":react(ListFilterWidget)").wait().click(); - await d.select(".PopoverBody--withArrow li > h4:contains(Favorites)").wait().click(); - await d.select(".Grid-cell > a .favoriting-button").wait().click(); - await d.select("img[src*='empty_dashboard']"); - - await d.select(":react(ListFilterWidget)").wait().click(); - await d.select(".PopoverBody--withArrow li > h4:contains(All dashboards)").wait().click(); - - // Should be able to archive and unarchive dashboards - // TODO: How to test objects that are in hover? - // await d.select(".Grid-cell > a .archival-button").wait().click(); - // await d.select(".Icon.Icon-viewArchive").wait().click(); - - // Remove the created dashboards to prevent clashes with other tests - await d.get(getPreviousDashboardUrl(1)); - await removeCurrentDash(); - // Should return to dashboard page where only one dash left - await d.select(".Grid-cell > a").wait().click(); - await removeCurrentDash(); - }); - - }); -}); diff --git a/frontend/test/legacy-selenium/dashboards/dashboards.utils.js b/frontend/test/legacy-selenium/dashboards/dashboards.utils.js deleted file mode 100644 index 726e4072fb979f9ea8ed764263920f8ca41fece8..0000000000000000000000000000000000000000 --- a/frontend/test/legacy-selenium/dashboards/dashboards.utils.js +++ /dev/null @@ -1,31 +0,0 @@ -/* eslint-disable */ -export var dashboardCount = 0 -export const incrementDashboardCount = () => { - dashboardCount += 1; -} -export const getLatestDashboardUrl = () => { - return `/dashboard/${dashboardCount}` -} -export const getPreviousDashboardUrl = (nFromLatest) => { - return `/dashboard/${dashboardCount - nFromLatest}` -} - -export const createDashboardInEmptyState = async () => { - await d.get("/dashboards"); - - // Create a new dashboard in the empty state (EmptyState react component) - await d.select(".Button.Button--primary").wait().click(); - await d.select("#CreateDashboardModal input[name='name']").wait().sendKeys("Customer Feedback Analysis"); - await d.select("#CreateDashboardModal input[name='description']").wait().sendKeys("For seeing the usual response times, feedback topics, our response rate, how often customers are directed to our knowledge base instead of providing a customized response"); - await d.select("#CreateDashboardModal .Button--primary").wait().click(); - - incrementDashboardCount(); - await d.waitUrl(getLatestDashboardUrl()); - -} - -export const removeCurrentDash = async () => { - await d.select(".Icon.Icon-pencil").wait().click(); - await d.select(".EditHeader .flex-align-right a:nth-of-type(2)").wait().click(); - await d.select(".Button.Button--danger").wait().click(); -} \ No newline at end of file