Skip to content

Commit

Permalink
feat(ui): add storage card to machine details overview (#1839)
Browse files Browse the repository at this point in the history
  • Loading branch information
squidsoup authored Nov 4, 2020
1 parent faad1f5 commit 4e66346
Show file tree
Hide file tree
Showing 5 changed files with 320 additions and 10 deletions.
24 changes: 14 additions & 10 deletions ui/.betterer.results
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ exports[`stricter compilation`] = {
[162, 4, 36, "Object is possibly \'null\'.", "1039669632"]
],
"src/app/App.tsx:3872899616": [
[21, 7, 25, "Could not find a declaration file for module \'@maas-ui/maas-ui-shared\'. \'/home/caleb/Projects/maas-ui/shared/dist/index.js\' implicitly has an \'any\' type.\\n Try \`npm install @types/maas-ui__maas-ui-shared\` if it exists or add a new declaration (.d.ts) file containing \`declare module \'@maas-ui/maas-ui-shared\';\`", "1778274862"],
[21, 7, 25, "Could not find a declaration file for module \'@maas-ui/maas-ui-shared\'. \'/Users/kit/src/canonical/local/maas-ui/shared/dist/index.js\' implicitly has an \'any\' type.\\n Try \`npm install @types/maas-ui__maas-ui-shared\` if it exists or add a new declaration (.d.ts) file containing \`declare module \'@maas-ui/maas-ui-shared\';\`", "1778274862"],
[188, 17, 17, "Object is possibly \'null\'.", "2133029343"],
[193, 7, 7, "Variable \'content\' is used before being assigned.", "3716929964"]
],
Expand Down Expand Up @@ -44,7 +44,7 @@ exports[`stricter compilation`] = {
[75, 4, 5, "Argument of type \'boolean | undefined\' is not assignable to parameter of type \'boolean\'.\\n Type \'undefined\' is not assignable to type \'boolean\'.", "195688512"]
],
"src/app/base/components/LegacyLink/LegacyLink.tsx:2706551295": [
[4, 52, 25, "Could not find a declaration file for module \'@maas-ui/maas-ui-shared\'. \'/home/caleb/Projects/maas-ui/shared/dist/index.js\' implicitly has an \'any\' type.\\n Try \`npm install @types/maas-ui__maas-ui-shared\` if it exists or add a new declaration (.d.ts) file containing \`declare module \'@maas-ui/maas-ui-shared\';\`", "1778274862"]
[4, 52, 25, "Could not find a declaration file for module \'@maas-ui/maas-ui-shared\'. \'/Users/kit/src/canonical/local/maas-ui/shared/dist/index.js\' implicitly has an \'any\' type.\\n Try \`npm install @types/maas-ui__maas-ui-shared\` if it exists or add a new declaration (.d.ts) file containing \`declare module \'@maas-ui/maas-ui-shared\';\`", "1778274862"]
],
"src/app/base/components/NotificationGroup/Notification/Notification.tsx:122297593": [
[26, 26, 12, "Argument of type \'Notification | null\' is not assignable to parameter of type \'Notification\'.\\n Type \'null\' is not assignable to type \'Notification\'.\\n Type \'null\' is not assignable to type \'Model\'.", "148512008"],
Expand All @@ -63,8 +63,8 @@ exports[`stricter compilation`] = {
[31, 4, 11, "Type \'number\' is not assignable to type \'null\'.", "1179509236"],
[33, 4, 12, "Type \'number\' is not assignable to type \'null\'.", "304100367"]
],
"src/app/base/components/SectionHeader/SectionHeader.tsx:559969946": [
[58, 16, 3, "Type \'string | number | null\' is not assignable to type \'string | number | undefined\'.\\n Type \'null\' is not assignable to type \'string | number | undefined\'.", "193424690"]
"src/app/base/components/SectionHeader/SectionHeader.tsx:2959761336": [
[73, 16, 3, "Type \'string | number | null\' is not assignable to type \'string | number | undefined\'.\\n Type \'null\' is not assignable to type \'string | number | undefined\'.", "193424690"]
],
"src/app/base/components/TagSelector/TagSelector.test.tsx:846439984": [
[6, 6, 4, "Variable \'tags\' implicitly has type \'any\' in some locations where its type cannot be determined.", "2087952548"],
Expand All @@ -86,7 +86,7 @@ exports[`stricter compilation`] = {
[214, 7, 11, "Property \'placeholder\' is missing in type \'{ disabledTags: { id: number; name: string; }[]; initialSelected: { id: number; name: string; }[]; tags: { id: number; name: string; }[]; }\' but required in type \'Props\'.", "3766634306"]
],
"src/app/base/components/TagSelector/TagSelector.tsx:2755544058": [
[1, 18, 51, "Could not find a declaration file for module \'@canonical/react-components/dist/components/Field\'. \'/home/caleb/Projects/maas-ui/node_modules/@canonical/react-components/dist/components/Field/index.js\' implicitly has an \'any\' type.\\n Try \`npm install @types/canonical__react-components\` if it exists or add a new declaration (.d.ts) file containing \`declare module \'@canonical/react-components/dist/components/Field\';\`", "1535046059"],
[1, 18, 51, "Could not find a declaration file for module \'@canonical/react-components/dist/components/Field\'. \'/Users/kit/src/canonical/local/maas-ui/node_modules/@canonical/react-components/dist/components/Field/index.js\' implicitly has an \'any\' type.\\n Try \`npm install @types/canonical__react-components\` if it exists or add a new declaration (.d.ts) file containing \`declare module \'@canonical/react-components/dist/components/Field\';\`", "1535046059"],
[37, 2, 12, "Binding element \'allowNewTags\' implicitly has an \'any\' type.", "3979358209"],
[38, 2, 6, "Binding element \'filter\' implicitly has an \'any\' type.", "1355726373"],
[39, 2, 12, "Binding element \'selectedTags\' implicitly has an \'any\' type.", "2698915821"],
Expand Down Expand Up @@ -332,7 +332,7 @@ exports[`stricter compilation`] = {
[97, 10, 16, "Argument of type \'(BaseMachine | MachineDetails | undefined)[]\' is not assignable to parameter of type \'Machine[]\'.", "4020685210"]
],
"src/app/machines/hooks.tsx:3635236711": [
[45, 4, 76, "Element implicitly has an \'any\' type because expression of type \'string\' can\'t be used to index type \'{ aborting: Selector<RootState, Machine[]>; abortingSelected: Selector<RootState, Machine[]>; acquiring: Selector<RootState, Machine[]>; ... 53 more ...; saving: (state: RootState) => boolean; }\'.\\n No index signature with a parameter of type \'string\' was found on type \'{ aborting: Selector<RootState, Machine[]>; abortingSelected: Selector<RootState, Machine[]>; acquiring: Selector<RootState, Machine[]>; ... 53 more ...; saving: (state: RootState) => boolean; }\'.", "1657451879"],
[45, 4, 76, "Element implicitly has an \'any\' type because expression of type \'string\' can\'t be used to index type \'{ aborting: Selector<RootState, Machine[]>; abortingSelected: Selector<RootState, Machine[]>; acquiring: Selector<RootState, Machine[]>; ... 54 more ...; saving: (state: RootState) => boolean; }\'.\\n No index signature with a parameter of type \'string\' was found on type \'{ aborting: Selector<RootState, Machine[]>; abortingSelected: Selector<RootState, Machine[]>; acquiring: Selector<RootState, Machine[]>; ... 54 more ...; saving: (state: RootState) => boolean; }\'.", "1657451879"],
[45, 37, 6, "Object is possibly \'undefined\'.", "1314712411"],
[45, 56, 6, "Object is possibly \'undefined\'.", "1314712411"],
[49, 11, 16, "Type \'(BaseMachine | MachineDetails | undefined)[]\' is not assignable to type \'Machine[]\'.\\n Type \'BaseMachine | MachineDetails | undefined\' is not assignable to type \'Machine\'.\\n Type \'undefined\' is not assignable to type \'Machine\'.", "2366246550"]
Expand All @@ -342,8 +342,8 @@ exports[`stricter compilation`] = {
[29, 28, 9, "Property \'setActive\' does not exist on type \'{ fetch: ActionCreatorWithPreparedPayload<[params?: any], { params: any; }, string, never, { model: any; method: string; }>; create: ActionCreatorWithPreparedPayload<[params?: any], { params: any; }, string, never, { ...; }>; update: ActionCreatorWithPreparedPayload<...>; delete: ActionCreatorWithPreparedPayload<......\'.", "1891567915"],
[33, 30, 9, "Property \'setActive\' does not exist on type \'{ fetch: ActionCreatorWithPreparedPayload<[params?: any], { params: any; }, string, never, { model: any; method: string; }>; create: ActionCreatorWithPreparedPayload<[params?: any], { params: any; }, string, never, { ...; }>; update: ActionCreatorWithPreparedPayload<...>; delete: ActionCreatorWithPreparedPayload<......\'.", "1891567915"]
],
"src/app/machines/views/MachineDetails/MachineHeader/MachineHeader.tsx:2073227660": [
[33, 28, 3, "Property \'get\' does not exist on type \'{ fetch: ActionCreatorWithPreparedPayload<[params?: any], { params: any; }, string, never, { model: any; method: string; }>; create: ActionCreatorWithPreparedPayload<[params?: any], { params: any; }, string, never, { ...; }>; update: ActionCreatorWithPreparedPayload<...>; delete: ActionCreatorWithPreparedPayload<......\'.", "193411891"]
"src/app/machines/views/MachineDetails/MachineHeader/MachineHeader.tsx:2666992142": [
[37, 28, 3, "Property \'get\' does not exist on type \'{ fetch: ActionCreatorWithPreparedPayload<[params?: any], { params: any; }, string, never, { model: any; method: string; }>; create: ActionCreatorWithPreparedPayload<[params?: any], { params: any; }, string, never, { ...; }>; update: ActionCreatorWithPreparedPayload<...>; delete: ActionCreatorWithPreparedPayload<......\'.", "193411891"]
],
"src/app/machines/views/MachineDetails/MachineSummary/MachineSummary.tsx:564355202": [
[42, 28, 3, "Property \'get\' does not exist on type \'{ fetch: ActionCreatorWithPreparedPayload<[params?: any], { params: any; }, string, never, { model: any; method: string; }>; create: ActionCreatorWithPreparedPayload<[params?: any], { params: any; }, string, never, { ...; }>; update: ActionCreatorWithPreparedPayload<...>; delete: ActionCreatorWithPreparedPayload<......\'.", "193411891"]
Expand All @@ -355,9 +355,13 @@ exports[`stricter compilation`] = {
[17, 18, 36, "Element implicitly has an \'any\' type because expression of type \'string\' can\'t be used to index type \'MachineDetails\'.\\n No index signature with a parameter of type \'string\' was found on type \'MachineDetails\'.", "830072625"],
[146, 18, 7, "Type \'string | null\' is not assignable to type \'string | undefined\'.\\n Type \'null\' is not assignable to type \'string | undefined\'.", "1236122734"]
],
"src/app/machines/views/MachineDetails/MachineSummary/OverviewCard/MemoryCard/MemoryCard.tsx:3019693856": [
"src/app/machines/views/MachineDetails/MachineSummary/OverviewCard/MemoryCard/MemoryCard.tsx:2120332270": [
[16, 18, 36, "Element implicitly has an \'any\' type because expression of type \'string\' can\'t be used to index type \'MachineDetails\'.\\n No index signature with a parameter of type \'string\' was found on type \'MachineDetails\'.", "830072625"],
[120, 18, 7, "Type \'string | null\' is not assignable to type \'string | undefined\'.\\n Type \'null\' is not assignable to type \'string | undefined\'.", "1236122734"]
[119, 16, 7, "Type \'string | null\' is not assignable to type \'string | undefined\'.\\n Type \'null\' is not assignable to type \'string | undefined\'.", "1236122734"]
],
"src/app/machines/views/MachineDetails/MachineSummary/OverviewCard/StorageCard/StorageCard.tsx:3582856219": [
[17, 18, 36, "Element implicitly has an \'any\' type because expression of type \'string\' can\'t be used to index type \'MachineDetails\'.\\n No index signature with a parameter of type \'string\' was found on type \'MachineDetails\'.", "830072625"],
[127, 16, 7, "Type \'string | null\' is not assignable to type \'string | undefined\'.\\n Type \'null\' is not assignable to type \'string | undefined\'.", "1236122734"]
],
"src/app/machines/views/MachineList/MachineListHeader/MachineListHeader.tsx:539216384": [
[104, 10, 17, "Type \'(action: MachineAction, deselect?: boolean | undefined) => void\' is not assignable to type \'SetSelectedAction\'.\\n Types of parameters \'action\' and \'action\' are incompatible.\\n Type \'SelectedAction | null\' is not assignable to type \'MachineAction\'.\\n Type \'null\' is not assignable to type \'MachineAction\'.", "167402512"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React from "react";
import CpuCard from "./CpuCard";
import MemoryCard from "./MemoryCard";
import StatusCard from "./StatusCard";
import StorageCard from "./StorageCard";
import type { SetSelectedAction } from "../MachineSummary";
import machineSelectors from "app/store/machine/selectors";
import type { Machine } from "app/store/machine/types";
Expand Down Expand Up @@ -33,6 +34,7 @@ const OverviewCard = ({ id, setSelectedAction }: Props): JSX.Element => {
<StatusCard machine={machine} />
<CpuCard machine={machine} setSelectedAction={setSelectedAction} />
<MemoryCard machine={machine} setSelectedAction={setSelectedAction} />
<StorageCard machine={machine} setSelectedAction={setSelectedAction} />
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { mount } from "enzyme";
import { Provider } from "react-redux";
import { MemoryRouter } from "react-router-dom";
import configureStore from "redux-mock-store";
import React from "react";

import {
machineDetails as machineDetailsFactory,
machineState as machineStateFactory,
rootState as rootStateFactory,
testStatus as testStatusFactory,
} from "testing/factories";
import StorageCard from "./StorageCard";
import type { RootState } from "app/store/root/types";

const mockStore = configureStore();

describe("StorageCard", () => {
let state: RootState;
beforeEach(() => {
state = rootStateFactory({
machine: machineStateFactory(),
});
});

it("renders a link with a count of passed tests", () => {
const machine = machineDetailsFactory();
machine.storage_test_status = testStatusFactory({
passed: 2,
});
state.machine.items = [machine];

const store = mockStore(state);
const wrapper = mount(
<Provider store={store}>
<MemoryRouter
initialEntries={[{ pathname: "/machine/abc123", key: "testKey" }]}
>
<StorageCard machine={machine} setSelectedAction={jest.fn()} />
</MemoryRouter>
</Provider>
);

expect(
wrapper.find("[data-test='tests']").childAt(0).find("Button").text()
).toEqual("2");
});

it("renders a link with a count of pending and running tests", () => {
const machine = machineDetailsFactory();
machine.storage_test_status = testStatusFactory({
running: 1,
pending: 2,
});
state.machine.items = [machine];

const store = mockStore(state);
const wrapper = mount(
<Provider store={store}>
<MemoryRouter
initialEntries={[{ pathname: "/machine/abc123", key: "testKey" }]}
>
<StorageCard machine={machine} setSelectedAction={jest.fn()} />
</MemoryRouter>
</Provider>
);

expect(
wrapper.find("[data-test='tests']").childAt(0).find("Button").text()
).toEqual("3");
});

it("renders a link with a count of failed tests", () => {
const machine = machineDetailsFactory();
machine.storage_test_status = testStatusFactory({
failed: 5,
});
state.machine.items = [machine];

const store = mockStore(state);
const wrapper = mount(
<Provider store={store}>
<MemoryRouter
initialEntries={[{ pathname: "/machine/abc123", key: "testKey" }]}
>
<StorageCard machine={machine} setSelectedAction={jest.fn()} />
</MemoryRouter>
</Provider>
);

expect(
wrapper.find("[data-test='tests']").childAt(0).find("Button").text()
).toEqual("5");
});

it("renders a results link", () => {
const machine = machineDetailsFactory();
machine.storage_test_status = testStatusFactory({
failed: 5,
});
state.machine.items = [machine];

const store = mockStore(state);
const wrapper = mount(
<Provider store={store}>
<MemoryRouter
initialEntries={[{ pathname: "/machine/abc123", key: "testKey" }]}
>
<StorageCard machine={machine} setSelectedAction={jest.fn()} />
</MemoryRouter>
</Provider>
);

expect(
wrapper.find("[data-test='tests']").childAt(1).find("Button").text()
).toContain("View results");
});

it("renders a test storage link if no tests run", () => {
const machine = machineDetailsFactory();
machine.storage_test_status = testStatusFactory();
state.machine.items = [machine];

const store = mockStore(state);
const wrapper = mount(
<Provider store={store}>
<MemoryRouter
initialEntries={[{ pathname: "/machine/abc123", key: "testKey" }]}
>
<StorageCard machine={machine} setSelectedAction={jest.fn()} />
</MemoryRouter>
</Provider>
);

expect(
wrapper.find("[data-test='tests']").childAt(0).find("Button").text()
).toContain("Test storage");
});
});
Loading

0 comments on commit 4e66346

Please sign in to comment.