Skip to content

Commit

Permalink
test: updates tests
Browse files Browse the repository at this point in the history
  • Loading branch information
aviemet committed May 2, 2024
1 parent 22b0afe commit ac7559b
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 13 deletions.
82 changes: 81 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, unknown>
}
```

`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<T> | ((records: T[]) => Partial<T>)) => 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 (
<>
<div style={ { display: 'flex' } }>
<label style={ { flex: 1 } }>{ label }</label>
<button onClick={ handleAddInput }>+</button>
</div>

{ paths.map((path, i) => (
<NestedFields key={ i } model={ path }>
<div style={ { display: 'flex' } }>
<div>{ children }</div>
<button onClick={ onClick: () => removeInput(i) }>-</button>
</div>
</NestedFields>
)) }
</>
)
}
```

### 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 }) => {
Expand Down
1 change: 1 addition & 0 deletions src/useDynamicInputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const useDynamicInputs = <T extends Record<string, unknown>>({ model, emptyData
inputModel = `${inputModel}.${model || ''}`

const handleAddInputs: AddInputHandler<T> = useCallback(override => {
console.log({ override })
setData((formData: T) => {
const clone = structuredClone(formData)
let node = get(clone, inputModel) as T[]
Expand Down
29 changes: 17 additions & 12 deletions tests/formComponent.test.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -168,16 +168,19 @@ describe('Form Component', () => {
{ children }
</Form>
)
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<typeof initialData>(),
{ wrapper: formProviderWrapper },
)

act(() => {
result.current.addInput()
result.current.addInput({ number: '1' })
Expand All @@ -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' })
})
})

Expand Down

0 comments on commit ac7559b

Please sign in to comment.