diff --git a/binderhub/static/js/App.jsx b/binderhub/static/js/App.jsx
index 14428e169..97f146e72 100644
--- a/binderhub/static/js/App.jsx
+++ b/binderhub/static/js/App.jsx
@@ -1,7 +1,5 @@
-import { createRoot } from "react-dom/client";
-
import { LoadingPage } from "./pages/LoadingPage.jsx";
-import { createBrowserRouter, RouterProvider, Route } from "react-router-dom";
+import { Route, Routes } from "react-router-dom";
import "bootstrap/js/dist/dropdown.js";
import "./index.scss";
@@ -9,7 +7,6 @@ import "@fontsource/clear-sans/100.css";
import "@fontsource/clear-sans/300.css";
import "@fontsource/clear-sans/400.css";
import { HomePage } from "./pages/HomePage.jsx";
-import { createRoutesFromElements } from "react-router";
import { AboutPage } from "./pages/AboutPage.jsx";
export const PAGE_CONFIG = window.pageConfig;
@@ -45,40 +42,7 @@ export const PUBLIC_BASE_URL = PAGE_CONFIG.publicBaseUrl
? new URL(BASE_URL)
: new URL(PAGE_CONFIG.baseUrl, window.location.href);
-const router = createBrowserRouter(
- createRoutesFromElements(
-
-
- }
- />
- {PROVIDERS.map((p) => (
- }
- />
- ))}
-
- }
- />
- ,
- ),
-);
-function App() {
+export function App() {
return (
<>
{PAGE_CONFIG.bannerHtml && (
@@ -92,12 +56,36 @@ function App() {
-
+
+
+ }
+ />
+ {PROVIDERS.map((p) => (
+ }
+ />
+ ))}
+
+ }
+ />
+
>
);
}
-
-const root = createRoot(document.getElementById("root"));
-root.render();
diff --git a/binderhub/static/js/App.test.jsx b/binderhub/static/js/App.test.jsx
new file mode 100644
index 000000000..f5249fb17
--- /dev/null
+++ b/binderhub/static/js/App.test.jsx
@@ -0,0 +1,27 @@
+import { render, screen } from "@testing-library/react";
+
+import { App } from "./App";
+import { MemoryRouter } from "react-router";
+
+test("render Homepage", () => {
+ render(
+
+
+ ,
+ );
+ expect(
+ screen.queryByText(
+ /Turn a Git repo into a collection of interactive notebooks/,
+ ),
+ ).toBeInTheDocument();
+});
+
+test("render About page", () => {
+ render(
+
+
+ ,
+ );
+ expect(screen.queryByText(/This is the about message/)).toBeInTheDocument();
+ expect(screen.queryByText(/v123.456/)).toBeInTheDocument();
+});
diff --git a/binderhub/static/js/index.jsx b/binderhub/static/js/index.jsx
new file mode 100644
index 000000000..69e7a5b4d
--- /dev/null
+++ b/binderhub/static/js/index.jsx
@@ -0,0 +1,10 @@
+import { createRoot } from "react-dom/client";
+import { BrowserRouter } from "react-router-dom";
+import { App } from "./App";
+
+const root = createRoot(document.getElementById("root"));
+root.render(
+
+
+ ,
+);
diff --git a/package.json b/package.json
index aac5a05e5..8db0621a0 100644
--- a/package.json
+++ b/package.json
@@ -69,6 +69,7 @@
],
"moduleNameMapper": {
"\\.css$": "identity-obj-proxy",
+ "\\.scss$": "identity-obj-proxy",
"\\.ico$": "identity-obj-proxy"
},
"setupFilesAfterEnv": [
diff --git a/setupTests.js b/setupTests.js
index d0eb842f3..fd314cc30 100644
--- a/setupTests.js
+++ b/setupTests.js
@@ -17,6 +17,9 @@ Object.defineProperty(window, "matchMedia", {
});
window.pageConfig = {
+ baseUrl: "/",
+ aboutMessage: "This is the about message",
+ binderVersion: "v123.456",
repoProviders: [
{
detect: {
diff --git a/webpack.config.js b/webpack.config.js
index db0d44a93..609148abb 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -7,7 +7,7 @@ const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
mode: "development",
context: path.resolve(__dirname, "binderhub/static"),
- entry: "./js/App.jsx",
+ entry: "./js/index.jsx",
output: {
path: path.resolve(__dirname, "binderhub/static/dist/"),
filename: "bundle.js",