aboutsummaryrefslogtreecommitdiffstats
path: root/src/utils/hooks/use-form/use-form-submit/use-form-submit.test.ts
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-11-03 19:34:16 +0100
committerArmand Philippot <git@armandphilippot.com>2023-11-11 18:15:27 +0100
commitddd45e29745b73e7fe1684e197dcff598b375644 (patch)
tree8bf01305b5c0d163c52a7dce747ed7a4a4650acb /src/utils/hooks/use-form/use-form-submit/use-form-submit.test.ts
parent5d3e8a4d0c2ce2ad8f22df857ab3ce54fcfc38ac (diff)
feat(hooks): add an useForm hook
* add two "sub"-hooks: useFormValues and useFormSubmit (that can be used independently) * handle initial data * handle custom submit callback * handle data validation * handle submit status
Diffstat (limited to 'src/utils/hooks/use-form/use-form-submit/use-form-submit.test.ts')
-rw-r--r--src/utils/hooks/use-form/use-form-submit/use-form-submit.test.ts163
1 files changed, 163 insertions, 0 deletions
diff --git a/src/utils/hooks/use-form/use-form-submit/use-form-submit.test.ts b/src/utils/hooks/use-form/use-form-submit/use-form-submit.test.ts
new file mode 100644
index 0000000..cb0da16
--- /dev/null
+++ b/src/utils/hooks/use-form/use-form-submit/use-form-submit.test.ts
@@ -0,0 +1,163 @@
+import { describe, expect, it, jest } from '@jest/globals';
+import { act, renderHook } from '@testing-library/react';
+import type { FormEvent } from 'react';
+import { type FormSubmitValidation, useFormSubmit } from './use-form-submit';
+
+const generateSubmitEvent = () =>
+ new Event('submit', {
+ bubbles: true,
+ cancelable: true,
+ }) as unknown as FormEvent<HTMLFormElement>;
+
+describe('useFormSubmit', () => {
+ const data = { foo: 'tempore', bar: false, baz: 42 };
+ const messages = { error: 'Error', success: 'Success' };
+
+ it('can submit the provided data', async () => {
+ const { result } = renderHook(() => useFormSubmit(data));
+
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
+ expect.assertions(4);
+
+ expect(result.current.messages).toBeNull();
+ expect(result.current.submitStatus).toBe('IDLE');
+
+ await act(async () => {
+ await result.current.submit(generateSubmitEvent());
+ });
+
+ expect(result.current.messages).toBeNull();
+ expect(result.current.submitStatus).toBe('SUCCEEDED');
+ });
+
+ it('can use a callback to handle submit', async () => {
+ const callback = jest.fn((_data) => undefined);
+ const { result } = renderHook(() =>
+ useFormSubmit(data, { submit: callback })
+ );
+
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
+ expect.assertions(5);
+
+ expect(callback).not.toHaveBeenCalled();
+ expect(result.current.messages).toBeNull();
+
+ await act(async () => {
+ await result.current.submit(generateSubmitEvent());
+ });
+
+ expect(callback).toHaveBeenCalledTimes(1);
+ expect(callback).toHaveBeenCalledWith(data);
+ expect(result.current.messages).toBeNull();
+ });
+
+ it('can use a callback that fails validating data on submit', async () => {
+ const callback = jest.fn(
+ (values: typeof data): FormSubmitValidation<typeof data> => {
+ return {
+ messages,
+ validator: () => values.bar,
+ };
+ }
+ );
+ const { result } = renderHook(() =>
+ useFormSubmit(data, { submit: callback })
+ );
+
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
+ expect.assertions(6);
+
+ expect(callback).not.toHaveBeenCalled();
+ expect(result.current.messages).toBeNull();
+
+ await act(async () => {
+ await result.current.submit(generateSubmitEvent());
+ });
+
+ expect(callback).toHaveBeenCalledTimes(1);
+ expect(callback).toHaveBeenCalledWith(data);
+ expect(result.current.submitStatus).toBe('FAILED');
+ expect(result.current.messages).toBe(messages);
+ });
+
+ it('can use a callback that succeeds validating data on submit', async () => {
+ const callback = jest.fn(
+ (values: typeof data): FormSubmitValidation<typeof data> => {
+ return {
+ messages,
+ validator: () => !values.bar,
+ };
+ }
+ );
+ const { result } = renderHook(() =>
+ useFormSubmit(data, { submit: callback })
+ );
+
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
+ expect.assertions(6);
+
+ expect(callback).not.toHaveBeenCalled();
+ expect(result.current.messages).toBeNull();
+
+ await act(async () => {
+ await result.current.submit(generateSubmitEvent());
+ });
+
+ expect(callback).toHaveBeenCalledTimes(1);
+ expect(callback).toHaveBeenCalledWith(data);
+ expect(result.current.submitStatus).toBe('SUCCEEDED');
+ expect(result.current.messages).toBe(messages);
+ });
+
+ it('can call an onSuccess callback on success', async () => {
+ const callback = jest.fn();
+ const { result } = renderHook(() =>
+ useFormSubmit(data, { onSuccess: callback })
+ );
+
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
+ expect.assertions(6);
+
+ expect(callback).not.toHaveBeenCalled();
+ expect(result.current.messages).toBeNull();
+ expect(result.current.submitStatus).toBe('IDLE');
+
+ await act(async () => {
+ await result.current.submit(generateSubmitEvent());
+ });
+
+ expect(result.current.messages).toBeNull();
+ expect(callback).toHaveBeenCalledTimes(1);
+ expect(result.current.submitStatus).toBe('SUCCEEDED');
+ });
+
+ it('can call an onFailure callback on failure', async () => {
+ const handlers = {
+ onFailure: jest.fn(),
+ submit: jest.fn(
+ (values: typeof data): FormSubmitValidation<typeof data> => {
+ return {
+ messages,
+ validator: () => values.bar,
+ };
+ }
+ ),
+ };
+ const { result } = renderHook(() => useFormSubmit(data, handlers));
+
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
+ expect.assertions(6);
+
+ expect(handlers.onFailure).not.toHaveBeenCalled();
+ expect(result.current.messages).toBeNull();
+ expect(result.current.submitStatus).toBe('IDLE');
+
+ await act(async () => {
+ await result.current.submit(generateSubmitEvent());
+ });
+
+ expect(result.current.messages).toBe(messages);
+ expect(handlers.onFailure).toHaveBeenCalledTimes(1);
+ expect(result.current.submitStatus).toBe('FAILED');
+ });
+});