Skip to content

Commit 17e0291

Browse files
committed
Add tests for MethodRow
1 parent 499060d commit 17e0291

4 files changed

Lines changed: 157 additions & 5 deletions

File tree

extensions/ql-vscode/src/view/common/Dropdown.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ type Props = {
2121
disabled?: boolean;
2222
disabledPlaceholder?: string;
2323
onChange?: (event: ChangeEvent<HTMLSelectElement>) => void;
24+
25+
"aria-label"?: string;
2426
};
2527

2628
/**
@@ -39,13 +41,15 @@ export function Dropdown({
3941
disabled,
4042
disabledPlaceholder,
4143
onChange,
44+
...props
4245
}: Props) {
4346
const disabledValue = disabledPlaceholder ?? DISABLED_VALUE;
4447
return (
4548
<StyledDropdown
4649
value={disabled ? disabledValue : value}
4750
disabled={disabled}
4851
onChange={onChange}
52+
{...props}
4953
>
5054
{disabled ? (
5155
<option key={disabledValue} value={disabledValue}>

extensions/ql-vscode/src/view/model-editor/KindInput.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,17 @@ type Props = {
99
value: ModeledMethod["kind"] | undefined;
1010
disabled?: boolean;
1111
onChange: (value: ModeledMethod["kind"]) => void;
12+
13+
"aria-label"?: string;
1214
};
1315

14-
export const KindInput = ({ kinds, value, disabled, onChange }: Props) => {
16+
export const KindInput = ({
17+
kinds,
18+
value,
19+
disabled,
20+
onChange,
21+
...props
22+
}: Props) => {
1523
const options = useMemo(
1624
() => kinds.map((kind) => ({ value: kind, label: kind })),
1725
[kinds],
@@ -42,6 +50,7 @@ export const KindInput = ({ kinds, value, disabled, onChange }: Props) => {
4250
options={options}
4351
disabled={disabled}
4452
onChange={handleInput}
53+
{...props}
4554
/>
4655
);
4756
};

extensions/ql-vscode/src/view/model-editor/MethodRow.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ const modelTypeOptions: Array<{ value: ModeledMethodType; label: string }> = [
6060
{ value: "neutral", label: "Neutral" },
6161
];
6262

63-
type Props = {
63+
export type MethodRowProps = {
6464
method: Method;
6565
methodCanBeModeled: boolean;
6666
modeledMethod: ModeledMethod | undefined;
@@ -70,7 +70,7 @@ type Props = {
7070
onChange: (method: Method, modeledMethod: ModeledMethod) => void;
7171
};
7272

73-
export const MethodRow = (props: Props) => {
73+
export const MethodRow = (props: MethodRowProps) => {
7474
const { methodCanBeModeled } = props;
7575

7676
if (methodCanBeModeled) {
@@ -80,7 +80,7 @@ export const MethodRow = (props: Props) => {
8080
}
8181
};
8282

83-
function ModelableMethodRow(props: Props) {
83+
function ModelableMethodRow(props: MethodRowProps) {
8484
const { method, modeledMethod, methodIsUnsaved, mode, onChange } = props;
8585

8686
const argumentsList = useMemo(() => {
@@ -239,6 +239,7 @@ function ModelableMethodRow(props: Props) {
239239
value={modeledMethod?.type ?? "none"}
240240
options={modelTypeOptions}
241241
onChange={handleTypeInput}
242+
aria-label="Model type"
242243
/>
243244
</VSCodeDataGridCell>
244245
<VSCodeDataGridCell gridColumn={3}>
@@ -247,6 +248,7 @@ function ModelableMethodRow(props: Props) {
247248
options={inputOptions}
248249
disabled={!showInputCell}
249250
onChange={handleInputInput}
251+
aria-label="Input"
250252
/>
251253
</VSCodeDataGridCell>
252254
<VSCodeDataGridCell gridColumn={4}>
@@ -255,6 +257,7 @@ function ModelableMethodRow(props: Props) {
255257
options={outputOptions}
256258
disabled={!showOutputCell}
257259
onChange={handleOutputInput}
260+
aria-label="Output"
258261
/>
259262
</VSCodeDataGridCell>
260263
<VSCodeDataGridCell gridColumn={5}>
@@ -263,6 +266,7 @@ function ModelableMethodRow(props: Props) {
263266
value={modeledMethod?.kind}
264267
disabled={!showKindCell}
265268
onChange={handleKindChange}
269+
aria-label="Kind"
266270
/>
267271
</VSCodeDataGridCell>
268272
</>
@@ -271,7 +275,7 @@ function ModelableMethodRow(props: Props) {
271275
);
272276
}
273277

274-
function UnmodelableMethodRow(props: Props) {
278+
function UnmodelableMethodRow(props: MethodRowProps) {
275279
const { method, mode } = props;
276280

277281
const jumpToUsage = useCallback(
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import * as React from "react";
2+
import {
3+
getAllByRole,
4+
render as reactRender,
5+
screen,
6+
} from "@testing-library/react";
7+
import { createMethod } from "../../../../test/factories/data-extension/method-factories";
8+
import { Mode } from "../../../model-editor/shared/mode";
9+
import { MethodRow, MethodRowProps } from "../MethodRow";
10+
import { ModeledMethod } from "../../../model-editor/modeled-method";
11+
import userEvent from "@testing-library/user-event";
12+
13+
describe(MethodRow.name, () => {
14+
const method = createMethod({
15+
library: "sql2o",
16+
libraryVersion: "1.6.0",
17+
signature: "org.sql2o.Connection#createQuery(String)",
18+
packageName: "org.sql2o",
19+
typeName: "Connection",
20+
methodName: "createQuery",
21+
methodParameters: "(String)",
22+
supported: false,
23+
});
24+
const modeledMethod: ModeledMethod = {
25+
...method,
26+
type: "summary",
27+
input: "Argument[0]",
28+
output: "ReturnValue",
29+
kind: "taint",
30+
provenance: "df-generated",
31+
};
32+
const onChange = jest.fn();
33+
34+
const render = (props: Partial<MethodRowProps> = {}) =>
35+
reactRender(
36+
<MethodRow
37+
method={method}
38+
methodCanBeModeled={true}
39+
modeledMethod={modeledMethod}
40+
methodIsUnsaved={false}
41+
modelingInProgress={false}
42+
mode={Mode.Application}
43+
onChange={onChange}
44+
{...props}
45+
/>,
46+
);
47+
48+
it("renders a modelable method", () => {
49+
render();
50+
51+
expect(screen.queryAllByRole("combobox")).toHaveLength(4);
52+
expect(screen.getByLabelText("Method modeled")).toBeInTheDocument();
53+
expect(screen.queryByLabelText("Loading")).not.toBeInTheDocument();
54+
});
55+
56+
it("can change the kind", async () => {
57+
render();
58+
59+
onChange.mockReset();
60+
61+
expect(screen.getByRole("combobox", { name: "Kind" })).toHaveValue("taint");
62+
63+
await userEvent.selectOptions(
64+
screen.getByRole("combobox", { name: "Kind" }),
65+
"value",
66+
);
67+
68+
expect(onChange).toHaveBeenCalledTimes(1);
69+
expect(onChange).toHaveBeenCalledWith(method, {
70+
...modeledMethod,
71+
kind: "value",
72+
});
73+
});
74+
75+
it("has the correct input options", () => {
76+
render();
77+
78+
const inputDropdown = screen.getByRole("combobox", { name: "Input" });
79+
expect(inputDropdown).toHaveValue("Argument[0]");
80+
81+
const options = getAllByRole(inputDropdown, "option");
82+
expect(options).toHaveLength(2);
83+
expect(options[0]).toHaveTextContent("Argument[this]");
84+
expect(options[1]).toHaveTextContent("Argument[0]");
85+
});
86+
87+
it("has the correct output options", () => {
88+
render();
89+
90+
const inputDropdown = screen.getByRole("combobox", { name: "Output" });
91+
expect(inputDropdown).toHaveValue("ReturnValue");
92+
93+
const options = getAllByRole(inputDropdown, "option");
94+
expect(options).toHaveLength(3);
95+
expect(options[0]).toHaveTextContent("ReturnValue");
96+
expect(options[1]).toHaveTextContent("Argument[this]");
97+
expect(options[2]).toHaveTextContent("Argument[0]");
98+
});
99+
100+
it("shows the modeling status indicator when unsaved", () => {
101+
render({
102+
methodIsUnsaved: true,
103+
});
104+
105+
expect(
106+
screen.getByLabelText("Changes have not been saved"),
107+
).toBeInTheDocument();
108+
});
109+
110+
it("shows the modeling status indicator when unmodeled", () => {
111+
render({
112+
modeledMethod: undefined,
113+
});
114+
115+
expect(screen.getByLabelText("Method not modeled")).toBeInTheDocument();
116+
});
117+
118+
it("shows the in progress indicator when in progress", () => {
119+
render({
120+
modelingInProgress: true,
121+
});
122+
123+
expect(screen.getByLabelText("Loading")).toBeInTheDocument();
124+
});
125+
126+
it("renders an unmodelable method", () => {
127+
render({
128+
methodCanBeModeled: false,
129+
modeledMethod: undefined,
130+
});
131+
132+
expect(screen.queryByRole("combobox")).not.toBeInTheDocument();
133+
expect(screen.getByText("Method already modeled")).toBeInTheDocument();
134+
});
135+
});

0 commit comments

Comments
 (0)