From ac7559bc0d211d8b68fde4d358c06f41ddf87fad Mon Sep 17 00:00:00 2001 From: Avram Walden Date: Thu, 2 May 2024 11:34:37 -0700 Subject: [PATCH] test: updates tests --- README.md | 82 +++++++++++++++++++++++++++++++++++- src/useDynamicInputs.ts | 1 + tests/formComponent.test.tsx | 29 +++++++------ 3 files changed, 99 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1c1c554..6f0e970 100644 --- a/README.md +++ b/README.md @@ -242,7 +242,87 @@ const PageWithFormOnIt = () => { ## useDynamicInputs -Provides methods for managing arrays in form data. Use it to make a reusable component with your own buttons and styles: +Provides methods for managing arrays in form data. Use it to make a reusable component with your own buttons and styles. + +`useDynamicInputs` accepts an object: + +```typescript +{ + model: string, + emptyData: Record +} +``` + +`model` should be a dot-notation string used to access an array in the form data +`emptyData` is an object with default (probably empty) values to be pushed to the end of the data array when a new input is added + +It returns an object: + +```typescript +{ + addInput: (override?: Partial | ((records: T[]) => Partial)) => void, + removeInput: (i: number) => T, + paths: string[], +} +``` + +`addInput` has 3 call signatures. +When passed nothing, it will push a copy of `emptyData` to the form data array. +When passed an object, it will merge that object with `emptyData`, overriding any existing keys/values. +When passed a function, it will first call that function, and then merge it with `emptyData` + +```javascript +const PhoneInputs = () => { + const { addInput, removeInput, paths } = useDynamicInputs({ + model: 'contact.phones', + emptyData: { number: '', type: '', order: 0 } + }) + + const handleAddInput = () => { + // Pushes { number: '', type: '', order: '' } to the phones form data array + addInput() + + // Override a value before pushing it to the form data array + addInput({ + type: 'personal' + }) + + // Passing a function allows using the data to build dynamic values before pushing to the form data array + addInput(records => { + const max = records.reduce((acc, record) => { + if(record.order > acc) return record.order + return acc + }, 0) + + return { + order: max + 1 + } + }) + } + + return ( + <> +
+ + +
+ + { paths.map((path, i) => ( + +
+
{ children }
+ +
+
+ )) } + + ) +} +``` + +### Reusable Dynamic Inputs Component + +Using `useDynamicInputs` you can build a dynamic inputs interface using your own markup structure or FE component framework. ```javascript const DynamicInputs = ({ children, model, label, emptyData }) => { diff --git a/src/useDynamicInputs.ts b/src/useDynamicInputs.ts index 07e08f8..2f88d80 100644 --- a/src/useDynamicInputs.ts +++ b/src/useDynamicInputs.ts @@ -29,6 +29,7 @@ const useDynamicInputs = >({ model, emptyData inputModel = `${inputModel}.${model || ''}` const handleAddInputs: AddInputHandler = useCallback(override => { + console.log({ override }) setData((formData: T) => { const clone = structuredClone(formData) let node = get(clone, inputModel) as T[] diff --git a/tests/formComponent.test.tsx b/tests/formComponent.test.tsx index 7fc5bb7..833bd3e 100644 --- a/tests/formComponent.test.tsx +++ b/tests/formComponent.test.tsx @@ -1,7 +1,7 @@ import React from 'react' import { fireEvent, render, screen } from '@testing-library/react' import '@testing-library/jest-dom' -import { Form } from '../src/Form' +import { Form, useForm } from '../src/Form' import Input from '../src/Inputs/Input' import { DynamicInputs, Submit, useDynamicInputs } from '../src' import { router } from '@inertiajs/react' @@ -168,16 +168,19 @@ describe('Form Component', () => { { children } ) - const { result } = renderHook(() => useDynamicInputs({ - model: 'phones', - emptyData: { number: '' }, - }), { wrapper: formProviderWrapper }) - - // phones: [ - // { number: '1234567890' }, - // { number: '2234567890' }, - // { number: '3234567890' }, - // ], + const { result } = renderHook( + () => useDynamicInputs({ + model: 'phones', + emptyData: { number: '' }, + }), + { wrapper: formProviderWrapper }, + ) + + const { result: formResult } = renderHook( + () => useForm(), + { wrapper: formProviderWrapper }, + ) + act(() => { result.current.addInput() result.current.addInput({ number: '1' }) @@ -186,7 +189,9 @@ describe('Form Component', () => { })) }) - // Need access to the form data context + expect(formResult.current.getData('contact.phones')).toContain({ number: '' }) + expect(formResult.current.getData('contact.phones')).toContain({ number: '1' }) + expect(formResult.current.getData('contact.phones')).toContain({ number: '1234567891' }) }) })