CEC-180 Cache Control (#30)
* Set cache expire to 1 day Add snapshot tests for new screens * Fix table pagniation random ids for snapshot tests * Auto reload on chunk load error * OTA Admin Portal => Admin Portal
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
jest.mock("../Contexts/UserContext");
|
||||
jest.mock("../Contexts/FileUploadContext");
|
||||
jest.mock("../Contexts/VehicleContext");
|
||||
jest.mock("../Contexts/UpdatesContext");
|
||||
jest.mock("../Contexts/UserContext");
|
||||
jest.mock("../../services/monitoring");
|
||||
|
||||
import { render, screen, cleanup, waitForElementToBeRemoved } from "@testing-library/react";
|
||||
@@ -19,7 +20,27 @@ const renderRoute = async (route) => {
|
||||
return container;
|
||||
};
|
||||
|
||||
const check = async (path, selector, compare) => {
|
||||
const container = await renderRoute(path);
|
||||
expect(container.querySelector(selector).innerHTML).toEqual(compare);
|
||||
expect(container).toMatchSnapshot();
|
||||
};
|
||||
|
||||
describe("App", () => {
|
||||
beforeAll(() => {
|
||||
// Stablize Table Pagination control ids
|
||||
expect.addSnapshotSerializer({
|
||||
test: function(val) {
|
||||
return val && typeof val === "string" && val.indexOf("mui-") >= 0;
|
||||
},
|
||||
print: function(val) {
|
||||
let str = val;
|
||||
str = str.replace(/mui-[0-9]*/g, "mui-00000");
|
||||
|
||||
return `"${str}"`;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
setToken(null);
|
||||
@@ -27,67 +48,101 @@ describe("App", () => {
|
||||
});
|
||||
|
||||
it("Route / unauthenticated", async () => {
|
||||
const container = await renderRoute("/");
|
||||
expect(container.querySelector("span.MuiButton-label").innerHTML).toEqual("Sign In");
|
||||
expect(container).toMatchSnapshot();
|
||||
await check("/", "span.MuiButton-label", "Sign In");
|
||||
});
|
||||
|
||||
it("Route /home unauthenticated", async () => {
|
||||
const container = await renderRoute("/home");
|
||||
expect(container.querySelector("span.MuiButton-label").innerHTML).toEqual("Sign In");
|
||||
expect(container).toMatchSnapshot();
|
||||
await check("/home", "span.MuiButton-label", "Sign In");
|
||||
});
|
||||
|
||||
it("Route /package-upload unauthenticated", async () => {
|
||||
const container = await renderRoute("/package-upload");
|
||||
expect(container.querySelector("span.MuiButton-label").innerHTML).toEqual("Sign In");
|
||||
expect(container).toMatchSnapshot();
|
||||
await check("/package-upload", "span.MuiButton-label", "Sign In");
|
||||
});
|
||||
|
||||
it("Route /vehicle-add unauthenticated", async () => {
|
||||
const container = await renderRoute("/vehicle-add");
|
||||
expect(container.querySelector("span.MuiButton-label").innerHTML).toEqual("Sign In");
|
||||
expect(container).toMatchSnapshot();
|
||||
await check("/vehicle-add", "span.MuiButton-label", "Sign In");
|
||||
});
|
||||
|
||||
it("Route /updates unauthenticated", async () => {
|
||||
await check("/updates", "span.MuiButton-label", "Sign In");
|
||||
});
|
||||
|
||||
it("Route /update unauthenticated", async () => {
|
||||
await check("/update/1", "span.MuiButton-label", "Sign In");
|
||||
});
|
||||
|
||||
it("Route /carupdate-deploy unauthenticated", async () => {
|
||||
await check("/carupdate-deploy/1", "span.MuiButton-label", "Sign In");
|
||||
});
|
||||
|
||||
it("Route /carupdate-status unauthenticated", async () => {
|
||||
await check("/carupdate-status/1", "span.MuiButton-label", "Sign In");
|
||||
});
|
||||
|
||||
it("Route /vehicles unauthenticated", async () => {
|
||||
await check("/vehicles", "span.MuiButton-label", "Sign In");
|
||||
});
|
||||
|
||||
it("Route /vehicle-status unauthenticated", async () => {
|
||||
await check("/vehicle-status/FISKER123", "span.MuiButton-label", "Sign In");
|
||||
});
|
||||
|
||||
it("Route / authenticated", async () => {
|
||||
setToken(TEST_AUTH_OBJECT);
|
||||
const container = await renderRoute("/");
|
||||
expect(container.querySelector("h1").innerHTML).toEqual("Welcome John!");
|
||||
expect(container).toMatchSnapshot();
|
||||
await check("/", "h1", "Welcome John!");
|
||||
});
|
||||
|
||||
it("Route /home authenticated", async () => {
|
||||
setToken(TEST_AUTH_OBJECT);
|
||||
const container = await renderRoute("/home");
|
||||
expect(container.querySelector("h1").innerHTML).toEqual("Welcome John!");
|
||||
expect(container).toMatchSnapshot();
|
||||
await check("/home", "h1", "Welcome John!");
|
||||
});
|
||||
|
||||
it("Route /package-upload authenticated", async () => {
|
||||
setToken(TEST_AUTH_OBJECT);
|
||||
const container = await renderRoute("/package-upload");
|
||||
expect(container.querySelector("h1").innerHTML).toEqual("Upload Update Package");
|
||||
expect(container).toMatchSnapshot();
|
||||
await check("/package-upload", "h1", "Upload Update Package");
|
||||
});
|
||||
|
||||
it("Route /vehicle-add authenticated", async () => {
|
||||
setToken(TEST_AUTH_OBJECT);
|
||||
const container = await renderRoute("/vehicle-add");
|
||||
expect(container.querySelector("h1").innerHTML).toEqual("Add Vehicle");
|
||||
expect(container).toMatchSnapshot();
|
||||
await check("/vehicle-add", "h1", "Add Vehicle");
|
||||
});
|
||||
|
||||
it("Route /updates authenticated", async () => {
|
||||
setToken(TEST_AUTH_OBJECT);
|
||||
await check("/updates", "h1", "Updates");
|
||||
});
|
||||
|
||||
it("Route /update authenticated", async () => {
|
||||
setToken(TEST_AUTH_OBJECT);
|
||||
await check("/update/1", "h1", "Update Package 1");
|
||||
});
|
||||
|
||||
it("Route /carupdate-deploy authenticated", async () => {
|
||||
setToken(TEST_AUTH_OBJECT);
|
||||
await check("/carupdate-deploy/1", "h1", "[1] ");
|
||||
});
|
||||
|
||||
it("Route /carupdate-status authenticated", async () => {
|
||||
setToken(TEST_AUTH_OBJECT);
|
||||
await check("/carupdate-status/1", "h1", "");
|
||||
});
|
||||
|
||||
it("Route /vehicles authenticated", async () => {
|
||||
setToken(TEST_AUTH_OBJECT);
|
||||
await check("/vehicles", "h1", "Vehicles");
|
||||
});
|
||||
|
||||
it("Route /vehicle-status authenticated", async () => {
|
||||
setToken(TEST_AUTH_OBJECT);
|
||||
await check("/vehicle-status/FISKER123", "h1", "FISKER123 Updates");
|
||||
});
|
||||
|
||||
it("Route /page-not-found unauthenticated", async () => {
|
||||
const container = await renderRoute("/page-not-found");
|
||||
expect(container.querySelector("h1").innerHTML).toEqual("Page Not Found");
|
||||
expect(container).toMatchSnapshot();
|
||||
await check("/page-not-found", "h1", "Page Not Found");
|
||||
});
|
||||
|
||||
it("Route /page-not-found authenticated", async () => {
|
||||
setToken(TEST_AUTH_OBJECT);
|
||||
const container = await renderRoute("/page-not-found");
|
||||
expect(container.querySelector("h1").innerHTML).toEqual("Page Not Found");
|
||||
expect(container).toMatchSnapshot();
|
||||
await check("/page-not-found", "h1", "Page Not Found");
|
||||
});
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
@@ -49,7 +49,7 @@ export default function CarStatusModal(props) {
|
||||
aria-labelledby="transition-modal-title"
|
||||
aria-describedby="transition-modal-description"
|
||||
className={classes.modal}
|
||||
open={props.vin}
|
||||
open={props.vin !== null && props.vin !== undefined}
|
||||
onClose={props.handleClose}
|
||||
BackdropComponent={Backdrop}
|
||||
BackdropProps={{
|
||||
|
||||
@@ -7,8 +7,8 @@ import {
|
||||
fireEvent,
|
||||
waitFor,
|
||||
} from "@testing-library/react";
|
||||
import { UpdatesProvider, useUpdatesContext } from "../Contexts/UpdatesContext";
|
||||
import { StatusProvider, useStatusContext } from "../Contexts/StatusContext";
|
||||
import { UpdatesProvider, useUpdatesContext } from "./UpdatesContext";
|
||||
import { StatusProvider, useStatusContext } from "./StatusContext";
|
||||
import { TEST_AUTH_OBJECT } from "../../utils/testing";
|
||||
|
||||
describe("UpdatesContext", () => {
|
||||
26
src/components/Contexts/__mocks__/UpdatesContext.jsx
Normal file
26
src/components/Contexts/__mocks__/UpdatesContext.jsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import React from "react";
|
||||
|
||||
const UpdatesContext = React.createContext();
|
||||
|
||||
let busy = false;
|
||||
let packages = [];
|
||||
let totalPackages = 0;
|
||||
let carUpdates = [];
|
||||
let totalCarUpdates = 0;
|
||||
|
||||
export const UpdatesProvider = ({ children }) => {
|
||||
return <div data-testid="mocked-updatesprovider">{children}</div>;
|
||||
};
|
||||
|
||||
export const useUpdatesContext = () => ({
|
||||
busy,
|
||||
packages,
|
||||
totalPackages,
|
||||
carUpdates,
|
||||
totalCarUpdates,
|
||||
getPackages: jest.fn(() => packages),
|
||||
updatePackage: jest.fn((data) => data),
|
||||
createCarUpdates: jest.fn((data) => data),
|
||||
getCarUpdates: jest.fn(() => carUpdates),
|
||||
getVINUpdates: jest.fn(() => carUpdates),
|
||||
});
|
||||
@@ -2,6 +2,7 @@ import React from "react";
|
||||
|
||||
let busy = false;
|
||||
let vehicles = [];
|
||||
let totalVehicles = 0;
|
||||
let error = null;
|
||||
|
||||
export const VehicleProvider = ({ children }) => {
|
||||
@@ -11,6 +12,7 @@ export const VehicleProvider = ({ children }) => {
|
||||
export const useVehicleContext = () => ({
|
||||
busy,
|
||||
vehicles,
|
||||
totalVehicles,
|
||||
getVehicles: jest.fn(() => vehicles),
|
||||
addVehicle: jest.fn(),
|
||||
});
|
||||
|
||||
@@ -2,25 +2,60 @@ import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Typography } from "@material-ui/core";
|
||||
|
||||
const reload = () => {
|
||||
window.location.reload();
|
||||
};
|
||||
export default class ErrorBoundary extends Component {
|
||||
state = {
|
||||
error: "",
|
||||
errorInfo: "",
|
||||
hasError: false,
|
||||
};
|
||||
|
||||
static getDerivedStateFromError(error) {
|
||||
return { hasError: true, error };
|
||||
}
|
||||
|
||||
componentDidCatch(error, errorInfo) {
|
||||
this.setState({ errorInfo });
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError)
|
||||
if (this.state.hasError) {
|
||||
if (this.state.error && this.state.error.name === "ChunkLoadError") {
|
||||
reload();
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography variant="h3" align="center">
|
||||
Client-side Error Occured and Logged
|
||||
</Typography>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
}}
|
||||
>
|
||||
<Typography variant="h3" align="center">
|
||||
Sorry, an error has occured and been logged
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h5"
|
||||
align="center"
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
textDecorationColor: "Blue",
|
||||
textDecorationStyle: "solid",
|
||||
textDecorationLine: "underline",
|
||||
color: "Blue",
|
||||
}}
|
||||
onClick={reload}
|
||||
>
|
||||
Click to reload
|
||||
</Typography>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user