Skip to content
Snippets Groups Projects
Commit 01f34f74 authored by Tom Robinson's avatar Tom Robinson
Browse files

Paraemters/embedding e2e tests [ci e2e]

parent 51ca0dc6
Branches
Tags
No related merge requests found
import { init } from "./app";
import { getRoutes } from "./routes.jsx";
import reducers from './reducers-main';
import { push } from 'react-router-redux'
init(reducers, getRoutes, () => {
import { init } from "metabase/app";
import { getRoutes } from "metabase/routes.jsx";
import reducers from 'metabase/reducers-main';
import api from "metabase/lib/api";
import { setErrorPage } from "metabase/redux/app";
import { clearCurrentUser } from "metabase/redux/user";
// we shouldn't redirect these URLs because we want to handle them differently
const WHITELIST_FORBIDDEN_URLS = [
// on dashboards, we show permission errors for individual cards we don't have access to
/api\/card\/\d+\/query$/,
// metadata endpoints should not cause redirects
// we should gracefully handle cases where we don't have access to metadata
/api\/database\/\d+\/metadata$/,
/api\/database\/\d+\/fields/,
/api\/field\/\d+\/values/,
/api\/table\/\d+\/query_metadata$/,
/api\/table\/\d+\/fks$/
];
init(reducers, getRoutes, (store) => {
// received a 401 response
api.on("401", (url) => {
if (url === "/api/user/current") {
return
}
store.dispatch(clearCurrentUser());
store.dispatch(push("/auth/login"));
});
// received a 403 response
api.on("403", (url) => {
if (url) {
for (const regex of WHITELIST_FORBIDDEN_URLS) {
if (regex.test(url)) {
return;
}
}
}
store.dispatch(setErrorPage({ status: 403 }));
});
})
......@@ -10,29 +10,13 @@ import { Provider } from 'react-redux'
import MetabaseAnalytics, { registerAnalyticsClickListener } from "metabase/lib/analytics";
import MetabaseSettings from "metabase/lib/settings";
import api from "metabase/lib/api";
import { getStore } from './store'
import { refreshSiteSettings } from "metabase/redux/settings";
import { setErrorPage } from "metabase/redux/app";
import { clearCurrentUser } from "metabase/redux/user";
import { Router, browserHistory } from "react-router";
import { push, syncHistoryWithStore } from 'react-router-redux'
import { syncHistoryWithStore } from 'react-router-redux'
// we shouldn't redirect these URLs because we want to handle them differently
const WHITELIST_FORBIDDEN_URLS = [
// on dashboards, we show permission errors for individual cards we don't have access to
/api\/card\/\d+\/query$/,
// metadata endpoints should not cause redirects
// we should gracefully handle cases where we don't have access to metadata
/api\/database\/\d+\/metadata$/,
/api\/database\/\d+\/fields/,
/api\/field\/\d+\/values/,
/api\/table\/\d+\/query_metadata$/,
/api\/table\/\d+\/fks$/
];
function _init(reducers, getRoutes, callback) {
const store = getStore(reducers, browserHistory);
......@@ -61,27 +45,6 @@ function _init(reducers, getRoutes, callback) {
window['ga-disable-' + MetabaseSettings.get('ga_code')] = MetabaseSettings.isTrackingEnabled() ? null : true;
});
// received a 401 response
api.on("401", (url) => {
if (url === "/api/user/current") {
return
}
store.dispatch(clearCurrentUser());
store.dispatch(push("/auth/login"));
});
// received a 403 response
api.on("403", (url) => {
if (url) {
for (const regex of WHITELIST_FORBIDDEN_URLS) {
if (regex.test(url)) {
return;
}
}
}
store.dispatch(setErrorPage({ status: 403 }));
});
if (callback) {
callback(store);
}
......
import {
describeE2E,
ensureLoggedIn
} from "../support/utils";
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;
import { startNativeQuestion, saveQuestion, logout } from "../support/metabase";
async function setCategoryParameter(value) {
// currently just selects the first parameter
await this.select(":react(Parameters) a").wait().click()
await this.select(":react(CategoryWidget) li:contains(" + value + ")").wait().click();
return this;
}
async function checkScalar(value) {
await this.sleep(250);
await this.select(".ScalarValue :react(Scalar)").waitText(value);
return this;
}
const COUNT_ALL = "200";
const COUNT_DOOHICKEY = "56";
const COUNT_GADGET = "43";
describeE2E("parameters", () => {
beforeEach(async () => {
await ensureLoggedIn(server, driver, "bob@metabase.com", "12341234");
});
describe("questions", () => {
it("should allow users to enable public sharing", async () => {
// load public sharing settings
await d.get("/admin/settings/public_sharing");
// if enabled, disable it so we're in a known state
if ((await d.select(":react(SettingsSetting) .flex .text-bold").wait().text()) === "Enabled") {
await d.select(":react(SettingsSetting) :react(Toggle)").wait().click();
}
// toggle it on
await d.select(":react(SettingsSetting) :react(Toggle)").wait().click();
// make sure it's enabled
await d.select(":react(SettingsSetting) .flex .text-bold").waitText("Enabled");
})
it("should allow users to enable embedding", async () => {
// load embedding settings
await d.get("/admin/settings/embedding_in_other_applications");
try {
// if enabled, disable it so we're in a known state
await d.select(":react(Toggle)").wait().click();
} catch (e) {
}
// enable it
await d.select(".Button:contains(Enable)").wait().click();
// make sure it's enabled
await d.select(":react(SettingsSetting) .flex .text-bold").waitText("Enabled");
});
it("should allow users to create parameterized SQL questions", async () => {
await d::startNativeQuestion("select count(*) from products where {{category}}")
await d.sleep(500);
await d.select(".ColumnarSelector-row:contains(Field)").wait().click();
await d.select(".PopoverBody .AdminSelect").wait().sendKeys("cat");
await d.select(".ColumnarSelector-row:contains(Category)").wait().click();
// test without the parameter
await d.select(".RunButton").wait().click();
await d::checkScalar(COUNT_ALL);
// test the parameter
await d::setCategoryParameter("Doohickey");
await d.select(".RunButton").wait().click();
await d::checkScalar(COUNT_DOOHICKEY);
// save the question, required for public link/embedding
await d::saveQuestion("sql parameterized");
// open sharing panel
await d.select(".Icon-share").wait().click();
// open application embedding panel
await d.select(":react(SharingPane) .text-purple:contains(Embed)").wait().click();
// make the parameter editable
await d.select(".AdminSelect-content:contains(Disabled)").wait().click();
await d.select(":react(Option):contains(Editable)").wait().click();
await d.sleep(500);
// publish
await d.select(".Button:contains(Publish)").wait().click();
// get the embed URL
const embedUrl = (await d.select(":react(PreviewPane) iframe").wait().attribute("src")).replace(/#.*$/, "");
// back to main share panel
await d.select("h2 a span:contains(Sharing)").wait().click();
// toggle public link on
await d.select(":react(SharingPane) :react(Toggle)").wait().click();
// get the public URL
const publicUrl = (await d.select(":react(CopyWidget) input").wait().attribute("value")).replace(/#.*$/, "");
// logout to ensure it works for non-logged in users
d::logout();
// public url
await d.get(publicUrl);
await d::checkScalar(COUNT_ALL);
// manually click parameter
await d::setCategoryParameter("Doohickey");
await d::checkScalar(COUNT_DOOHICKEY);
// set parameter via url
await d.get(publicUrl + "?category=Gadget");
await d::checkScalar(COUNT_GADGET);
// embed
await d.get(embedUrl);
await d::checkScalar(COUNT_ALL);
// manually click parameter
await d::setCategoryParameter("Doohickey");
await d::checkScalar(COUNT_DOOHICKEY);
// set parameter via url
await d.get(embedUrl + "?category=Gadget");
await d::checkScalar(COUNT_GADGET);
});
});
});
No preview for this file type
export async function logout() {
await this.wd().manage().deleteAllCookies();
return this;
}
export async function startGuiQuestion(text) {
await this.get("/question");
return this;
}
export async function startNativeQuestion(text) {
await this.get("/question");
await this.select(".Icon-sql").wait().click();
await this.select(".ace_text-input").wait().sendKeys(text);
return this;
}
export async function runQuery() {
await this.select(".RunButton").wait().click();
return this;
}
export async function saveQuestion(questionName, newDashboardName) {
// save question
await this.select(".Header-buttonSection:first-child").wait().click();
await this.select("#SaveQuestionModal input[name='name']").wait().sendKeys(questionName);
await this.select("#SaveQuestionModal .Button.Button--primary").wait().click().waitRemoved(); // wait for the modal to be removed
if (newDashboardName) {
// add to new dashboard
await this.select("#QuestionSavedModal .Button.Button--primary").wait().click();
await this.select("#CreateDashboardModal input[name='name']").wait().sendKeys(newDashboardName);
await this.select("#CreateDashboardModal .Button.Button--primary").wait().click().waitRemoved(); // wait for the modal to be removed
} else {
await this.select("#QuestionSavedModal .Button:contains(Not)").wait().click();
}
// wait for modal to close :-/
await this.sleep(500);
return this;
}
......@@ -7,6 +7,11 @@ import { Driver } from "webchauffeur";
const DEFAULT_TIMEOUT = 50000;
// these are sessions persisted in the fixture dbs, to avoid having to login
const DEFAULT_SESSIONS = {
"bob@metabase.com": "068a6678-db09-4853-b7d5-d0ef6cb9cbc8"
}
const log = (message) => {
console.log(message);
};
......@@ -144,11 +149,11 @@ export const checkLoggedIn = async (server, driver, email) => {
}
const getSessionId = (server, email) => {
server.sessions = server.sessions || {};
server.sessions = server.sessions || { ...DEFAULT_SESSIONS };
return server.sessions[email];
}
const setSessionId = (server, email, sessionId) => {
server.sessions = server.sessions || {};
server.sessions = server.sessions || { ...DEFAULT_SESSIONS };
server.sessions[email] = sessionId;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment