Skip to content
Snippets Groups Projects
Unverified Commit 434e7868 authored by Anton Kulyk's avatar Anton Kulyk Committed by GitHub
Browse files

Clean up `PublicApp` component and add tests (#27724)

* Move `PublicApp` to its own directory

* Fix `renderWithProviders` for public environment

* Clean up `PublicApp` and add tests

* Extend coverage

* Wasn't planning to commit this yet

* Swap condition
parent 61395781
No related branches found
No related tags found
No related merge requests found
......@@ -13,7 +13,7 @@ const LogoBadge = ({ dark }) => (
<LogoIcon height={28} dark={dark} />
<span className="text-small">
<span className="ml1 md-ml2 text-medium">{jt`Powered by ${(
<span className={dark ? "text-white" : "text-brand"}>
<span key="metabase" className={dark ? "text-white" : "text-brand"}>
{t`Metabase`}
</span>
)}`}</span>
......
/* eslint-disable react/prop-types */
import React, { Component } from "react";
import { connect } from "react-redux";
import PublicNotFound from "metabase/public/components/PublicNotFound";
import PublicError from "metabase/public/components/PublicError";
const mapStateToProps = (state, props) => ({
errorPage: state.app.errorPage,
});
class PublicApp extends Component {
render() {
const { children, errorPage } = this.props;
if (errorPage) {
if (errorPage.status === 404) {
return <PublicNotFound />;
} else {
return <PublicError />;
}
} else {
return children;
}
}
}
export default connect(mapStateToProps)(PublicApp);
import React from "react";
import { connect } from "react-redux";
import { getErrorPage } from "metabase/selectors/app";
import PublicNotFound from "metabase/public/components/PublicNotFound";
import PublicError from "metabase/public/components/PublicError";
import type { AppErrorDescriptor, State } from "metabase-types/store";
interface OwnProps {
children: JSX.Element;
}
interface StateProps {
errorPage?: AppErrorDescriptor | null;
}
type Props = OwnProps & StateProps;
function mapStateToProps(state: State) {
return {
errorPage: getErrorPage(state),
};
}
function PublicApp({ errorPage, children }: Props) {
if (errorPage) {
return errorPage.status === 404 ? <PublicNotFound /> : <PublicError />;
}
return children;
}
export default connect<StateProps, unknown, OwnProps, State>(mapStateToProps)(
PublicApp,
);
import React from "react";
import userEvent from "@testing-library/user-event";
import { getIcon, renderWithProviders, screen } from "__support__/ui";
import { mockSettings } from "__support__/settings";
import { AppErrorDescriptor } from "metabase-types/store";
import { createMockAppState } from "metabase-types/store/mocks";
import EmbedFrame from "../../components/EmbedFrame";
import PublicApp from "./PublicApp";
type SetupOpts = {
name?: string;
description?: string;
actionButtons?: JSX.Element[];
error?: AppErrorDescriptor;
hasEmbedBranding?: boolean;
};
function setup({
error,
hasEmbedBranding = true,
...embedFrameProps
}: SetupOpts = {}) {
const app = createMockAppState({ errorPage: error });
const settings = mockSettings({ "hide-embed-branding?": !hasEmbedBranding });
renderWithProviders(
<PublicApp>
<EmbedFrame {...embedFrameProps}>
<h1 data-testid="test-content">Test</h1>
</EmbedFrame>
</PublicApp>,
{ mode: "public", storeInitialState: { app, settings }, withRouter: true },
);
}
describe("PublicApp", () => {
it("renders children", () => {
setup();
expect(screen.getByTestId("test-content")).toBeInTheDocument();
});
it("renders name", () => {
setup({ name: "My Title", description: "My Description" });
expect(screen.getByText("My Title")).toBeInTheDocument();
expect(screen.queryByText("My Description")).not.toBeInTheDocument();
});
it("renders description", () => {
setup({ name: "My Title", description: "My Description" });
userEvent.hover(getIcon("info"));
expect(screen.getByText("My Description")).toBeInTheDocument();
});
it("renders action buttons", () => {
setup({ actionButtons: [<button key="test">Click Me</button>] });
expect(
screen.getByRole("button", { name: "Click Me" }),
).toBeInTheDocument();
});
it("renders branding", () => {
setup();
expect(screen.getByText(/Powered by/i)).toBeInTheDocument();
expect(screen.getByText(/Metabase/)).toBeInTheDocument();
});
it("renders not found page on error", () => {
setup({ error: { status: 404 } });
expect(screen.getByText("Not found")).toBeInTheDocument();
expect(screen.queryByTestId("test-content")).not.toBeInTheDocument();
});
it("renders error message", () => {
setup({
error: {
status: 500,
data: { error_code: "error", message: "Something went wrong" },
},
});
expect(screen.getByText("Something went wrong")).toBeInTheDocument();
expect(screen.queryByTestId("test-content")).not.toBeInTheDocument();
});
it("renders fallback error message", () => {
setup({ error: { status: 500 } });
expect(screen.getByText(/An error occurred/)).toBeInTheDocument();
expect(screen.queryByTestId("test-content")).not.toBeInTheDocument();
});
it("renders branding in error states", () => {
setup({ error: { status: 404 } });
expect(screen.getByText(/Powered by/i)).toBeInTheDocument();
expect(screen.getByText(/Metabase/)).toBeInTheDocument();
});
it("hides branding in error states if it's turned off", () => {
setup({ error: { status: 404 }, hasEmbedBranding: false });
expect(screen.queryByText(/Powered by/i)).not.toBeInTheDocument();
expect(screen.queryByText(/Metabase/)).not.toBeInTheDocument();
});
});
export { default } from "./PublicApp";
import React from "react";
import { render, screen } from "@testing-library/react";
import { merge } from "icepick";
import _ from "underscore";
import { createMemoryHistory } from "history";
import { Router, Route } from "react-router";
import { Provider } from "react-redux";
......@@ -43,16 +44,19 @@ export function renderWithProviders(
...options
}: RenderWithProvidersOptions = {},
) {
const initialReduxState = createMockState(
let initialState = createMockState(
withSampleDatabase
? merge(sampleDatabaseReduxState, storeInitialState)
: storeInitialState,
);
const store = getStore(
mode === "default" ? mainReducers : publicReducers,
initialReduxState,
);
if (mode === "public") {
const publicReducerNames = Object.keys(publicReducers);
initialState = _.pick(initialState, ...publicReducerNames) as State;
}
const reducers = mode === "default" ? mainReducers : publicReducers;
const store = getStore(reducers, initialState);
const wrapper = (props: any) => (
<Wrapper
......@@ -106,10 +110,11 @@ function MaybeRouter({
if (!hasRouter) {
return children;
}
const history = createMemoryHistory({ entries: ["/"] });
function Page(props: any) {
return React.cloneElement(children, props);
return React.cloneElement(children, _.omit(props, "children"));
}
return (
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment