Merge branch 'release/0.0.3'

This commit is contained in:
jwu-fisker
2022-10-05 14:18:38 -07:00
45 changed files with 1127 additions and 347 deletions

View File

@@ -1,8 +1,8 @@
import React, { useContext, useState, useEffect } from "react";
import React, {useContext, useState} from "react";
import api from "../../services/vehiclesAPI";
import { useUserContext } from "./UserContext";
import { LocalDateTimeString } from "../../utils/dates";
import {useInterval} from "usehooks-ts";
const CANSignalContext = React.createContext();
@@ -15,41 +15,26 @@ const BlankSignal = (msg) => ({
const transformSignals = (signals) =>
signals
.map((signal) => {
const { Timestamp, ...Settings } = signal;
const keys = Object.keys(Settings);
const { timestamp, value, name } = signal;
return keys.map((key) => ({
timestamp: LocalDateTimeString(Timestamp),
signal: key,
value: Settings[key],
}));
return {
timestamp: LocalDateTimeString(timestamp),
signal: name,
value: value,
};
})
.flat();
export const CANSignalProvider = ({ children }) => {
const {
token: {
idToken: { jwtToken: token },
},
} = useUserContext();
export const CANSignalProvider = ({ token, children }) => {
const [vin, setVIN] = useState(null);
const [signals, setSignals] = useState([]);
let delay = 500;
const [delay, setDelay] = useState(500);
useEffect(() => {
getCANSignals();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [vin]);
useEffect(() => {
const timer = setTimeout(() => {
getCANSignals();
}, delay);
return () => {
clearTimeout(timer);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [signals]);
useInterval(
() => {
getCANSignals()
}, vin?delay:null
)
const getCANSignals = async () => {
try {
@@ -62,10 +47,10 @@ export const CANSignalProvider = ({ children }) => {
const items = transformSignals(result.data);
if (items.length > 0) {
delay = 500;
setDelay(500);
setSignals(items);
} else {
delay = 1000;
setDelay(1000);
setSignals([BlankSignal("No signals")]);
}
} catch (e) {

View File

@@ -0,0 +1,75 @@
jest.mock("../../services/vehiclesAPI");
import {
render,
cleanup,
screen,
fireEvent,
waitFor,
act,
} from "@testing-library/react";
import {CANSignalProvider, useCANSignalContext} from "./CANSignalsContext";
const checkSignalsResults = (filters) => {
expect(screen.getByTestId("signals").innerHTML).toEqual(filters);
};
describe("CANSignalsContext", () => {
describe("getSignals", () => {
beforeEach(() => {
jest.useFakeTimers("setInterval");
const TestComp = () => {
const { signals, setVIN } = useCANSignalContext();
return (
<>
<div data-testid="signals">{JSON.stringify(signals)}</div>
<button
data-testid="getSignals"
onClick={()=>{setVIN("TESTVIN1234567890")}}
/>
</>
);
};
render(
<CANSignalProvider>
<TestComp />
</CANSignalProvider>
);
});
afterEach(() => {
jest.useRealTimers();
cleanup();
});
it("initial state", () => {
checkSignalsResults("[]");
});
it("getSignals", async () => {
// eslint-disable-next-line testing-library/no-unnecessary-act
await act(async () => {
fireEvent.click(screen.getByTestId("getSignals"));
await waitFor(() =>
expect(screen.getByTestId("signals").innerHTML).toBe("[]")
);
jest.advanceTimersByTime(501);
})
await waitFor(() => {
return expect(screen.getByTestId("signals").innerHTML).not.toBe("[]");
} );
checkSignalsResults(JSON.stringify(expectedSignalsData));
});
});
});
const expectedSignalsData = [
{
timestamp: "7/14/2021 8:09:40 PM",
signal: "signal",
value: 123
},
];

View File

@@ -139,7 +139,7 @@ describe("FleetContext", () => {
onClick={() =>
add({
name: "EU-WEST",
log_level: "warn",
log_level: "warning",
canbus: { enabled: false },
})
}
@@ -219,7 +219,7 @@ describe("FleetContext", () => {
onClick={() =>
update({
name: "EU-WEST",
log_level: "warn",
log_level: "warning",
canbus: { enabled: false },
})
}
@@ -782,7 +782,7 @@ const expectedFleetsData = [
},
{
name: "US-CENTRAL",
log_level: "warn",
log_level: "warning",
canbus: {
enabled: false,
data_logger_enabled: false,

View File

@@ -31,6 +31,8 @@ export const VehicleProvider = ({ children }) => {
const [vehicle, setVehicle] = useState({});
const [vehicles, setVehicles] = useState([]);
const [totalVehicles, setTotalVehicles] = useState(0);
const [fleets, setFleets] = useState([]);
const [totalFleets, setTotalFleets] = useState(0);
const [models, setModels] = useState([]);
const [years, setYears] = useState([]);
@@ -45,6 +47,7 @@ export const VehicleProvider = ({ children }) => {
}
cars.forEach((car) => {
car.connected = result[car.vin] || false;
car.connectedHMI = result[`2:${car.vin}`] || false;
});
} catch (e) {
logger.error(e.stack);
@@ -219,6 +222,25 @@ export const VehicleProvider = ({ children }) => {
}
};
const getFleets = async (vin, search, token) => {
try {
setBusy(true);
validateVIN(vin);
const result = await api.getFleets(vin, search, token);
if (result.error) {
setFleets([]);
throw new Error(`Get Fleets of vehicle`)
}
setFleets(result.data ?? []);
if (result.total) {
setTotalFleets(result.total);
}
} finally {
setBusy(false)
}
}
return (
<VehicleContext.Provider
value={{
@@ -228,6 +250,8 @@ export const VehicleProvider = ({ children }) => {
vehicle,
vehicles,
years,
fleets,
totalFleets,
addVehicle,
deleteVehicle,
getConnections,
@@ -241,6 +265,7 @@ export const VehicleProvider = ({ children }) => {
getVehicles,
sendCommand,
updateVehicle,
getFleets,
}}
>
{children}

View File

@@ -13,19 +13,64 @@ import { StatusProvider, useStatusContext } from "./StatusContext";
const checkVehicleResult = (error, busy, vehicle) => {
checkBaseResults(error, busy);
expect(screen.getByTestId("vehicle").innerHTML).toEqual(vehicle);
}
};
const checkVehiclesResult = (error, busy, vehicles) => {
checkBaseResults(error, busy);
expect(screen.getByTestId("vehicles").innerHTML).toEqual(vehicles);
};
const checkFleetsResult = (error, busy, fleets) => {
checkBaseResults(error, busy);
expect(screen.getByTestId("fleets").innerHTML).toEqual(fleets);
};
const checkBaseResults = (error, busy) => {
expect(screen.getByTestId("error").innerHTML).toEqual(error);
expect(screen.getByTestId("busy").innerHTML).toEqual(busy);
};
describe("VehicleContext", () => {
describe("getFleets", () => {
beforeEach(() => {
const TestComp = () => {
const { busy, error, fleets, getFleets } = useVehicleContext();
return (
<>
<div data-testid="error">{error}</div>
<div data-testid="busy">{busy.toString()}</div>
<div data-testid="fleets">{JSON.stringify(fleets)}</div>
<button
data-testid="getFleets"
onClick={() => getFleets("3C4PDCBG0ET127145")}
/>
</>
);
};
render(
<VehicleProvider>
<TestComp />
</VehicleProvider>
);
});
afterEach(() => {
cleanup();
});
it("Initial state", () => {
checkFleetsResult("", "false", "[]");
});
it("getFleets", async () => {
fireEvent.click(screen.getByTestId("getFleets"));
await waitFor(() =>
expect(screen.getByTestId("fleets").innerHTML).not.toBe("[]")
);
checkFleetsResult("", "false", JSON.stringify(["fleet1", "fleet2"]));
});
});
describe("getVehicles", () => {
beforeEach(() => {
const TestComp = () => {
@@ -195,12 +240,22 @@ describe("VehicleContext", () => {
<>
<div data-testid="error">{message}</div>
<div data-testid="busy">{busy.toString()}</div>
<button data-testid="updateVehicleNull" onClick={() => update(null)} />
<button data-testid="updateVehicleNoVIN" onClick={() => update({})} />
<button
data-testid="updateVehicleNull"
onClick={() => update(null)}
/>
<button
data-testid="updateVehicleNoVIN"
onClick={() => update({})}
/>
<button
data-testid="updateVehicle"
onClick={() =>
update({ vin: "3C4PDCBG0ET127145", log_level: "warn", canbus: { enabled: false } })
update({
vin: "3C4PDCBG0ET127145",
log_level: "warning",
canbus: { enabled: false },
})
}
/>
</>
@@ -265,13 +320,17 @@ describe("VehicleContext", () => {
<>
<div data-testid="error">{message}</div>
<div data-testid="busy">{busy.toString()}</div>
<button data-testid="deleteVehicleNull" onClick={() => deleteV(null)} />
<button data-testid="deleteVehicleNonexistent" onClick={() => deleteV("11111111111111111")} />
<button
data-testid="deleteVehicleNull"
onClick={() => deleteV(null)}
/>
<button
data-testid="deleteVehicleNonexistent"
onClick={() => deleteV("11111111111111111")}
/>
<button
data-testid="deleteVehicle"
onClick={() =>
deleteV("3C4PDCBG0ET127145")
}
onClick={() => deleteV("3C4PDCBG0ET127145")}
/>
</>
);
@@ -321,7 +380,7 @@ describe("VehicleContext", () => {
describe("sendCommand", () => {
beforeEach(async () => {
const TestComp = () => {
const {busy, sendCommand} = useVehicleContext();
const { busy, sendCommand } = useVehicleContext();
const { message, setMessage } = useStatusContext();
const sendC = async (vin, command) => {
@@ -336,25 +395,38 @@ describe("VehicleContext", () => {
<>
<div data-testid="error">{message}</div>
<div data-testid="busy">{busy.toString()}</div>
<button data-testid="sendCommandNullVin" onClick={() => sendC(null, {command:"doors_lock"})} />
<button data-testid="sendCommandNonexistentVin" onClick={() => sendC(["11111111111111111"], {command:"doors_lock"})} />
<button
data-testid="sendCommandNullVin"
onClick={() => sendC(null, { command: "doors_lock" })}
/>
<button
data-testid="sendCommandNonexistentVin"
onClick={() =>
sendC(["11111111111111111"], { command: "doors_lock" })
}
/>
<button
data-testid="sendCommandVin"
onClick={() => sendC("3C4PDCBG0ET127145", {command:"doors_lock"})}
onClick={() =>
sendC("3C4PDCBG0ET127145", { command: "doors_lock" })
}
/>
<button
data-testid="sendCommandWrongCommand"
onClick={() => sendC("3C4PDCBG0ET127145", {command:"noSuchCommand"})}
onClick={() =>
sendC("3C4PDCBG0ET127145", { command: "noSuchCommand" })
}
/>
</>
);}
render(
<StatusProvider>
<VehicleProvider>
<TestComp />
</VehicleProvider>
</StatusProvider>
</>
);
};
render(
<StatusProvider>
<VehicleProvider>
<TestComp />
</VehicleProvider>
</StatusProvider>
);
});
afterEach(() => {
@@ -364,24 +436,23 @@ describe("VehicleContext", () => {
it("initial state", () => {
checkBaseResults("", "false");
});
})
});
});
const expectedFilters = [
{
can_id: "123-456",
interval: 789
interval: 789,
},
{
can_id: "1",
interval: 1000
interval: 1000,
},
{
can_id: "1000",
interval: 1
}
]
interval: 1,
},
];
const expectedVehicleData = {
vin: "3C4PDCBG0ET127145",
@@ -390,9 +461,16 @@ const expectedVehicleData = {
trim: "Basic",
ecu_list: "ECUA 2.0.0, ECUB 2.1.1",
log_level: "info",
canbus: { enabled: true, data_logger_enabled: true, max_mem_buffer_size: 1, max_disk_buffer_size: 2, filters: expectedFilters },
canbus: {
enabled: true,
data_logger_enabled: true,
max_mem_buffer_size: 1,
max_disk_buffer_size: 2,
filters: expectedFilters,
},
connected: true,
}
connectedHMI: false,
};
const expectedVehiclesData = [
{
@@ -402,19 +480,44 @@ const expectedVehiclesData = [
trim: "Basic",
ecu_list: "ECUA 2.0.0, ECUB 2.1.1",
log_level: "info",
canbus: { enabled: true, data_logger_enabled: true, max_mem_buffer_size: 1, max_disk_buffer_size: 2, filters: expectedFilters },
canbus: {
enabled: true,
data_logger_enabled: true,
max_mem_buffer_size: 1,
max_disk_buffer_size: 2,
filters: expectedFilters,
},
connected: true,
connectedHMI: false,
},
{ vin: "1G1FP87S3GN100062", connected: true, connectedHMI: false },
{
vin: "1HGCG325XYA062256",
year: 2021,
connected: true,
connectedHMI: false,
},
{
vin: "1J4GZ78YXWC160024",
year: 2021,
model: "Ocean",
connected: true,
connectedHMI: false,
},
{
vin: "2C3CCAAG8CH222800",
model: "Ocean",
trim: "Basic",
connected: true,
connectedHMI: false,
},
{ vin: "1G1FP87S3GN100062", connected: true },
{ vin: "1HGCG325XYA062256", year: 2021, connected: true },
{ vin: "1J4GZ78YXWC160024", year: 2021, model: "Ocean", connected: true },
{ vin: "2C3CCAAG8CH222800", model: "Ocean", trim: "Basic", connected: true },
{
vin: "KNADM4A39C6028108",
year: 2021,
model: "Ocean",
trim: "Basic",
connected: true,
connectedHMI: false,
},
{
vin: "1G11C5SL9FF153507",
@@ -422,5 +525,6 @@ const expectedVehiclesData = [
model: "Ocean",
trim: "Basic",
connected: true,
connectedHMI: false,
},
];

View File

@@ -28,7 +28,7 @@ let fleets = [
},
{
name: "US-CENTRAL",
log_level: "warn",
log_level: "warning",
canbus: { enabled: false, data_logger_enabled: false, max_mem_buffer_size: 0, max_disk_buffer_size: 0 },
vehicles: ["USCENTVIN12345678", "USCENTVIN12345679", "USCENTVIN12345670"]
},

View File

@@ -35,6 +35,7 @@ let vehicle = {
let vehicleState = {
data: {
online: false,
online_hmi: true,
battery: {
percent: 95,
},
@@ -77,6 +78,8 @@ let vehicles = [];
let models = ["Ocean", "PEAR"];
let years = [2023, 2024];
let totalVehicles = 0;
let fleets = ["fleet1", "fleet2"];
let totalFleets = 2;
let error = null;
export const VehicleProvider = ({ children }) => {
@@ -86,6 +89,8 @@ export const VehicleProvider = ({ children }) => {
export const useVehicleContext = () => ({
busy,
models,
fleets,
totalFleets,
totalVehicles,
vehicle,
vehicles,
@@ -141,6 +146,10 @@ export const useVehicleContext = () => ({
command,
parameters,
})),
getFleets: jest.fn((vin, search,_token) => {return {
data: ["fleet1", "fleet2"],
total: 2,
}}),
});
export const setBusy = (val) => {