Skip to content

Commit

Permalink
#264 Add optional switch for byte slice (#268)
Browse files Browse the repository at this point in the history
  • Loading branch information
nevendyulgerov authored Dec 10, 2024
1 parent 84963a1 commit 324d1cd
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 1 deletion.
50 changes: 49 additions & 1 deletion apps/web/src/components/specification/form/fields/ByteSlices.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Checkbox,
Collapse,
Fieldset,
Flex,
Group,
NumberInput,
Select,
Expand All @@ -13,15 +14,17 @@ import {
Text,
TextInput,
Title,
VisuallyHidden,
Tooltip,
useMantineTheme,
VisuallyHidden,
} from "@mantine/core";
import { createFormActions, useForm } from "@mantine/form";
import { useDisclosure } from "@mantine/hooks";
import { AbiType } from "abitype";
import { any, clone, gt, gte, isEmpty, isNil, lt, reject } from "ramda";
import {
isBlank,
isBoolean,
isFunction,
isNilOrEmpty,
isNotNilOrEmpty,
Expand All @@ -30,6 +33,7 @@ import { FC, ReactNode, useEffect, useRef } from "react";
import {
TbArrowsDiagonal,
TbArrowsDiagonalMinimize2,
TbInfoCircle,
TbTrash,
} from "react-icons/tb";
import { SliceInstruction } from "../../types";
Expand All @@ -48,6 +52,9 @@ const InstructionsReview: FC<Props> = ({ slices, onSliceChange }) => {
<Table.Td>{slice.from}</Table.Td>
<Table.Td>{slice.to ?? "end of bytes"}</Table.Td>
<Table.Td>{`${isEmpty(slice.type) ? "Hex" : slice.type}`}</Table.Td>
<Table.Td>{`${
isBoolean(slice.optional) && slice.optional ? "Yes" : "No"
}`}</Table.Td>
<Table.Td>
<Button
size="compact-sm"
Expand Down Expand Up @@ -99,6 +106,9 @@ const InstructionsReview: FC<Props> = ({ slices, onSliceChange }) => {
<Table.Th style={{ whiteSpace: "nowrap" }}>
Type
</Table.Th>
<Table.Th style={{ whiteSpace: "nowrap" }}>
Optional
</Table.Th>
<Table.Th style={{ whiteSpace: "nowrap" }}>
Action
</Table.Th>
Expand Down Expand Up @@ -126,6 +136,7 @@ interface FormValues {
from: string;
to: string;
type: string;
optional?: boolean;
};
}

Expand Down Expand Up @@ -191,6 +202,7 @@ const initialValues: FormValues = {
from: "",
to: "",
type: "",
optional: false,
},
};

Expand Down Expand Up @@ -295,6 +307,40 @@ const SliceInstructionFields: FC<SliceInstructionFieldsProps> = ({
description="Optional: Empty means return slice value as-is (i.e. Hex.)"
{...form.getInputProps("sliceInput.type")}
/>
<Group
justify="space-between"
align="normal"
wrap="nowrap"
>
<Stack gap={0}>
<Flex>
<Text component="span" size="sm" mr={4}>
Optional
</Text>
<Tooltip
label="An optional boolean flag used to control the decoding behavior for the byte slice. When turned on, the decoder won't throw an exception caused by slicing the byte range, if that range is out of bounds (not found). Instead a fallback value of nil ('0x') will be used for that byte slice."
multiline
w={300}
>
<Text>
<TbInfoCircle />
</Text>
</Tooltip>
</Flex>
<Text size="xs" c="dimmed" component="span">
Signal to the decoder not to throw an
exception caused by slicing the byte range.
</Text>
</Stack>
<Switch
data-testid="byte-slice-optional-switch"
{...form.getInputProps("sliceInput.optional")}
checked={
form.getInputProps("sliceInput.optional")
.value
}
/>
</Group>
</Stack>
<Group justify="flex-end" mt="md">
<Button
Expand All @@ -310,12 +356,14 @@ const SliceInstructionFields: FC<SliceInstructionFieldsProps> = ({
!isEmpty(sliceInput.to)
? parseInt(sliceInput?.to)
: undefined;
const optional = sliceInput.optional;

const slice: SliceInstruction = {
from,
to,
name,
type,
optional,
};

const newSlices = [...(slices ?? []), slice];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ describe("Specification Form View", () => {
name: "tokenAddress",
to: 20,
type: "",
optional: false,
},
],
sliceTarget: "tokenAddress",
Expand All @@ -482,6 +483,90 @@ describe("Specification Form View", () => {
}),
});
});

it("should correctly set the default value for the optional byte-slice flag", async () => {
await act(async () => render(<StatefulView />));

act(() => {
fireEvent.click(
screen.getByText("ABI Parameters")
.parentNode as HTMLLabelElement,
);
fireEvent.click(screen.getByTestId("add-byte-slice-switch"));

fireEvent.change(screen.getByTestId("slice-name-input"), {
target: { value: "tokenAddress" },
});

fireEvent.change(screen.getByTestId("slice-from-input"), {
target: { value: "0" },
});

fireEvent.change(screen.getByTestId("slice-to-input"), {
target: { value: "20" },
});

fireEvent.click(screen.getByTestId("slice-add-button"));
});

fireEvent.click(screen.getByText("Review your definition"));

await waitFor(() =>
expect(screen.getByTestId("0-tokenAddress")).toBeVisible(),
);

const reviewTable = screen.getByTestId(
"batch-review-table",
) as HTMLDivElement;

expect(getByText(reviewTable, "Optional")).toBeInTheDocument();
expect(getByText(reviewTable, "No")).toBeInTheDocument();

fireEvent.click(screen.getByText("Remove slice-tokenAddress"));
});

it("should correctly configure the optional boolean flag for a byte slice", async () => {
await act(async () => render(<StatefulView />));

act(() => {
fireEvent.click(
screen.getByText("ABI Parameters")
.parentNode as HTMLLabelElement,
);
fireEvent.click(screen.getByTestId("add-byte-slice-switch"));

fireEvent.change(screen.getByTestId("slice-name-input"), {
target: { value: "tokenAddress" },
});

fireEvent.change(screen.getByTestId("slice-from-input"), {
target: { value: "0" },
});

fireEvent.change(screen.getByTestId("slice-to-input"), {
target: { value: "20" },
});

fireEvent.click(
screen.getByTestId("byte-slice-optional-switch"),
);

fireEvent.click(screen.getByTestId("slice-add-button"));
});

fireEvent.click(screen.getByText("Review your definition"));

await waitFor(() =>
expect(screen.getByTestId("0-tokenAddress")).toBeVisible(),
);

const reviewTable = screen.getByTestId(
"batch-review-table",
) as HTMLDivElement;

expect(getByText(reviewTable, "Optional")).toBeInTheDocument();
expect(getByText(reviewTable, "Yes")).toBeInTheDocument();
});
});

describe("validations", () => {
Expand Down

0 comments on commit 324d1cd

Please sign in to comment.