Skip to content

Commit 322a000

Browse files
committed
Convert final OperatorInstanceUpdateForm.
Signed-off-by: Michael Nelson <[email protected]>
1 parent 47f56ed commit 322a000

File tree

6 files changed

+129
-169
lines changed

6 files changed

+129
-169
lines changed

dashboard/src/components/OperatorInstance/OperatorInstance.test.tsx

+14-31
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,13 @@ import OperatorHeader from "components/OperatorView/OperatorHeader";
1515
import ApplicationStatusContainer from "containers/ApplicationStatusContainer";
1616
import { act } from "react-dom/test-utils";
1717
import * as ReactRedux from "react-redux";
18-
import { defaultStore, getStore, initialState, mountWrapper } from "shared/specs/mountWrapper";
18+
import { getStore, initialState, mountWrapper } from "shared/specs/mountWrapper";
1919
import { FetchError, IStoreState } from "shared/types";
2020
import OperatorInstance from "./OperatorInstance";
2121
import { IOperatorsState } from "reducers/operators";
2222
import { IClusterState } from "reducers/cluster";
2323
import { MemoryRouter, Route } from "react-router-dom";
2424

25-
const defaultProps = {
26-
csvName: "foo",
27-
crdName: "foo.kubeapps.com",
28-
cluster: initialState.config.kubeappsCluster,
29-
namespace: "kubeapps",
30-
instanceName: "bar",
31-
};
32-
3325
const defaultCSV = {
3426
metadata: { name: "foo" },
3527
spec: {
@@ -117,7 +109,7 @@ it("renders a fetch error", () => {
117109
errors: { ...initialState.operators.errors, resource: { fetch: new FetchError("Boom!") } },
118110
},
119111
} as Partial<IStoreState>),
120-
<OperatorInstance {...defaultProps} />,
112+
<OperatorInstance />,
121113
);
122114
expect(wrapper.find(Alert)).toIncludeText("Boom!");
123115
expect(wrapper.find(OperatorHeader)).not.toExist();
@@ -131,7 +123,7 @@ it("renders an update error", () => {
131123
errors: { resource: { update: new Error("Boom!") } },
132124
},
133125
} as Partial<IStoreState>),
134-
<OperatorInstance {...defaultProps} />,
126+
<OperatorInstance />,
135127
);
136128
expect(wrapper.find(Alert)).toIncludeText("Boom!");
137129
});
@@ -144,7 +136,7 @@ it("renders an delete error", () => {
144136
errors: { resource: { update: new Error("Boom!") } },
145137
},
146138
} as Partial<IStoreState>),
147-
<OperatorInstance {...defaultProps} />,
139+
<OperatorInstance />,
148140
);
149141
expect(wrapper.find(Alert)).toIncludeText("Boom!");
150142
});
@@ -175,32 +167,28 @@ it("retrieves CSV and resource when mounted", () => {
175167
</Route>
176168
</MemoryRouter>,
177169
);
178-
expect(getCSV).toHaveBeenCalledWith(
179-
defaultProps.cluster,
180-
defaultProps.namespace,
181-
defaultProps.csvName,
182-
);
170+
expect(getCSV).toHaveBeenCalledWith("default-cluster", "kubeapps", "foo");
183171
expect(getResource).toHaveBeenCalledWith(
184-
defaultProps.cluster,
185-
defaultProps.namespace,
186-
defaultProps.csvName,
187-
defaultProps.crdName,
188-
defaultProps.instanceName,
172+
"default-cluster",
173+
"kubeapps",
174+
"foo",
175+
"foo.kubeapps.com",
176+
"bar",
189177
);
190178
});
191179

192180
it("renders a loading wrapper", () => {
193181
const wrapper = mountWrapper(
194182
getStore({ operators: { isFetching: true } } as Partial<IStoreState>),
195-
<OperatorInstance {...defaultProps} />,
183+
<OperatorInstance />,
196184
);
197185
expect(wrapper.find(LoadingWrapper)).toExist();
198186
});
199187

