Skip to content
Snippets Groups Projects
Commit c7e18011 authored by Atte Keinänen's avatar Atte Keinänen
Browse files

Run backend with empty db, add incomplete test suite

parent 5385d8fa
Branches
Tags
No related merge requests found
......@@ -9,7 +9,7 @@ import { SessionApi, SettingsApi } from "metabase/services";
import { loadCurrentUser } from "./user";
import { getUserIsAdmin } from "metabase/selectors/user";
const REFRESH_SITE_SETTINGS = "metabase/settings/REFRESH_SITE_SETTINGS";
export const REFRESH_SITE_SETTINGS = "metabase/settings/REFRESH_SITE_SETTINGS";
const REFRESH_SETTINGS_LIST = "metabase/settings/REFRESH_SETTINGS_LIST";
export const refreshSiteSettings = createThunkAction(REFRESH_SITE_SETTINGS, () =>
......
......@@ -94,6 +94,7 @@ import CardComparison from "metabase/xray/containers/CardComparison.jsx";
import getAdminPermissionsRoutes from "metabase/admin/permissions/routes.jsx";
import PeopleListingApp from "metabase/admin/people/containers/PeopleListingApp.jsx";
import GroupsListingApp from "metabase/admin/people/containers/GroupsListingApp.jsx";
import GroupDetailApp from "metabase/admin/people/containers/GroupDetailApp.jsx";
......
......@@ -53,8 +53,8 @@ export async function login() {
)
}
if (process.env.SHARED_LOGIN_SESSION_ID) {
loginSession = { id: process.env.SHARED_LOGIN_SESSION_ID }
if (isTestFixtureDatabase() && process.env.TEST_FIXTURE_SHARED_LOGIN_SESSION_ID) {
loginSession = { id: process.env.TEST_FIXTURE_SHARED_LOGIN_SESSION_ID }
} else {
loginSession = await SessionApi.create({ username: "bob@metabase.com", password: "12341234"});
}
......@@ -92,6 +92,16 @@ export async function whenOffline(callWhenOffline) {
});
}
export function switchToPlainDatabase() {
api.basename = process.env.PLAIN_BACKEND_HOST;
}
export function switchToTestFixtureDatabase() {
api.basename = process.env.TEST_FIXTURE_BACKEND_HOST;
}
const isPlainDatabase = () => api.basename === process.env.PLAIN_BACKEND_HOST;
const isTestFixtureDatabase = () => api.basename === process.env.TEST_FIXTURE_BACKEND_HOST;
/**
* Creates an augmented Redux store for testing the whole app including browser history manipulation. Includes:
* - A simulated browser history that is used by react-router
......@@ -119,10 +129,27 @@ export const createTestStore = async ({ publicApp = false, embedApp = false } =
return store;
}
/**
* History state change events you can listen to in tests
*/
export const BROWSER_HISTORY_PUSH = `integrated-tests/BROWSER_HISTORY_PUSH`
export const BROWSER_HISTORY_REPLACE = `integrated-tests/BROWSER_HISTORY_REPLACE`
export const BROWSER_HISTORY_POP = `integrated-tests/BROWSER_HISTORY_POP`
const testStoreEnhancer = (createStore, history, getRoutes) => {
return (...args) => {
const store = createStore(...args);
// Because we don't have an access to internal actions of react-router,
// let's create synthetic actions from actual history changes instead
history.listen((location) => {
store.dispatch({
type: `integrated-tests/BROWSER_HISTORY_${location.action}`,
location: location
})
});
const testStoreExtensions = {
_originalDispatch: store.dispatch,
_onActionDispatched: null,
......@@ -172,6 +199,7 @@ const testStoreEnhancer = (createStore, history, getRoutes) => {
if (allActionsAreTriggered()) {
// Short-circuit if all action types are already in the history of dispatched actions
store._latestDispatchedActions = getRemainingActions();
return Promise.resolve();
} else {
return new Promise((resolve, reject) => {
......@@ -206,6 +234,10 @@ const testStoreEnhancer = (createStore, history, getRoutes) => {
* Logs the actions that have been dispatched so far
*/
debug: () => {
if (store._onActionDispatched) {
console.log("You have `store.waitForActions(...)` still in progress – have you forgotten to prepend `await` to the method call?")
}
console.log(
chalk.bold("Dispatched actions since last call of `waitForActions`:\n") +
(store._latestDispatchedActions.map(store._formatDispatchedAction).join("\n") || "No dispatched actions") +
......@@ -349,8 +381,9 @@ api._makeRequest = async (method, url, headers, requestBody, data, options) => {
}
// Set the correct base url to metabase/lib/api module
if (process.env.E2E_HOST) {
api.basename = process.env.E2E_HOST;
if (process.env.TEST_FIXTURE_BACKEND_HOST && process.env.TEST_FIXTURE_BACKEND_HOST) {
// Default to the test db fixture
api.basename = process.env.TEST_FIXTURE_BACKEND_HOST;
} else {
console.log(
'Please use `yarn run test-integrated` or `yarn run test-integrated-watch` for running integration tests.'
......
......@@ -48,7 +48,6 @@ describe('dashboard list', () => {
const wrapper = app.find(DatabaseListApp)
expect(wrapper.length).toEqual(1)
})
describe('adds', () => {
......
......@@ -6,10 +6,14 @@ import { spawn } from "child_process";
// use require for BackendResource to run it after the mock afterAll has been set
const BackendResource = require("./legacy-selenium/support/backend.js").BackendResource
const server = BackendResource.get({});
const apiHost = process.env.E2E_HOST || server.host;
const login = async () => {
const serverWithTestDbFixture = BackendResource.get({});
const testFixtureBackendHost = serverWithTestDbFixture.host;
const serverWithPlainDb = BackendResource.get({ dbKey: "" });
const plainBackendHost = serverWithPlainDb.host;
const login = async (apiHost) => {
const loginFetchOptions = {
method: "POST",
headers: new Headers({
......@@ -38,13 +42,18 @@ const login = async () => {
}
const init = async() => {
await BackendResource.start(server)
const sharedLoginSession = await login()
await Promise.all([
BackendResource.start(serverWithTestDbFixture),
BackendResource.start(serverWithPlainDb)
])
const sharedLoginSession = await login(testFixtureBackendHost)
const env = {
...process.env,
"E2E_HOST": apiHost,
"SHARED_LOGIN_SESSION_ID": sharedLoginSession.id
"TEST_FIXTURE_BACKEND_HOST": testFixtureBackendHost,
"PLAIN_BACKEND_HOST": plainBackendHost,
"TEST_FIXTURE_SHARED_LOGIN_SESSION_ID": sharedLoginSession.id
}
const userArgs = process.argv.slice(2);
const jestProcess = spawn(
......@@ -63,7 +72,7 @@ const init = async() => {
const cleanup = async (exitCode = 0) => {
await jasmineAfterAllCleanup();
await BackendResource.stop(server);
await BackendResource.stop(serverWithTestDbFixture);
process.exit(exitCode);
}
......
import {
createTestStore,
switchToPlainDatabase,
BROWSER_HISTORY_REPLACE
} from "__support__/integrated_tests";
import {
click,
clickButton,
setInputValue
} from "__support__/enzyme_utils";
import { mount } from "enzyme";
import { delay } from "metabase/lib/promise"
import Setup from "metabase/setup/components/Setup";
import { SET_ACTIVE_STEP } from "metabase/setup/actions";
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;
describe("setup wizard", () => {
let store = null;
let app = null;
beforeAll(async () => {
switchToPlainDatabase();
store = await createTestStore()
store.pushPath("/");
app = mount(store.getAppContainer())
})
it("should start from the welcome page", async () => {
await store.waitForActions([BROWSER_HISTORY_REPLACE])
expect(store.getPath()).toBe("/setup")
expect(app.find(Setup).find("h1").text()).toBe("Welcome to Metabase")
});
it("should allow you to create an account", async () => {
clickButton(app.find(".Button.Button--primary"))
await store.waitForActions([SET_ACTIVE_STEP])
const nextButton = app.find('button[children="Next"]')
expect(nextButton.props().disabled).toBe(true)
setInputValue(app.find('input[name="firstName"]'), 'Testy')
setInputValue(app.find('input[name="lastName"]'), 'McTestface')
setInputValue(app.find('input[name="email"]'), 'testy@metabase.com')
// test first with a weak password
setInputValue(app.find('input[name="password"]'), '12341234')
setInputValue(app.find('input[name="passwordConfirm"]'), '12341234')
setInputValue(app.find('input[name="siteName"]'), '1234')
// the form shouldn't be valid yet
expect(nextButton.props().disabled).toBe(true)
// then with a strong password, generated with my beloved password manager
setInputValue(app.find('input[name="password"]'), 'QJbHYJN3tPW[29AoBM3#rsfB4@hshp>gC8mDmUTtbGTfExY]#nBjmtX@NmEJwxBc')
setInputValue(app.find('input[name="passwordConfirm"]'), 'QJbHYJN3tPW[29AoBM3#rsfB4@hshp>gC8mDmUTtbGTfExY]#nBjmtX@NmEJwxBc')
// THIS FAILS! That's because UserStep has some React anti-patterns.
expect(nextButton.props().disabled).toBe(false)
clickButton(nextButton);
})
it("should allow you to add a database", async () => {
// // add h2 database
// await waitForElement(driver, "option[value=h2]");
//
// const h2Option = findElement(driver, "option[value=h2]");
// await h2Option.click();
// await waitForElementAndSendKeys(driver, "[name=name]", 'Metabase H2');
// const dbPath = path.resolve(__dirname, '../support/fixtures/metabase.db');
// await waitForElementAndSendKeys(driver, "[name=db]", `file:${dbPath}`);
// await waitForElementAndClick(driver, ".Button.Button--primary");
})
it("should let you opt in/out from user tracking", async () => {
//
// await waitForElement(driver, ".SetupStep.rounded.full.relative.SetupStep--active:last-of-type");
// await waitForElementAndClick(driver, ".Button.Button--primary");
//
// await waitForElement(driver, "a[href='/?new']");
// await waitForElementAndClick(driver, ".Button.Button--primary");
//
// await waitForUrl(driver, `${server.host}/?new`);
// await waitForElement(driver, ".Modal h2:first-child");
// const onboardingModalHeading = await findElement(driver, ".Modal h2:first-child");
// expect(await onboardingModalHeading.getText()).toBe('Testy, welcome to Metabase!');
})
// NOTE Atte Keinänen 8/15/17:
// If you want to develop tests incrementally, you should disable this step as this will complete the setup
// That is an irreversible action (you have to nuke the db in order to see the setup screen again
it("should show you the onboarding modal", async () => {
})
afterAll(async () => {
// Problem with setup guide test is that you can't reset the db to the initial state
})
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment