Add tests for MethodRow

This commit is contained in:
Koen Vlaswinkel
2023-09-14 14:41:03 +02:00
parent 499060d549
commit 17e0291bb5
4 changed files with 157 additions and 5 deletions

View File

@@ -21,6 +21,8 @@ type Props = {
disabled?: boolean;
disabledPlaceholder?: string;
onChange?: (event: ChangeEvent<HTMLSelectElement>) => void;
"aria-label"?: string;
};
/**
@@ -39,6 +41,7 @@ export function Dropdown({
disabled,
disabledPlaceholder,
onChange,
...props
}: Props) {
const disabledValue = disabledPlaceholder ?? DISABLED_VALUE;
return (
@@ -46,6 +49,7 @@ export function Dropdown({
value={disabled ? disabledValue : value}
disabled={disabled}
onChange={onChange}
{...props}
>
{disabled ? (
<option key={disabledValue} value={disabledValue}>

View File

@@ -9,9 +9,17 @@ type Props = {
value: ModeledMethod["kind"] | undefined;
disabled?: boolean;
onChange: (value: ModeledMethod["kind"]) => void;
"aria-label"?: string;
};
export const KindInput = ({ kinds, value, disabled, onChange }: Props) => {
export const KindInput = ({
kinds,
value,
disabled,
onChange,
...props
}: Props) => {
const options = useMemo(
() => kinds.map((kind) => ({ value: kind, label: kind })),
[kinds],
@@ -42,6 +50,7 @@ export const KindInput = ({ kinds, value, disabled, onChange }: Props) => {
options={options}
disabled={disabled}
onChange={handleInput}
{...props}
/>
);
};

View File

@@ -60,7 +60,7 @@ const modelTypeOptions: Array<{ value: ModeledMethodType; label: string }> = [
{ value: "neutral", label: "Neutral" },
];
type Props = {
export type MethodRowProps = {
method: Method;
methodCanBeModeled: boolean;
modeledMethod: ModeledMethod | undefined;
@@ -70,7 +70,7 @@ type Props = {
onChange: (method: Method, modeledMethod: ModeledMethod) => void;
};
export const MethodRow = (props: Props) => {
export const MethodRow = (props: MethodRowProps) => {
const { methodCanBeModeled } = props;
if (methodCanBeModeled) {
@@ -80,7 +80,7 @@ export const MethodRow = (props: Props) => {
}
};
function ModelableMethodRow(props: Props) {
function ModelableMethodRow(props: MethodRowProps) {
const { method, modeledMethod, methodIsUnsaved, mode, onChange } = props;
const argumentsList = useMemo(() => {
@@ -239,6 +239,7 @@ function ModelableMethodRow(props: Props) {
value={modeledMethod?.type ?? "none"}
options={modelTypeOptions}
onChange={handleTypeInput}
aria-label="Model type"
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={3}>
@@ -247,6 +248,7 @@ function ModelableMethodRow(props: Props) {
options={inputOptions}
disabled={!showInputCell}
onChange={handleInputInput}
aria-label="Input"
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={4}>
@@ -255,6 +257,7 @@ function ModelableMethodRow(props: Props) {
options={outputOptions}
disabled={!showOutputCell}
onChange={handleOutputInput}
aria-label="Output"
/>
</VSCodeDataGridCell>
<VSCodeDataGridCell gridColumn={5}>
@@ -263,6 +266,7 @@ function ModelableMethodRow(props: Props) {
value={modeledMethod?.kind}
disabled={!showKindCell}
onChange={handleKindChange}
aria-label="Kind"
/>
</VSCodeDataGridCell>
</>
@@ -271,7 +275,7 @@ function ModelableMethodRow(props: Props) {
);
}
function UnmodelableMethodRow(props: Props) {
function UnmodelableMethodRow(props: MethodRowProps) {
const { method, mode } = props;
const jumpToUsage = useCallback(

View File

@@ -0,0 +1,135 @@
import * as React from "react";
import {
getAllByRole,
render as reactRender,
screen,
} from "@testing-library/react";
import { createMethod } from "../../../../test/factories/data-extension/method-factories";
import { Mode } from "../../../model-editor/shared/mode";
import { MethodRow, MethodRowProps } from "../MethodRow";
import { ModeledMethod } from "../../../model-editor/modeled-method";
import userEvent from "@testing-library/user-event";
describe(MethodRow.name, () => {
const method = createMethod({
library: "sql2o",
libraryVersion: "1.6.0",
signature: "org.sql2o.Connection#createQuery(String)",
packageName: "org.sql2o",
typeName: "Connection",
methodName: "createQuery",
methodParameters: "(String)",
supported: false,
});
const modeledMethod: ModeledMethod = {
...method,
type: "summary",
input: "Argument[0]",
output: "ReturnValue",
kind: "taint",
provenance: "df-generated",
};
const onChange = jest.fn();
const render = (props: Partial<MethodRowProps> = {}) =>
reactRender(
<MethodRow
method={method}
methodCanBeModeled={true}
modeledMethod={modeledMethod}
methodIsUnsaved={false}
modelingInProgress={false}
mode={Mode.Application}
onChange={onChange}
{...props}
/>,
);
it("renders a modelable method", () => {
render();
expect(screen.queryAllByRole("combobox")).toHaveLength(4);
expect(screen.getByLabelText("Method modeled")).toBeInTheDocument();
expect(screen.queryByLabelText("Loading")).not.toBeInTheDocument();
});
it("can change the kind", async () => {
render();
onChange.mockReset();
expect(screen.getByRole("combobox", { name: "Kind" })).toHaveValue("taint");
await userEvent.selectOptions(
screen.getByRole("combobox", { name: "Kind" }),
"value",
);
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledWith(method, {
...modeledMethod,
kind: "value",
});
});
it("has the correct input options", () => {
render();
const inputDropdown = screen.getByRole("combobox", { name: "Input" });
expect(inputDropdown).toHaveValue("Argument[0]");
const options = getAllByRole(inputDropdown, "option");
expect(options).toHaveLength(2);
expect(options[0]).toHaveTextContent("Argument[this]");
expect(options[1]).toHaveTextContent("Argument[0]");
});
it("has the correct output options", () => {
render();
const inputDropdown = screen.getByRole("combobox", { name: "Output" });
expect(inputDropdown).toHaveValue("ReturnValue");
const options = getAllByRole(inputDropdown, "option");
expect(options).toHaveLength(3);
expect(options[0]).toHaveTextContent("ReturnValue");
expect(options[1]).toHaveTextContent("Argument[this]");
expect(options[2]).toHaveTextContent("Argument[0]");
});
it("shows the modeling status indicator when unsaved", () => {
render({
methodIsUnsaved: true,
});
expect(
screen.getByLabelText("Changes have not been saved"),
).toBeInTheDocument();
});
it("shows the modeling status indicator when unmodeled", () => {
render({
modeledMethod: undefined,
});
expect(screen.getByLabelText("Method not modeled")).toBeInTheDocument();
});
it("shows the in progress indicator when in progress", () => {
render({
modelingInProgress: true,
});
expect(screen.getByLabelText("Loading")).toBeInTheDocument();
});
it("renders an unmodelable method", () => {
render({
methodCanBeModeled: false,
modeledMethod: undefined,
});
expect(screen.queryByRole("combobox")).not.toBeInTheDocument();
expect(screen.getByText("Method already modeled")).toBeInTheDocument();
});
});