mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-12 12:33:02 +00:00
Updated ServerDashboard to testing-library, added tests
This commit is contained in:
@@ -61,7 +61,7 @@ const ServerDashboard = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!user_data) {
|
if (!user_data) {
|
||||||
return <div></div>;
|
return <div data-testid="no-show"></div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page != user_page) {
|
if (page != user_page) {
|
||||||
@@ -73,7 +73,7 @@ const ServerDashboard = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<div className="container" data-testid="container">
|
||||||
{errorAlert != null ? (
|
{errorAlert != null ? (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2">
|
<div className="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2">
|
||||||
@@ -104,6 +104,7 @@ const ServerDashboard = (props) => {
|
|||||||
<SortHandler
|
<SortHandler
|
||||||
sorts={{ asc: usernameAsc, desc: usernameDesc }}
|
sorts={{ asc: usernameAsc, desc: usernameDesc }}
|
||||||
callback={(method) => setSortMethod(() => method)}
|
callback={(method) => setSortMethod(() => method)}
|
||||||
|
testid="user-sort"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th id="admin-header">
|
<th id="admin-header">
|
||||||
@@ -111,6 +112,7 @@ const ServerDashboard = (props) => {
|
|||||||
<SortHandler
|
<SortHandler
|
||||||
sorts={{ asc: adminAsc, desc: adminDesc }}
|
sorts={{ asc: adminAsc, desc: adminDesc }}
|
||||||
callback={(method) => setSortMethod(() => method)}
|
callback={(method) => setSortMethod(() => method)}
|
||||||
|
testid="admin-sort"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th id="last-activity-header">
|
<th id="last-activity-header">
|
||||||
@@ -118,6 +120,7 @@ const ServerDashboard = (props) => {
|
|||||||
<SortHandler
|
<SortHandler
|
||||||
sorts={{ asc: dateAsc, desc: dateDesc }}
|
sorts={{ asc: dateAsc, desc: dateDesc }}
|
||||||
callback={(method) => setSortMethod(() => method)}
|
callback={(method) => setSortMethod(() => method)}
|
||||||
|
testid="last-activity-sort"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th id="running-status-header">
|
<th id="running-status-header">
|
||||||
@@ -125,6 +128,7 @@ const ServerDashboard = (props) => {
|
|||||||
<SortHandler
|
<SortHandler
|
||||||
sorts={{ asc: runningAsc, desc: runningDesc }}
|
sorts={{ asc: runningAsc, desc: runningDesc }}
|
||||||
callback={(method) => setSortMethod(() => method)}
|
callback={(method) => setSortMethod(() => method)}
|
||||||
|
testid="running-status-sort"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th id="actions-header">Actions</th>
|
<th id="actions-header">Actions</th>
|
||||||
@@ -144,13 +148,14 @@ const ServerDashboard = (props) => {
|
|||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
className="start-all"
|
className="start-all"
|
||||||
|
data-testid="start-all"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
Promise.all(startAll(user_data.map((e) => e.name)))
|
Promise.all(startAll(user_data.map((e) => e.name)))
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
let failedServers = res.filter((e) => !e.ok);
|
let failedServers = res.filter((e) => !e.ok);
|
||||||
if (failedServers.length > 0) {
|
if (failedServers.length > 0) {
|
||||||
setErrorAlert(
|
setErrorAlert(
|
||||||
`Could not start ${failedServers.length} ${
|
`Failed to start ${failedServers.length} ${
|
||||||
failedServers.length > 1 ? "servers" : "server"
|
failedServers.length > 1 ? "servers" : "server"
|
||||||
}. ${
|
}. ${
|
||||||
failedServers.length > 1 ? "Are they " : "Is it "
|
failedServers.length > 1 ? "Are they " : "Is it "
|
||||||
@@ -165,12 +170,12 @@ const ServerDashboard = (props) => {
|
|||||||
dispatchPageUpdate(data, page);
|
dispatchPageUpdate(data, page);
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setErrorAlert(`Could not update users list.`)
|
setErrorAlert(`Failed to update users list.`)
|
||||||
);
|
);
|
||||||
return res;
|
return res;
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setErrorAlert(`Could not start servers.`)
|
setErrorAlert(`Failed to start servers.`)
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -181,13 +186,14 @@ const ServerDashboard = (props) => {
|
|||||||
<Button
|
<Button
|
||||||
variant="danger"
|
variant="danger"
|
||||||
className="stop-all"
|
className="stop-all"
|
||||||
|
data-testid="stop-all"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
Promise.all(stopAll(user_data.map((e) => e.name)))
|
Promise.all(stopAll(user_data.map((e) => e.name)))
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
let failedServers = res.filter((e) => !e.ok);
|
let failedServers = res.filter((e) => !e.ok);
|
||||||
if (failedServers.length > 0) {
|
if (failedServers.length > 0) {
|
||||||
setErrorAlert(
|
setErrorAlert(
|
||||||
`Could not stop ${failedServers.length} ${
|
`Failed to stop ${failedServers.length} ${
|
||||||
failedServers.length > 1 ? "servers" : "server"
|
failedServers.length > 1 ? "servers" : "server"
|
||||||
}. ${
|
}. ${
|
||||||
failedServers.length > 1 ? "Are they " : "Is it "
|
failedServers.length > 1 ? "Are they " : "Is it "
|
||||||
@@ -202,13 +208,11 @@ const ServerDashboard = (props) => {
|
|||||||
dispatchPageUpdate(data, page);
|
dispatchPageUpdate(data, page);
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setErrorAlert(`Could not update users list.`)
|
setErrorAlert(`Failed to update users list.`)
|
||||||
);
|
);
|
||||||
return res;
|
return res;
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) => setErrorAlert(`Failed to stop servers.`));
|
||||||
setErrorAlert(`Could not stop all servers.`)
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Stop All
|
Stop All
|
||||||
@@ -227,12 +231,12 @@ const ServerDashboard = (props) => {
|
|||||||
</tr>
|
</tr>
|
||||||
{user_data.map((e, i) => (
|
{user_data.map((e, i) => (
|
||||||
<tr key={i + "row"} className="user-row">
|
<tr key={i + "row"} className="user-row">
|
||||||
<td>{e.name}</td>
|
<td data-testid="user-row-name">{e.name}</td>
|
||||||
<td>{e.admin ? "admin" : ""}</td>
|
<td data-testid="user-row-admin">{e.admin ? "admin" : ""}</td>
|
||||||
<td>
|
<td data-testid="user-row-last-activity">
|
||||||
{e.last_activity ? timeSince(e.last_activity) : "Never"}
|
{e.last_activity ? timeSince(e.last_activity) : "Never"}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td data-testid="user-row-server-activity">
|
||||||
{e.server != null ? (
|
{e.server != null ? (
|
||||||
// Stop Single-user server
|
// Stop Single-user server
|
||||||
<button
|
<button
|
||||||
@@ -240,21 +244,21 @@ const ServerDashboard = (props) => {
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
stopServer(e.name)
|
stopServer(e.name)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.ok) return res;
|
data < 300
|
||||||
throw new Error(res.status);
|
? updateUsers(...slice)
|
||||||
})
|
.then((data) => {
|
||||||
.then((res) => {
|
dispatchPageUpdate(data, page);
|
||||||
updateUsers(...slice)
|
})
|
||||||
.then((data) => {
|
.catch((err) =>
|
||||||
dispatchPageUpdate(data, page);
|
setErrorAlert(
|
||||||
})
|
`Failed to update users list.`
|
||||||
.catch((err) =>
|
)
|
||||||
setErrorAlert(`Could not update users list.`)
|
)
|
||||||
);
|
: setErrorAlert(`Failed to stop server`);
|
||||||
return res;
|
return res;
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setErrorAlert(`Could not stop server.`)
|
setErrorAlert(`Failed to stop server.`)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -267,21 +271,21 @@ const ServerDashboard = (props) => {
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
startServer(e.name)
|
startServer(e.name)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.ok) return res;
|
data < 300
|
||||||
throw new Error(res.status);
|
? updateUsers(...slice)
|
||||||
})
|
.then((data) => {
|
||||||
.then((res) => {
|
dispatchPageUpdate(data, page);
|
||||||
updateUsers(...slice)
|
})
|
||||||
.then((data) => {
|
.catch((err) =>
|
||||||
dispatchPageUpdate(data, page);
|
setErrorAlert(
|
||||||
})
|
`Failed to update users list.`
|
||||||
.catch((err) =>
|
)
|
||||||
setErrorAlert(`Could not update users list.`)
|
)
|
||||||
);
|
: setErrorAlert(`Failed to start server`);
|
||||||
return res;
|
return res;
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
setErrorAlert(`Could not start server.`);
|
setErrorAlert(`Failed to start server.`);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -342,13 +346,14 @@ ServerDashboard.propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const SortHandler = (props) => {
|
const SortHandler = (props) => {
|
||||||
var { sorts, callback } = props;
|
var { sorts, callback, testid } = props;
|
||||||
|
|
||||||
var [direction, setDirection] = useState(undefined);
|
var [direction, setDirection] = useState(undefined);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="sort-icon"
|
className="sort-icon"
|
||||||
|
data-testid={testid}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!direction) {
|
if (!direction) {
|
||||||
callback(sorts.desc);
|
callback(sorts.desc);
|
||||||
@@ -376,6 +381,7 @@ const SortHandler = (props) => {
|
|||||||
SortHandler.propTypes = {
|
SortHandler.propTypes = {
|
||||||
sorts: PropTypes.object,
|
sorts: PropTypes.object,
|
||||||
callback: PropTypes.func,
|
callback: PropTypes.func,
|
||||||
|
testid: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ServerDashboard;
|
export default ServerDashboard;
|
||||||
|
@@ -1,161 +1,441 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Enzyme, { mount } from "enzyme";
|
import "@testing-library/jest-dom";
|
||||||
import ServerDashboard from "./ServerDashboard";
|
import { act } from "react-dom/test-utils";
|
||||||
import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
|
import { render, screen, fireEvent } from "@testing-library/react";
|
||||||
import { HashRouter, Switch } from "react-router-dom";
|
import { HashRouter, Switch } from "react-router-dom";
|
||||||
import { Provider, useSelector } from "react-redux";
|
import { Provider, useSelector } from "react-redux";
|
||||||
import { createStore } from "redux";
|
import { createStore } from "redux";
|
||||||
|
// eslint-disable-next-line
|
||||||
|
import regeneratorRuntime from 'regenerator-runtime'
|
||||||
|
|
||||||
Enzyme.configure({ adapter: new Adapter() });
|
import ServerDashboard from "./ServerDashboard";
|
||||||
|
|
||||||
jest.mock("react-redux", () => ({
|
jest.mock("react-redux", () => ({
|
||||||
...jest.requireActual("react-redux"),
|
...jest.requireActual("react-redux"),
|
||||||
useSelector: jest.fn(),
|
useSelector: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe("ServerDashboard Component: ", () => {
|
var serverDashboardJsx = (spy) => (
|
||||||
var serverDashboardJsx = (callbackSpy) => (
|
<Provider store={createStore(() => {}, {})}>
|
||||||
<Provider store={createStore(() => {}, {})}>
|
<HashRouter>
|
||||||
<HashRouter>
|
<Switch>
|
||||||
<Switch>
|
<ServerDashboard
|
||||||
<ServerDashboard
|
updateUsers={spy}
|
||||||
updateUsers={callbackSpy}
|
shutdownHub={spy}
|
||||||
shutdownHub={callbackSpy}
|
startServer={spy}
|
||||||
startServer={callbackSpy}
|
stopServer={spy}
|
||||||
stopServer={callbackSpy}
|
startAll={spy}
|
||||||
startAll={callbackSpy}
|
stopAll={spy}
|
||||||
stopAll={callbackSpy}
|
/>
|
||||||
/>
|
</Switch>
|
||||||
</Switch>
|
</HashRouter>
|
||||||
</HashRouter>
|
</Provider>
|
||||||
</Provider>
|
);
|
||||||
);
|
|
||||||
|
|
||||||
var mockAsync = () =>
|
var mockAsync = (data) =>
|
||||||
jest
|
jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation(() =>
|
.mockImplementation(() =>
|
||||||
Promise.resolve({ json: () => Promise.resolve({ k: "v" }) })
|
Promise.resolve({ json: () => Promise.resolve(data ? data : { k: "v" }) })
|
||||||
);
|
);
|
||||||
|
|
||||||
var mockAppState = () => ({
|
var mockAsyncRejection = () =>
|
||||||
user_data: JSON.parse(
|
jest.fn().mockImplementation(() => Promise.reject());
|
||||||
'[{"kind":"user","name":"foo","admin":true,"groups":[],"server":"/user/foo/","pending":null,"created":"2020-12-07T18:46:27.112695Z","last_activity":"2020-12-07T21:00:33.336354Z","servers":{"":{"name":"","last_activity":"2020-12-07T20:58:02.437408Z","started":"2020-12-07T20:58:01.508266Z","pending":null,"ready":true,"state":{"pid":28085},"url":"/user/foo/","user_options":{},"progress_url":"/hub/api/users/foo/server/progress"}}},{"kind":"user","name":"bar","admin":false,"groups":[],"server":null,"pending":null,"created":"2020-12-07T18:46:27.115528Z","last_activity":"2020-12-07T20:43:51.013613Z","servers":{}}]'
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
var mockAppState = () => ({
|
||||||
useSelector.mockImplementation((callback) => {
|
user_data: JSON.parse(
|
||||||
return callback(mockAppState());
|
'[{"kind":"user","name":"foo","admin":true,"groups":[],"server":"/user/foo/","pending":null,"created":"2020-12-07T18:46:27.112695Z","last_activity":"2020-12-07T21:00:33.336354Z","servers":{"":{"name":"","last_activity":"2020-12-07T20:58:02.437408Z","started":"2020-12-07T20:58:01.508266Z","pending":null,"ready":true,"state":{"pid":28085},"url":"/user/foo/","user_options":{},"progress_url":"/hub/api/users/foo/server/progress"}}},{"kind":"user","name":"bar","admin":false,"groups":[],"server":null,"pending":null,"created":"2020-12-07T18:46:27.115528Z","last_activity":"2020-12-07T20:43:51.013613Z","servers":{}}]'
|
||||||
});
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
beforeEach(() => {
|
||||||
useSelector.mockClear();
|
useSelector.mockImplementation((callback) => {
|
||||||
});
|
return callback(mockAppState());
|
||||||
|
|
||||||
it("Renders users from props.user_data into table", () => {
|
|
||||||
let component = mount(serverDashboardJsx(mockAsync())),
|
|
||||||
userRows = component.find(".user-row");
|
|
||||||
expect(userRows.length).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Renders correctly the status of a single-user server", () => {
|
|
||||||
let component = mount(serverDashboardJsx(mockAsync())),
|
|
||||||
userRows = component.find(".user-row");
|
|
||||||
// Renders .stop-button when server is started
|
|
||||||
// Should be 1 since user foo is started
|
|
||||||
expect(userRows.at(0).find(".stop-button").length).toBe(1);
|
|
||||||
// Renders .start-button when server is stopped
|
|
||||||
// Should be 1 since user bar is stopped
|
|
||||||
expect(userRows.at(1).find(".start-button").length).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Invokes the startServer event on button click", () => {
|
|
||||||
let callbackSpy = mockAsync(),
|
|
||||||
component = mount(serverDashboardJsx(callbackSpy)),
|
|
||||||
startBtn = component.find(".start-button");
|
|
||||||
startBtn.simulate("click");
|
|
||||||
expect(callbackSpy).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Invokes the stopServer event on button click", () => {
|
|
||||||
let callbackSpy = mockAsync(),
|
|
||||||
component = mount(serverDashboardJsx(callbackSpy)),
|
|
||||||
stopBtn = component.find(".stop-button");
|
|
||||||
stopBtn.simulate("click");
|
|
||||||
expect(callbackSpy).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Invokes the shutdownHub event on button click", () => {
|
|
||||||
let callbackSpy = mockAsync(),
|
|
||||||
component = mount(serverDashboardJsx(callbackSpy)),
|
|
||||||
shutdownBtn = component.find("#shutdown-button").first();
|
|
||||||
shutdownBtn.simulate("click");
|
|
||||||
expect(callbackSpy).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Sorts according to username", () => {
|
|
||||||
let component = mount(serverDashboardJsx(mockAsync())).find(
|
|
||||||
"ServerDashboard"
|
|
||||||
),
|
|
||||||
handler = component.find("SortHandler").first();
|
|
||||||
handler.simulate("click");
|
|
||||||
let first = component.find(".user-row").first();
|
|
||||||
expect(first.html().includes("bar")).toBe(true);
|
|
||||||
handler.simulate("click");
|
|
||||||
first = component.find(".user-row").first();
|
|
||||||
expect(first.html().includes("foo")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Sorts according to admin", () => {
|
|
||||||
let component = mount(serverDashboardJsx(mockAsync())).find(
|
|
||||||
"ServerDashboard"
|
|
||||||
),
|
|
||||||
handler = component.find("SortHandler").at(1);
|
|
||||||
handler.simulate("click");
|
|
||||||
let first = component.find(".user-row").first();
|
|
||||||
expect(first.html().includes("admin")).toBe(true);
|
|
||||||
handler.simulate("click");
|
|
||||||
first = component.find(".user-row").first();
|
|
||||||
expect(first.html().includes("admin")).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Sorts according to last activity", () => {
|
|
||||||
let component = mount(serverDashboardJsx(mockAsync())).find(
|
|
||||||
"ServerDashboard"
|
|
||||||
),
|
|
||||||
handler = component.find("SortHandler").at(2);
|
|
||||||
handler.simulate("click");
|
|
||||||
let first = component.find(".user-row").first();
|
|
||||||
// foo used most recently
|
|
||||||
expect(first.html().includes("foo")).toBe(true);
|
|
||||||
handler.simulate("click");
|
|
||||||
first = component.find(".user-row").first();
|
|
||||||
// invert sort - bar used least recently
|
|
||||||
expect(first.html().includes("bar")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Sorts according to server status (running/not running)", () => {
|
|
||||||
let component = mount(serverDashboardJsx(mockAsync())).find(
|
|
||||||
"ServerDashboard"
|
|
||||||
),
|
|
||||||
handler = component.find("SortHandler").at(3);
|
|
||||||
handler.simulate("click");
|
|
||||||
let first = component.find(".user-row").first();
|
|
||||||
// foo running
|
|
||||||
expect(first.html().includes("foo")).toBe(true);
|
|
||||||
handler.simulate("click");
|
|
||||||
first = component.find(".user-row").first();
|
|
||||||
// invert sort - bar not running
|
|
||||||
expect(first.html().includes("bar")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Renders nothing if required data is not available", () => {
|
|
||||||
useSelector.mockImplementation((callback) => {
|
|
||||||
return callback({});
|
|
||||||
});
|
|
||||||
let component = mount(serverDashboardJsx(jest.fn()));
|
|
||||||
expect(component.html()).toBe("<div></div>");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
useSelector.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Renders", async () => {
|
||||||
|
let callbackSpy = mockAsync();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(serverDashboardJsx(callbackSpy));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByTestId("container")).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Renders users from props.user_data into table", async () => {
|
||||||
|
let callbackSpy = mockAsync();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(serverDashboardJsx(callbackSpy));
|
||||||
|
});
|
||||||
|
|
||||||
|
let foo = screen.getByText("foo");
|
||||||
|
let bar = screen.getByText("bar");
|
||||||
|
|
||||||
|
expect(foo).toBeVisible();
|
||||||
|
expect(bar).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Renders correctly the status of a single-user server", async () => {
|
||||||
|
let callbackSpy = mockAsync();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(serverDashboardJsx(callbackSpy));
|
||||||
|
});
|
||||||
|
|
||||||
|
let start = screen.getByText("Start Server");
|
||||||
|
let stop = screen.getByText("Stop Server");
|
||||||
|
|
||||||
|
expect(start).toBeVisible();
|
||||||
|
expect(stop).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Invokes the startServer event on button click", async () => {
|
||||||
|
let callbackSpy = mockAsync();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(serverDashboardJsx(callbackSpy));
|
||||||
|
});
|
||||||
|
|
||||||
|
let start = screen.getByText("Start Server");
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(start);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(callbackSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Invokes the stopServer event on button click", async () => {
|
||||||
|
let callbackSpy = mockAsync();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(serverDashboardJsx(callbackSpy));
|
||||||
|
});
|
||||||
|
|
||||||
|
let stop = screen.getByText("Stop Server");
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(stop);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(callbackSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Invokes the shutdownHub event on button click", async () => {
|
||||||
|
let callbackSpy = mockAsync();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(serverDashboardJsx(callbackSpy));
|
||||||
|
});
|
||||||
|
|
||||||
|
let shutdown = screen.getByText("Shutdown Hub");
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(shutdown);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(callbackSpy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Sorts according to username", async () => {
|
||||||
|
let callbackSpy = mockAsync();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(serverDashboardJsx(callbackSpy));
|
||||||
|
});
|
||||||
|
|
||||||
|
let handler = screen.getByTestId("user-sort");
|
||||||
|
fireEvent.click(handler);
|
||||||
|
|
||||||
|
let first = screen.getAllByTestId("user-row-name")[0];
|
||||||
|
expect(first.textContent).toBe("bar");
|
||||||
|
|
||||||
|
fireEvent.click(handler);
|
||||||
|
|
||||||
|
first = screen.getAllByTestId("user-row-name")[0];
|
||||||
|
expect(first.textContent).toBe("foo");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Sorts according to admin", async () => {
|
||||||
|
let callbackSpy = mockAsync();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(serverDashboardJsx(callbackSpy));
|
||||||
|
});
|
||||||
|
|
||||||
|
let handler = screen.getByTestId("admin-sort");
|
||||||
|
fireEvent.click(handler);
|
||||||
|
|
||||||
|
let first = screen.getAllByTestId("user-row-admin")[0];
|
||||||
|
expect(first.textContent).toBe("admin");
|
||||||
|
|
||||||
|
fireEvent.click(handler);
|
||||||
|
|
||||||
|
first = screen.getAllByTestId("user-row-admin")[0];
|
||||||
|
expect(first.textContent).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Sorts according to last activity", async () => {
|
||||||
|
let callbackSpy = mockAsync();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(serverDashboardJsx(callbackSpy));
|
||||||
|
});
|
||||||
|
|
||||||
|
let handler = screen.getByTestId("last-activity-sort");
|
||||||
|
fireEvent.click(handler);
|
||||||
|
|
||||||
|
let first = screen.getAllByTestId("user-row-name")[0];
|
||||||
|
expect(first.textContent).toBe("foo");
|
||||||
|
|
||||||
|
fireEvent.click(handler);
|
||||||
|
|
||||||
|
first = screen.getAllByTestId("user-row-name")[0];
|
||||||
|
expect(first.textContent).toBe("bar");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Sorts according to server status (running/not running)", async () => {
|
||||||
|
let callbackSpy = mockAsync();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(serverDashboardJsx(callbackSpy));
|
||||||
|
});
|
||||||
|
|
||||||
|
let handler = screen.getByTestId("running-status-sort");
|
||||||
|
fireEvent.click(handler);
|
||||||
|
|
||||||
|
let first = screen.getAllByTestId("user-row-name")[0];
|
||||||
|
expect(first.textContent).toBe("foo");
|
||||||
|
|
||||||
|
fireEvent.click(handler);
|
||||||
|
|
||||||
|
first = screen.getAllByTestId("user-row-name")[0];
|
||||||
|
expect(first.textContent).toBe("bar");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Renders nothing if required data is not available", async () => {
|
||||||
|
useSelector.mockImplementation((callback) => {
|
||||||
|
return callback({});
|
||||||
|
});
|
||||||
|
|
||||||
|
let callbackSpy = mockAsync();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(serverDashboardJsx(callbackSpy));
|
||||||
|
});
|
||||||
|
|
||||||
|
let noShow = screen.getByTestId("no-show");
|
||||||
|
|
||||||
|
expect(noShow).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Shows a UI error dialogue when start all servers fails", async () => {
|
||||||
|
let spy = mockAsync();
|
||||||
|
let rejectSpy = mockAsyncRejection;
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(
|
||||||
|
<Provider store={createStore(() => {}, {})}>
|
||||||
|
<HashRouter>
|
||||||
|
<Switch>
|
||||||
|
<ServerDashboard
|
||||||
|
updateUsers={spy}
|
||||||
|
shutdownHub={spy}
|
||||||
|
startServer={spy}
|
||||||
|
stopServer={spy}
|
||||||
|
startAll={rejectSpy}
|
||||||
|
stopAll={spy}
|
||||||
|
/>
|
||||||
|
</Switch>
|
||||||
|
</HashRouter>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let startAll = screen.getByTestId("start-all");
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(startAll);
|
||||||
|
});
|
||||||
|
|
||||||
|
let errorDialog = screen.getByText("Failed to start servers.");
|
||||||
|
|
||||||
|
expect(errorDialog).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Shows a UI error dialogue when stop all servers fails", async () => {
|
||||||
|
let spy = mockAsync();
|
||||||
|
let rejectSpy = mockAsyncRejection;
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(
|
||||||
|
<Provider store={createStore(() => {}, {})}>
|
||||||
|
<HashRouter>
|
||||||
|
<Switch>
|
||||||
|
<ServerDashboard
|
||||||
|
updateUsers={spy}
|
||||||
|
shutdownHub={spy}
|
||||||
|
startServer={spy}
|
||||||
|
stopServer={spy}
|
||||||
|
startAll={spy}
|
||||||
|
stopAll={rejectSpy}
|
||||||
|
/>
|
||||||
|
</Switch>
|
||||||
|
</HashRouter>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let stopAll = screen.getByTestId("stop-all");
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(stopAll);
|
||||||
|
});
|
||||||
|
|
||||||
|
let errorDialog = screen.getByText("Failed to stop servers.");
|
||||||
|
|
||||||
|
expect(errorDialog).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Shows a UI error dialogue when start user server fails", async () => {
|
||||||
|
let spy = mockAsync();
|
||||||
|
let rejectSpy = mockAsyncRejection();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(
|
||||||
|
<Provider store={createStore(() => {}, {})}>
|
||||||
|
<HashRouter>
|
||||||
|
<Switch>
|
||||||
|
<ServerDashboard
|
||||||
|
updateUsers={spy}
|
||||||
|
shutdownHub={spy}
|
||||||
|
startServer={rejectSpy}
|
||||||
|
stopServer={spy}
|
||||||
|
startAll={spy}
|
||||||
|
stopAll={spy}
|
||||||
|
/>
|
||||||
|
</Switch>
|
||||||
|
</HashRouter>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let start = screen.getByText("Start Server");
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(start);
|
||||||
|
});
|
||||||
|
|
||||||
|
let errorDialog = screen.getByText("Failed to start server.");
|
||||||
|
|
||||||
|
expect(errorDialog).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Shows a UI error dialogue when start user server returns an improper status code", async () => {
|
||||||
|
let spy = mockAsync();
|
||||||
|
let rejectSpy = mockAsync({ status: 403 });
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(
|
||||||
|
<Provider store={createStore(() => {}, {})}>
|
||||||
|
<HashRouter>
|
||||||
|
<Switch>
|
||||||
|
<ServerDashboard
|
||||||
|
updateUsers={spy}
|
||||||
|
shutdownHub={spy}
|
||||||
|
startServer={rejectSpy}
|
||||||
|
stopServer={spy}
|
||||||
|
startAll={spy}
|
||||||
|
stopAll={spy}
|
||||||
|
/>
|
||||||
|
</Switch>
|
||||||
|
</HashRouter>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let start = screen.getByText("Start Server");
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(start);
|
||||||
|
});
|
||||||
|
|
||||||
|
let errorDialog = screen.getByText("Failed to start server.");
|
||||||
|
|
||||||
|
expect(errorDialog).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Shows a UI error dialogue when stop user servers fails", async () => {
|
||||||
|
let spy = mockAsync();
|
||||||
|
let rejectSpy = mockAsyncRejection();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(
|
||||||
|
<Provider store={createStore(() => {}, {})}>
|
||||||
|
<HashRouter>
|
||||||
|
<Switch>
|
||||||
|
<ServerDashboard
|
||||||
|
updateUsers={spy}
|
||||||
|
shutdownHub={spy}
|
||||||
|
startServer={spy}
|
||||||
|
stopServer={rejectSpy}
|
||||||
|
startAll={spy}
|
||||||
|
stopAll={spy}
|
||||||
|
/>
|
||||||
|
</Switch>
|
||||||
|
</HashRouter>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let stop = screen.getByText("Stop Server");
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(stop);
|
||||||
|
});
|
||||||
|
|
||||||
|
let errorDialog = screen.getByText("Failed to stop server.");
|
||||||
|
|
||||||
|
expect(errorDialog).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Shows a UI error dialogue when stop user server returns an improper status code", async () => {
|
||||||
|
let spy = mockAsync();
|
||||||
|
let rejectSpy = mockAsync({ status: 403 });
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
render(
|
||||||
|
<Provider store={createStore(() => {}, {})}>
|
||||||
|
<HashRouter>
|
||||||
|
<Switch>
|
||||||
|
<ServerDashboard
|
||||||
|
updateUsers={spy}
|
||||||
|
shutdownHub={spy}
|
||||||
|
startServer={spy}
|
||||||
|
stopServer={rejectSpy}
|
||||||
|
startAll={spy}
|
||||||
|
stopAll={spy}
|
||||||
|
/>
|
||||||
|
</Switch>
|
||||||
|
</HashRouter>
|
||||||
|
</Provider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let stop = screen.getByText("Stop Server");
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(stop);
|
||||||
|
});
|
||||||
|
|
||||||
|
let errorDialog = screen.getByText("Failed to stop server.");
|
||||||
|
|
||||||
|
expect(errorDialog).toBeVisible();
|
||||||
|
});
|
||||||
|
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user