• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cartesi / rollups-explorer / 11325553061

14 Oct 2024 10:19AM UTC coverage: 84.745% (-1.7%) from 86.415%
11325553061

Pull #256

github

nevendyulgerov
test(apps/web): Add unit tests for GenericInput form
Pull Request #256: #251 Add ABI encoding for raw input form

1303 of 1565 branches covered (83.26%)

Branch coverage included in aggregate %.

710 of 904 new or added lines in 13 files covered. (78.54%)

135 existing lines in 1 file now uncovered.

9185 of 10811 relevant lines covered (84.96%)

46.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.94
/packages/ui/src/GenericInputForm/index.tsx
1
import {
1✔
2
    useSimulateInputBoxAddInput,
3
    useWriteInputBoxAddInput,
4
} from "@cartesi/rollups-wagmi";
1✔
5
import {
6
    Alert,
7
    Autocomplete,
8
    Button,
9
    Collapse,
10
    Group,
11
    Loader,
12
    SegmentedControl,
13
    Stack,
14
    Textarea,
15
} from "@mantine/core";
1✔
16
import { FC, useCallback, useEffect } from "react";
1✔
17
import { TbAlertCircle, TbCheck } from "react-icons/tb";
1✔
18
import { Abi, BaseError, stringToHex } from "viem";
1✔
19
import { useWaitForTransactionReceipt } from "wagmi";
1✔
20
import { TransactionProgress } from "../TransactionProgress";
1✔
21
import useUndeployedApplication from "../hooks/useUndeployedApplication";
1✔
22
import { TransactionFormSuccessData } from "../DepositFormTypes";
23
import { AbiFields } from "./AbiFields";
1✔
24
import { AbiValueParameter, FormMode } from "./types";
25
import { FormProvider } from "./context";
1✔
26
import { useGenericInputForm } from "./useGenericInputForm";
1✔
27
import { useDebouncedCallback } from "@mantine/hooks";
1✔
28
import { encodeFunctionParams } from "./utils";
1✔
29

30
export interface GenericInputFormSpecification {
31
    id: string;
32
    name: string;
33
    abi: Abi;
34
}
35

36
export interface GenericInputFormProps {
37
    applications: string[];
38
    specifications: GenericInputFormSpecification[];
39
    isLoadingApplications: boolean;
40
    onSearchApplications: (applicationId: string) => void;
41
    onSuccess: (receipt: TransactionFormSuccessData) => void;
42
}
43

