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