Skip to content

Commit

Permalink
chore: added nested path tests
Browse files Browse the repository at this point in the history
  • Loading branch information
logaretm committed Aug 12, 2024
1 parent 25c801c commit a7742a5
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 17 deletions.
30 changes: 19 additions & 11 deletions packages/playground/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
<template>
<div class="flex flex-col">
<InputText label="Test" name="test" />
<InputText label="deep" name="some.deep.path" />
<InputText label="arr" name="some.array.0.path" />

<pre>{{ isValid }}</pre>
<span data-testid="e2">{{ getError('some.array.0.path') }}</span>

<pre>{{ getErrors() }}</pre>
</div>
</template>

<script lang="ts" setup>
import InputText from '@/components/InputText.vue';
import { useForm } from '@formwerk/core';
import { defineSchema } from '@formwerk/schema-yup';
import * as yup from 'yup';
import { defineSchema } from '@formwerk/schema-zod';
import { z } from 'zod';
const { values, isValid, handleSubmit } = useForm({
const { getError, isValid, getErrors } = useForm({
schema: defineSchema(
yup.object({
test: yup.string().required(),
z.object({
some: z.object({
deep: z.object({
path: z.string().min(1, 'REQUIRED'),
}),
array: z.array(
z.object({
path: z.string().min(1, 'REQUIRED'),
}),
),
}),
}),
),
});
const onSubmit = handleSubmit(values => {
console.log(values);
});
</script>
52 changes: 51 additions & 1 deletion packages/schema-yup/src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { fireEvent, render, screen } from '@testing-library/vue';
import { useForm, useTextField } from '@formwerk/core';
import { defineSchema } from '.';
import * as y from 'yup';
import flush from 'flush-promises';
import { flush } from '@test-utils/index';

const requiredMessage = (field: string) => `${field} is a required field`;

Expand Down Expand Up @@ -54,6 +54,56 @@ describe('schema-yup', () => {
expect(screen.getByTestId('form-err').textContent).toBe(requiredMessage('test'));
});

test('validates nested paths', async () => {
await render({
components: { Child: createInputComponent() },
setup() {
const { getError, isValid } = useForm({
schema: defineSchema(
y.object({
some: y.object({
deep: y.object({
path: y.string().required(),
}),
array: y.array().of(
y.object({
path: y.string().required(),
}),
),
}),
}),
),
});

return { getError, isValid };
},
template: `
<form>
<Child name="some.deep.path" />
<Child name="some.array.0.path" />
<span data-testid="is-valid">{{ isValid }}</span>
<span data-testid="e1">{{ getError('some.deep.path') }}</span>
<span data-testid="e2">{{ getError('some.array.0.path') }}</span>
</form>
`,
});

await flush();
expect(screen.getByTestId('is-valid').textContent).toBe('false');
expect(screen.getByTestId('e1').textContent).toBe(requiredMessage('some.deep.path'));
expect(screen.getByTestId('e2').textContent).toBe(requiredMessage('some.array[0].path'));

await fireEvent.update(screen.getByTestId('some.deep.path'), 'test');
await fireEvent.update(screen.getByTestId('some.array.0.path'), 'test');
await fireEvent.blur(screen.getByTestId('some.deep.path'));
await fireEvent.blur(screen.getByTestId('some.array.0.path'));
await flush();
expect(screen.getByTestId('is-valid').textContent).toBe('true');
expect(screen.getByTestId('e1').textContent).toBe('');
expect(screen.getByTestId('e2').textContent).toBe('');
});

test('prevents submission if the form is not valid', async () => {
const handler = vi.fn();

Expand Down
6 changes: 3 additions & 3 deletions packages/schema-yup/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { InferType, Schema, ValidateOptions, ValidationError } from 'yup';
import type { PartialDeep } from 'type-fest';
import { TypedSchema, TypedSchemaError } from '@formwerk/core';
import { TypedSchema, TypedSchemaError, normalizePath } from '@formwerk/core';
import { isObject, merge } from '../../shared/src';

export function defineSchema<TSchema extends Schema, TOutput = InferType<TSchema>, TInput = PartialDeep<TOutput>>(
Expand All @@ -26,12 +26,12 @@ export function defineSchema<TSchema extends Schema, TOutput = InferType<TSchema
}

if (!error.inner?.length && error.errors.length) {
return { errors: [{ path: error.path as string, messages: error.errors }] };
return { errors: [{ path: normalizePath(error.path as string), messages: error.errors }] };
}

const errors: Record<string, TypedSchemaError> = error.inner.reduce(
(acc, curr) => {
const path = curr.path || '';
const path = normalizePath(curr.path || '');
if (!acc[path]) {
acc[path] = { messages: [], path };
}
Expand Down
56 changes: 55 additions & 1 deletion packages/schema-zod/src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { defineSchema } from '.';
import { z } from 'zod';
import flush from 'flush-promises';

describe('schema-yup', () => {
describe('schema-zod', () => {
function createInputComponent(): Component {
return {
inheritAttrs: false,
Expand Down Expand Up @@ -153,4 +153,58 @@ describe('schema-yup', () => {
await expect(screen.getByDisplayValue('default-test')).toBeDefined();
await expect(screen.getByDisplayValue('22')).toBeDefined();
});

test('validates nested paths', async () => {
await render({
components: { Child: createInputComponent() },
setup() {
const { getError, isValid, values } = useForm({
schema: defineSchema(
z.object({
some: z.object({
deep: z.object({
path: z.string().min(1, 'Required'),
}),
array: z.array(
z.object({
path: z.string().min(1, 'Required'),
}),
),
}),
}),
),
});

return { getError, isValid, values };
},
template: `
<form>
<Child name="some.deep.path" />
<Child name="some.array.0.path" />
{{values}}
<span data-testid="is-valid">{{ isValid }}</span>
<span data-testid="e1">{{ getError('some.deep.path') }}</span>
<span data-testid="e2">{{ getError('some.array.0.path') }}</span>
</form>
`,
});

await flush();
vi.advanceTimersByTime(1000);
await flush();
expect(screen.getByTestId('is-valid').textContent).toBe('false');
expect(screen.getByTestId('e1').textContent).toBe('Required');
expect(screen.getByTestId('e2').textContent).toBe('Required');

await fireEvent.update(screen.getByTestId('some.deep.path'), 'test');
await fireEvent.update(screen.getByTestId('some.array.0.path'), 'test');
await fireEvent.blur(screen.getByTestId('some.deep.path'));
await fireEvent.blur(screen.getByTestId('some.array.0.path'));
vi.advanceTimersByTime(1000);
await flush();
expect(screen.getByTestId('is-valid').textContent).toBe('true');
expect(screen.getByTestId('e1').textContent).toBe('');
expect(screen.getByTestId('e2').textContent).toBe('');
});
});
2 changes: 1 addition & 1 deletion packages/test-utils/src/flush.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import { vi } from 'vitest';

export async function flush() {
await flushPromises();
vi.advanceTimersByTime(SCHEMA_BATCH_MS);
vi.advanceTimersByTime(SCHEMA_BATCH_MS + 10);
await flushPromises();
}

0 comments on commit a7742a5

Please sign in to comment.