44
export const GenericInputForm: FC<GenericInputFormProps> = (props) => {
1✔
45
    const {
117✔
46
        applications,
117✔
47
        specifications,
117✔
48
        isLoadingApplications,
117✔
49
        onSearchApplications,
117✔
50
        onSuccess,
117✔
51
    } = props;
117✔
52
    const form = useGenericInputForm(specifications);
117✔
53
    const { address, rawInput, mode } = form.getTransformedValues();
117✔
54
    const prepare = useSimulateInputBoxAddInput({
117✔
55
        args: [address, rawInput],
117✔
56
        query: {
117✔
57
            enabled: form.isValid(),
117✔
58
        },
117✔
59
    });
117✔
60

61
    const execute = useWriteInputBoxAddInput();
117✔
62
    const wait = useWaitForTransactionReceipt({
117✔
63
        hash: execute.data,
117✔
64
    });
117✔
65
    const loading = execute.isPending || wait.isLoading;
117✔
66
    const isFormValid = form.isValid();
117✔
67
    const canSubmit = isFormValid && prepare.error === null;
117✔
68
    const isUndeployedApp = useUndeployedApplication(address, applications);
117✔
69
    const abiFunctionParams = form.getInputProps("abiFunctionParams");
117✔
70

71
    const onChangeFormMode = useCallback(
117✔
72
        (mode: string | null) => {
117✔
73
            form.reset();
8✔
74
            form.setFieldValue("mode", mode as FormMode);
8✔
75
        },
8✔
76
        [form],
117✔
77
    );
117✔
78

79
    const encodeFunctionParamsDebounced = useDebouncedCallback(
117✔
80
        (params: AbiValueParameter[]) => {
117✔
81
            // Encode the function params
82
            const payload = encodeFunctionParams(params);
1✔
83
            // Set the encoded function params as value for hex field
84
            form.setFieldValue("rawInput", payload);
1✔
85
        },
1✔
86
        400,
117✔
87
    );
117✔
88

89
    useEffect(() => {
117✔
90
        if (wait.isSuccess) {
37✔
91
            onSuccess({ receipt: wait.data, type: "RAW" });
11✔
92
            form.reset();
11✔
93
            execute.reset();
11✔
94
            onSearchApplications("");
11✔
95
        }
11✔
96
        // eslint-disable-next-line react-hooks/exhaustive-deps
97
    }, [wait, onSearchApplications, onSuccess]);
117✔
98

99
    useEffect(() => {
117✔
100
        if (isFormValid) {
94✔
101
            encodeFunctionParamsDebounced(abiFunctionParams.value);
14✔
102
        }
14✔
103
    }, [abiFunctionParams.value, isFormValid, encodeFunctionParamsDebounced]);
117✔
104

105
    return (
117✔
106
        <FormProvider form={form}>
117✔
107
            <form data-testid="raw-input-form">
117✔
108
                <Stack>
117✔
109
                    <Autocomplete
117✔
110
                        label="Application"
117✔
111
                        description="The application smart contract address"
117✔
112
                        placeholder="0x"
117✔
113
                        data={applications}
117✔
114
                        withAsterisk
117✔
115
                        data-testid="application-autocomplete"
117✔
116
                        rightSection={
117✔
117
                            (prepare.isLoading || isLoadingApplications) && (
117!
NEW
118
                                <Loader size="xs" />
×
119
                            )
120
                        }
121
                        {...form.getInputProps("application")}
117✔
122
                        error={
117✔
123
                            form.errors.application ||
117✔
124
                            (prepare.error as BaseError)?.shortMessage
116!
125
                        }
126
                        onChange={(nextValue) => {
117✔
127
                            form.setFieldValue("application", nextValue);
13✔
128
                            onSearchApplications(nextValue);
13✔
129
                        }}
13✔
130
                    />
117✔
131

132
                    {!form.errors.application && isUndeployedApp && (
117✔
133
                        <Alert
1✔
134
                            variant="light"
1✔
135
                            color="yellow"
1✔
136
                            icon={<TbAlertCircle />}
1✔
137
                        >
1✔
138
                            This is an undeployed application.
139
                        </Alert>
1✔
140
                    )}
141

142
                    <SegmentedControl
117✔
143
                        value={mode}
117✔
144
                        onChange={onChangeFormMode}
117✔
145
                        data={[
117✔
146
                            { label: "Hex", value: "hex" },
117✔
147
                            { label: "String to Hex", value: "string" },
117✔
148
                            { label: "ABI to Hex", value: "abi" },
117✔
149
                        ]}
117✔
150
                    />
117✔
151

152
                    {mode === "hex" ? (
117✔
153
                        <Textarea
54✔
154
                            label="Hex input"
54✔
155
                            description="Hex input for the application"
54✔
156
                            withAsterisk
54✔
157
                            data-testid="hex-textarea"
54✔
158
                            {...form.getInputProps("rawInput")}
54✔
159
                        />
54✔
160
                    ) : mode === "string" ? (
63✔
161
                        <>
3✔
162
                            <Textarea
3✔
163
                                label="String input"
3✔
164
                                description="String input for the application"
3✔
165
                                {...form.getInputProps("stringInput")}
3✔
166
                                onChange={(event) => {
3✔
167
                                    const nextValue = event.target.value;
1✔
168
                                    form.setFieldValue(
1✔
169
                                        "stringInput",
1✔
170
                                        nextValue,
1✔
171
                                    );
1✔
172

173
                                    form.setFieldValue(
1✔
174
                                        "rawInput",
1✔
175
                                        stringToHex(nextValue),
1✔
176
                                    );
1✔
177
                                }}
1✔
178
                            />
3✔
179

180
                            <Textarea
3✔
181
                                label="Hex value"
3✔
182
                                description="Encoded hex value for the application"
3✔
183
                                readOnly
3✔
184
                                {...form.getInputProps("rawInput")}
3✔
185
                            />
3✔
186
                        </>
3✔
187
                    ) : mode === "abi" ? (
60✔
188
                        <AbiFields specifications={specifications} />
59✔
189
                    ) : null}
1✔
190

191
                    <Collapse
117✔
192
                        in={
117✔
193
                            execute.isPending ||
117✔
194
                            wait.isLoading ||
117✔
195
                            execute.isSuccess ||
117✔
196
                            execute.isError
117✔
197
                        }
198
                    >
199
                        <TransactionProgress
117✔
200
                            prepare={prepare}
117✔
201
                            execute={execute}
117✔
202
                            wait={wait}
117✔
203
                            confirmationMessage="Raw input sent successfully!"
117✔
204
                            defaultErrorMessage={execute.error?.message}
117!
205
                        />
117✔
206
                    </Collapse>
117✔
207

208
                    <Group justify="right">
117✔
209
                        <Button
117✔
210
                            variant="filled"
117✔
211
                            disabled={!canSubmit}
117✔
212
                            leftSection={<TbCheck />}
117✔
213
                            loading={loading}
117✔
214
                            data-testid="generic-input-submit-button"
117✔
215
                            onClick={() =>
117✔
216
                                execute.writeContract(prepare.data!.request)
7✔
217
                            }
218
                        >
117✔
219
                            Send
220
                        </Button>
117✔
221
                    </Group>
117✔
222
                </Stack>
117✔
223
            </form>
117✔
224
        </FormProvider>
117✔
225
    );
226
};
117✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc