Diplay ECU name in update status (#110)

Optimize car update status progress control
Remove car update status page test
Replace with individual component tests
This commit is contained in:
John Wu
2021-11-15 09:12:03 -08:00
committed by GitHub
parent 4318ce9048
commit 537e8ed30b
14 changed files with 2540 additions and 1068 deletions

View File

@@ -0,0 +1,150 @@
import React from "react";
import { render, waitFor } from "@testing-library/react";
import CarUpdateStatusProgress from "../CarUpdateStatusProgress";
import useStyles from "../../useStyles";
const TestWrapper = ({ status }) => {
const classes = useStyles();
return <CarUpdateStatusProgress status={status} classes={classes} />;
};
const renderCarUpdateStatusProgress = async (status) => {
const { container } = render(<TestWrapper status={status} />);
await waitFor(() => {});
return container;
};
describe("CarUpdateStatusProgress", () => {
const tests = [
{
name: "manifest_received",
status: {
car_update_id: 297,
msg: "manifest_received",
err: -6,
extra_info: "",
},
},
{
name: "manifest_accepted",
status: {
car_update_id: 297,
msg: "manifest_accepted",
err: -7,
extra_info: "",
},
},
{
name: "download_started",
status: {
car_update_id: 297,
msg: "download_started",
err: -14,
extra_info: "",
},
},
{
name: "download_start ECU",
status: {
car_update_id: 297,
ecu: "ADAS",
file_current: 0,
file_total: 1264672,
package_current: 0,
package_total: 2529856,
msg: "download_start",
err: 0,
},
},
{
name: "downloading",
status: {
car_update_id: 297,
ecu: "ADAS",
file_current: 1048576,
file_total: 1264672,
package_current: 1048576,
package_total: 2529856,
msg: "downloading",
err: 0,
},
},
{
name: "download_complete",
status: {
car_update_id: 297,
ecu: "ADAS",
file_current: 1264672,
file_total: 1264672,
package_current: 1264672,
package_total: 2529856,
msg: "download_complete",
err: 0,
},
},
{
name: "package_download_complete",
status: {
car_update_id: 297,
msg: "package_download_complete",
err: -15,
extra_info: "",
},
},
{
name: "download_error",
status: {
car_update_id: 1,
ecu: "TEST",
file_current: 0,
file_total: 100,
package_current: 0,
package_total: 1000,
msg: "download_error",
err: 0,
},
},
{
name: "installing",
status: {
car_update_id: 1,
ecu: "TEST",
installed: 5,
total_files: 10,
msg: "installing",
err: 0,
},
},
{
name: "install_complete ECU",
status: {
car_update_id: 1,
ecu: "TEST",
installed: 10,
total_files: 10,
msg: "install_complete",
err: 0,
},
},
{
name: "install_error",
status: {
car_update_id: 1,
ecu: "TEST",
installed: 5,
total_files: 10,
msg: "install_error",
err: 0,
},
},
];
for (let i = 0, len = tests.length; i < len; i++) {
const test = tests[i];
it(`Render ${test.name}`, async () => {
const container = await renderCarUpdateStatusProgress(test.status);
expect(container).toMatchSnapshot();
});
}
});

View File

@@ -5,6 +5,80 @@ import clsx from "clsx";
import CircularProgress from "../CircularProgress";
const PHASES = [
{
label: "Pending",
events: ["pending"],
progress: () => 100,
},
{
label: "Recieved",
events: ["manifest_accepted", "manifest_received"],
progress: () => 100,
},
{
label: "Precondition",
events: ["requirements_succeeded"],
progress: () => 100,
},
{
label: "Download",
events: [
"downloading",
"download_start",
"download_complete",
"download_error",
"package_download_start",
],
progress: (msg, progress) =>
[
"package_download_start",
"downloading",
"download_start",
"download_complete",
].indexOf(msg) > -1
? progress
: -100,
},
{
label: "Approved",
events: ["package_download_complete", "install_approval_await"],
progress: () => -1,
},
{
label: "Install",
events: [
"install_approval_received",
"install_start",
"installing",
"install_complete",
"install_error",
],
progress: (msg, progress) =>
[
"install_approval_received",
"install_start",
"installing",
"install_complete",
].indexOf(msg) > -1
? progress
: -100,
},
{
label: "Clean up",
events: ["package_install_complete", "cleanup_failed"],
progress: (msg, progress) => {
if (msg === "package_install_complete") return -1;
return -100;
},
},
{
label: "Updated",
events: ["cleanup_success", "manifest_succeeded"],
progress: (msg, progress) => 100,
},
];
const Progress = ({ value, classes }) => {
if (value === 100)
return (
@@ -21,63 +95,26 @@ const Progress = ({ value, classes }) => {
return <RadioButtonUnchecked className={classes.progressIcon} />;
};
const getProgress = (index, phase, progress) => {
if (index === phase) return progress;
if (index < phase) return 100;
return -1;
};
const CarUpdateStatus = ({ status, classes }) => {
const [approval, setApproval] = useState(-1);
const [cleanup, setCleanup] = useState(-1);
const [download, setDownload] = useState(-1);
const [install, setInstall] = useState(-1);
const [precondition, setPrecondition] = useState(-1);
const [received, setReceived] = useState(-1);
const [updated, setUpdated] = useState(-1);
const [phase, setPhase] = useState(0);
const [progress, setProgress] = useState(-1);
useEffect(() => {
/* eslint-disable no-fallthrough, default-case */
if (!status) return;
// update previous steps
switch (status.msg) {
case "manifest_succeeded":
setUpdated(100);
case "cleanup_success":
setCleanup(100);
case "package_install_complete":
setInstall(100);
case "install_approval_received":
setApproval(100);
case "install_approval_await":
case "install_start":
case "installing":
case "install_complete":
case "install_error":
case "package_download_complete":
setDownload(100);
case "download_start":
case "downloading":
case "download_complete":
case "download_error":
case "package_download_start":
case "requirements_succeeded":
setPrecondition(100);
case "manifest_accepted":
case "manifest_received":
setReceived(100);
}
// update progress and errors
switch (status.msg) {
case "installing":
setInstall(status.progress);
break;
case "install_error":
setInstall(-100);
break;
case "downloading":
setDownload(status.progress);
break;
case "download_error":
setDownload(-100);
break;
case "cleanup_failed":
setCleanup(-100);
for (let i = 0, len = PHASES.length; i < len; i++) {
const PHASE = PHASES[i];
if (PHASE.events.indexOf(status.msg) > -1) {
setPhase(i);
setProgress(PHASE.progress(status.msg, status.progress));
break;
}
}
}, [status]);
@@ -90,38 +127,17 @@ const CarUpdateStatus = ({ status, classes }) => {
flexWrap: "wrap",
}}
>
<div className={classes.textCenterAlign}>
<Progress value={100} classes={classes} />
<Typography>Pending</Typography>
</div>
<div className={classes.textCenterAlign}>
<Progress value={received} classes={classes} />
<Typography>Recieved</Typography>
</div>
<div className={classes.textCenterAlign}>
<Progress value={precondition} classes={classes} />
<Typography>Precondition</Typography>
</div>
<div className={classes.textCenterAlign}>
<Progress value={download} classes={classes} />
<Typography>Download</Typography>
</div>
<div className={classes.textCenterAlign}>
<Progress value={approval} classes={classes} />
<Typography>Approved</Typography>
</div>
<div className={classes.textCenterAlign}>
<Progress value={install} classes={classes} />
<Typography>Install</Typography>
</div>
<div className={classes.textCenterAlign}>
<Progress value={cleanup} classes={classes} />
<Typography>Clean up</Typography>
</div>
<div className={classes.textCenterAlign}>
<Progress value={updated} classes={classes} />
<Typography>Updated</Typography>
</div>
{PHASES.map((item, index) => {
return (
<div key={index} className={classes.textCenterAlign}>
<Progress
value={getProgress(index, phase, progress)}
classes={classes}
/>
<Typography>{item.label}</Typography>
</div>
);
})}
</div>
);
};

View File

@@ -0,0 +1,42 @@
jest.mock("../../Contexts/CarUpdatesContext");
import React from "react";
import { render, waitFor } from "@testing-library/react";
import { CarUpdatesProvider } from "../../Contexts/CarUpdatesContext";
import CarUpdateStatusTable from "../CarUpdateStatusTable";
import { StatusProvider } from "../../Contexts/StatusContext";
import { TEST_AUTH_OBJECT } from "../../../utils/testing";
const renderCarUpdateStatusTable = async () => {
const { container } = render(
<StatusProvider>
<CarUpdatesProvider>
<CarUpdateStatusTable carupdateid={283} token={TEST_AUTH_OBJECT} />
</CarUpdatesProvider>
</StatusProvider>
);
await waitFor(() => {});
return container;
};
describe("CarUpdateStatusTable", () => {
beforeAll(() => {
expect.addSnapshotSerializer({
test: function (val) {
return val && typeof val === "string" && val.indexOf("mui-") >= 0;
},
print: function (val) {
let str = val;
str = str.replace(/mui-\d*/g, "mui-00000");
return `"${str}"`;
},
});
});
it("Render", async () => {
const container = await renderCarUpdateStatusTable();
expect(container).toMatchSnapshot();
});
});

View File

@@ -0,0 +1,285 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CarUpdateStatusTable Render 1`] = `
<div>
<div
data-testid="mocked-carupdatesprovider"
>
<table
class="MuiTable-root"
>
<thead
class="MuiTableHead-root"
>
<tr
class="MuiTableRow-root MuiTableRow-head"
>
<th
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
scope="col"
>
<span
aria-disabled="false"
class="MuiButtonBase-root MuiTableSortLabel-root"
role="button"
tabindex="0"
>
Date
<svg
aria-hidden="true"
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
/>
</svg>
</span>
</th>
<th
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
scope="col"
>
<span
aria-disabled="false"
class="MuiButtonBase-root MuiTableSortLabel-root"
role="button"
tabindex="0"
>
Status
<svg
aria-hidden="true"
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
/>
</svg>
</span>
</th>
<th
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
scope="col"
>
<span
aria-disabled="false"
class="MuiButtonBase-root MuiTableSortLabel-root"
role="button"
tabindex="0"
>
Info
<svg
aria-hidden="true"
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
/>
</svg>
</span>
</th>
<th
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
scope="col"
>
<span
aria-disabled="false"
class="MuiButtonBase-root MuiTableSortLabel-root"
role="button"
tabindex="0"
>
Error
<svg
aria-hidden="true"
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
/>
</svg>
</span>
</th>
</tr>
</thead>
<tbody
class="MuiTableBody-root"
>
<tr
class="MuiTableRow-root"
>
<td
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
>
8/23/2021 5:06:38 PM
</td>
<td
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
>
package_install_complete
</td>
<td
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
/>
<td
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
/>
</tr>
<tr
class="MuiTableRow-root"
>
<td
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
>
8/23/2021 5:06:38 PM
</td>
<td
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
>
package_install_start
</td>
<td
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
>
TEST
</td>
<td
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
/>
</tr>
</tbody>
<tfoot
class="MuiTableFooter-root"
>
<tr
class="MuiTableRow-root MuiTableRow-footer"
>
<td
class="MuiTableCell-root MuiTableCell-footer MuiTablePagination-root"
colspan="5"
>
<div
class="MuiToolbar-root MuiToolbar-regular MuiTablePagination-toolbar MuiToolbar-gutters"
>
<div
class="MuiTablePagination-spacer"
/>
<p
class="MuiTypography-root MuiTablePagination-caption MuiTypography-body2 MuiTypography-colorInherit"
id="mui-00000"
>
Rows per page:
</p>
<div
class="MuiInputBase-root MuiTablePagination-input MuiTablePagination-selectRoot"
>
<select
aria-label="rows per page"
class="MuiSelect-root MuiSelect-select MuiTablePagination-select MuiInputBase-input"
id="mui-00000"
>
<option
class="MuiTablePagination-menuItem"
value="5"
>
5
</option>
<option
class="MuiTablePagination-menuItem"
value="10"
>
10
</option>
<option
class="MuiTablePagination-menuItem"
value="25"
>
25
</option>
<option
class="MuiTablePagination-menuItem"
value="100"
>
100
</option>
</select>
<svg
aria-hidden="true"
class="MuiSvgIcon-root MuiSelect-icon MuiTablePagination-selectIcon"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M7 10l5 5 5-5z"
/>
</svg>
</div>
<p
class="MuiTypography-root MuiTablePagination-caption MuiTypography-body2 MuiTypography-colorInherit"
>
1-2 of 2
</p>
<div
class="MuiTablePagination-actions"
>
<button
aria-label="Previous page"
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit Mui-disabled Mui-disabled"
disabled=""
tabindex="-1"
title="Previous page"
type="button"
>
<span
class="MuiIconButton-label"
>
<svg
aria-hidden="true"
class="MuiSvgIcon-root"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"
/>
</svg>
</span>
</button>
<button
aria-label="Next page"
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit Mui-disabled Mui-disabled"
disabled=""
tabindex="-1"
title="Next page"
type="button"
>
<span
class="MuiIconButton-label"
>
<svg
aria-hidden="true"
class="MuiSvgIcon-root"
focusable="false"
viewBox="0 0 24 24"
>
<path
d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"
/>
</svg>
</span>
</button>
</div>
</div>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
`;