200188
it("renders all the subcomponents", () => {
201189
const wrapper = mountWrapper(
202190
getStore({ operators: { csv: defaultCSV, resource } } as Partial<IStoreState>),
203-
<OperatorInstance {...defaultProps} />,
191+
<OperatorInstance />,
204192
);
205193
expect(wrapper.find(ApplicationStatusContainer)).toExist();
206194
expect(wrapper.find(AccessURLTable)).toExist();
@@ -215,7 +203,7 @@ it("skips AppNotes and AppValues if the resource doesn't have spec or status", (
215203
getStore({
216204
operators: { csv: defaultCSV, resource: { ...resource, spec: undefined, status: undefined } },
217205
} as Partial<IStoreState>),
218-
<OperatorInstance {...defaultProps} />,
206+
<OperatorInstance />,
219207
);
220208
expect(wrapper.find(AppNotes)).not.toExist();
221209
expect(wrapper.find(AppValues)).not.toExist();
@@ -260,12 +248,7 @@ it("deletes the resource", async () => {
260248
await act(async () => {
261249
await (dialog.prop("onConfirm") as any)();
262250
});
263-
expect(deleteResource).toHaveBeenCalledWith(
264-
defaultProps.cluster,
265-
defaultProps.namespace,
266-
"foo",
267-
resource,
268-
);
251+
expect(deleteResource).toHaveBeenCalledWith("default-cluster", "kubeapps", "foo", resource);
269252
});
270253

271254
it("updates the state with the CRD resources", () => {

dashboard/src/components/OperatorInstanceUpdateForm/OperatorInstanceUpdateForm.test.tsx

+89-32
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,10 @@ import OperatorHeader from "components/OperatorView/OperatorHeader";
88
import * as ReactRedux from "react-redux";
99
import { defaultStore, getStore, initialState, mountWrapper } from "shared/specs/mountWrapper";
1010
import { FetchError, IStoreState } from "shared/types";
11-
import OperatorInstanceUpdateForm, {
12-
IOperatorInstanceUpgradeFormProps,
13-
} from "./OperatorInstanceUpdateForm";
14-
15-
const defaultProps: IOperatorInstanceUpgradeFormProps = {
16-
csvName: "foo",
17-
crdName: "foo-cluster",
18-
cluster: initialState.config.kubeappsCluster,
19-
namespace: "kubeapps",
20-
resourceName: "my-foo",
21-
};
11+
import OperatorInstanceUpdateForm from "./OperatorInstanceUpdateForm";
12+
import { MemoryRouter, Route } from "react-router-dom";
13+
import { IOperatorsState } from "reducers/operators";
14+
import { IClusterState } from "reducers/cluster";
2215

2316
const defaultResource = {
2417
kind: "Foo",
@@ -29,7 +22,7 @@ const defaultResource = {
2922
} as any;
3023

3124
const defaultCRD = {
32-
name: defaultProps.crdName,
25+
name: "foo-cluster",
3326
kind: "Foo",
3427
description: "useful description",
3528
} as any;
@@ -102,21 +95,44 @@ afterEach(() => {
10295

10396
it("gets resource and CSV", () => {
10497
const getResource = jest.fn();
98+
const store = getStore({
99+
operators: {
100+
resource: defaultResource,
101+
csv: defaultCSV,
102+
} as Partial<IOperatorsState>,
103+
clusters: {
104+
currentCluster: "default-cluster",
105+
clusters: {
106+
"default-cluster": {
107+
currentNamespace: "kubeapps",
108+
} as Partial<IClusterState>,
109+
},
110+
},
111+
} as Partial<IStoreState>);
105112
const getCSV = jest.fn();
106113
actions.operators.getResource = getResource;
107114
actions.operators.getCSV = getCSV;
108-
mountWrapper(defaultStore, <OperatorInstanceUpdateForm {...defaultProps} />);
109-
expect(getCSV).toHaveBeenCalledWith(
110-
defaultProps.cluster,
111-
defaultProps.namespace,
112-
defaultProps.csvName,
115+
mountWrapper(
116+
store,
117+
<MemoryRouter
118+
initialEntries={[
119+
"/c/default/ns/default/operators-instances/new/foo/foo-cluster/my-foo/update",
120+
]}
121+
>
122+
<Route
123+
path={"/c/:cluster/ns/:namespace/operators-instances/new/:csv/:crd/:instanceName/update"}
124+
>
125+
<OperatorInstanceUpdateForm />
126+
</Route>
127+
</MemoryRouter>,
113128
);
129+
expect(getCSV).toHaveBeenCalledWith("default-cluster", "kubeapps", "foo");
114130
expect(getResource).toHaveBeenCalledWith(
115-
defaultProps.cluster,
116-
defaultProps.namespace,
117-
defaultProps.csvName,
118-
defaultProps.crdName,
119-
defaultProps.resourceName,
131+
"default-cluster",
132+
"kubeapps",
133+
"foo",
134+
"foo-cluster",
135+
"my-foo",
120136
);
121137
});
122138

@@ -128,7 +144,17 @@ it("set default and deployed values", () => {
128144
csv: defaultCSV,
129145
},
130146
} as Partial<IStoreState>),
131-
<OperatorInstanceUpdateForm {...defaultProps} />,
147+
<MemoryRouter
148+
initialEntries={[
149+
"/c/default/ns/default/operators-instances/new/foo/foo-cluster/my-foo/update",
150+
]}
151+
>
152+
<Route
153+
path={"/c/:cluster/ns/:namespace/operators-instances/new/:csv/:crd/:instanceName/update"}
154+
>
155+
<OperatorInstanceUpdateForm />
156+
</Route>
157+
</MemoryRouter>,
132158
);
133159
expect(wrapper.find(OperatorInstanceFormBody).props()).toMatchObject({
134160
defaultValues: 'kind: "Foo"\napiVersion: "v1"\n',
@@ -137,7 +163,20 @@ it("set default and deployed values", () => {
137163
});
138164

139165
it("renders an error if the resource is not populated", () => {
140-
const wrapper = mountWrapper(defaultStore, <OperatorInstanceUpdateForm {...defaultProps} />);
166+
const wrapper = mountWrapper(
167+
defaultStore,
168+
<MemoryRouter
169+
initialEntries={[
170+
"/c/default/ns/default/operators-instances/new/foo/foo-cluster/my-foo/update",
171+
]}
172+
>
173+
<Route
174+
path={"/c/:cluster/ns/:namespace/operators-instances/new/:csv/:crd/:instanceName/update"}
175+
>
176+
<OperatorInstanceUpdateForm />
177+
</Route>
178+
</MemoryRouter>,
179+
);
141180
expect(wrapper.find(Alert)).toIncludeText("Resource my-foo not found");
142181
});
143182

@@ -153,7 +192,7 @@ it("renders only an error if the resource is not found", () => {
153192
},
154193
},
155194
} as Partial<IStoreState>),
156-
<OperatorInstanceUpdateForm {...defaultProps} />,
195+
<OperatorInstanceUpdateForm />,
157196
);
158197
expect(wrapper.find(Alert)).toIncludeText("not found");
159198
expect(wrapper.find(OperatorHeader)).not.toExist();
@@ -167,20 +206,38 @@ it("should submit the form", () => {
167206
operators: {
168207
resource: defaultResource,
169208
csv: defaultCSV,
209+
} as Partial<IOperatorsState>,
210+
clusters: {
211+
currentCluster: "default-cluster",
212+
clusters: {
213+
"default-cluster": {
214+
currentNamespace: "kubeapps",
215+
} as Partial<IClusterState>,
216+
},
170217
},
171218
} as Partial<IStoreState>),
172-
<OperatorInstanceUpdateForm {...defaultProps} />,
219+
<MemoryRouter
220+
initialEntries={[
221+
"/c/default/ns/default/operators-instances/new/foo/foo-cluster/my-foo/update",
222+
]}
223+
>
224+
<Route
225+
path={"/c/:cluster/ns/:namespace/operators-instances/new/:csv/:crd/:instanceName/update"}
226+
>
227+
<OperatorInstanceUpdateForm />
228+
</Route>
229+
</MemoryRouter>,
173230
);
174231

175232
const form = wrapper.find("form");
176233
form.simulate("submit", { preventDefault: jest.fn() });
177234

178235
expect(updateResource).toHaveBeenCalledWith(
179-
defaultProps.cluster,
180-
defaultProps.namespace,
181-
defaultResource.apiVersion,
182-
defaultProps.crdName,
183-
defaultProps.resourceName,
184-
defaultResource,
236+
"default-cluster",
237+
"kubeapps",
238+
"v1",
239+
"foo-cluster",
240+
"my-foo",
241+
{ apiVersion: "v1", kind: "Foo", metadata: { name: "my-foo" } },
185242
);
186243
});

dashboard/src/components/OperatorInstanceUpdateForm/OperatorInstanceUpdateForm.tsx

+24-25
Original file line numberDiff line numberDiff line change
@@ -18,38 +18,25 @@ import { IClusterServiceVersionCRD, IResource, IStoreState } from "shared/types"
1818
import * as url from "shared/url";
1919
import { parseToString } from "shared/yamlUtils";
2020
import OperatorInstanceFormBody from "../OperatorInstanceFormBody/OperatorInstanceFormBody";
21+
import { useParams } from "react-router-dom";
2122

22-
export interface IOperatorInstanceUpgradeFormProps {
23-
csvName: string;
24-
crdName: string;
25-
cluster: string;
26-
namespace: string;
27-
resourceName: string;
28-
}
29-
30-
function OperatorInstanceUpdateForm({
31-
csvName,
32-
crdName,
33-
cluster,
34-
namespace,
35-
resourceName,
36-
}: IOperatorInstanceUpgradeFormProps) {
23+
function OperatorInstanceUpdateForm() {
3724
const dispatch: ThunkDispatch<IStoreState, null, Action> = useDispatch();
3825
const [defaultValues, setDefaultValues] = useState("");
3926
const [currentValues, setCurrentValues] = useState("");
4027
const [crd, setCRD] = useState(undefined as IClusterServiceVersionCRD | undefined);
4128
const [icon, setIcon] = useState(placeholder);
4229

43-
useEffect(() => {
44-
// Clean up component state
45-
setDefaultValues("");
46-
setCurrentValues("");
47-
setCRD(undefined);
48-
setIcon(placeholder);
49-
dispatch(actions.operators.getResource(cluster, namespace, csvName, crdName, resourceName));
50-
dispatch(actions.operators.getCSV(cluster, namespace, csvName));
51-
}, [dispatch, cluster, namespace, csvName, crdName, resourceName]);
52-
30+
type IOperatorInstanceUpdateFormParams = {
31+
csv: string;
32+
crd: string;
33+
instanceName: string;
34+
};
35+
const {
36+
csv: csvName,
37+
crd: crdName,
38+
instanceName: resourceName,
39+
} = useParams<IOperatorInstanceUpdateFormParams>();
5340
const {
5441
operators: {
5542
isFetching,
@@ -59,7 +46,19 @@ function OperatorInstanceUpdateForm({
5946
resource: { fetch: fetchError, update: updateError },
6047
},
6148
},
49+
clusters: { currentCluster: cluster, clusters },
6250
} = useSelector((state: IStoreState) => state);
51+
const namespace = clusters[cluster].currentNamespace;
52+
53+
useEffect(() => {
54+
// Clean up component state
55+
setDefaultValues("");
56+
setCurrentValues("");
57+
setCRD(undefined);
58+
setIcon(placeholder);
59+
dispatch(actions.operators.getResource(cluster, namespace, csvName, crdName, resourceName));
60+
dispatch(actions.operators.getCSV(cluster, namespace, csvName));
61+
}, [dispatch, cluster, namespace, csvName, crdName, resourceName]);
6362

6463
useEffect(() => {
6564
if (resource) {

0 commit comments

Comments
 (0)