diff --git a/.eslintrc.cjs b/.eslintrc.cjs index b277371..9f9dd9c 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -48,5 +48,13 @@ module.exports = { 'vue/no-bare-strings-in-template': 'off', }, }, + { + files: ['./apps/demo/**/*'], + rules: { + '@typescript-eslint/no-magic-numbers': 'off', + 'no-magic-numbers': 'off', + 'vue/no-bare-strings-in-template': 'off', + }, + }, ], }; diff --git a/apps/demo/src/views/FormView.spec.ts b/apps/demo/src/views/FormView.spec.ts index 66bc6f6..9d6961b 100644 --- a/apps/demo/src/views/FormView.spec.ts +++ b/apps/demo/src/views/FormView.spec.ts @@ -1,6 +1,5 @@ -import {defineComponent, h, nextTick, Suspense, type DefineComponent} from 'vue'; -import {describe, it, expect, afterEach} from 'vitest'; -import {render, within, waitFor} from '@testing-library/vue'; +import {describe, it, expect} from 'vitest'; +import {render, within} from '@testing-library/vue'; import userEvent from '@testing-library/user-event'; import FormView from './FormView.vue'; @@ -18,40 +17,9 @@ export const flushPromises = (): Promise => { }); }; -const capitalize = (string: string): string => { - return string.charAt(0).toUpperCase() + string.slice(1); -}; - -const suspenseWrapper = (componentToWrap: any): DefineComponent => { - return defineComponent({ - name: 'SuspenseWrapper', - props: componentToWrap.props, - emits: componentToWrap.emits, - render() { - const props = { - ...this.$props, - }; - componentToWrap.emits?.forEach((emit: string) => { - props[`on${capitalize(emit)}`] = (...args: any[]) => this.$emit(emit, ...args); - }); - const slots = this.$slots; - return h( - 'div', - {id: 'root'}, - h(Suspense, null, { - default() { - return h(componentToWrap, props, slots); - }, - fallback: () => h('div', 'fallback'), - }), - ); - }, - }); -}; - describe('FormView', () => { const renderComponent = async () => { - const component = render(suspenseWrapper(FormView)); + const component = render(FormView); await flushPromises(); return component; }; @@ -74,7 +42,8 @@ describe('FormView', () => { const descriptionFields = getAllByLabelText('Description'); const descriptionField = descriptionFields[0]; - const errors = within(descriptionField.parentElement).getByRole('list'); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const errors = within(descriptionField.parentElement!).getByRole('list'); const error = within(errors).getByRole('listitem'); expect(error.innerText).toBe('This is an error from afterSubmit'); @@ -95,7 +64,8 @@ describe('FormView', () => { const lastNameFields = getAllByLabelText('Last name'); const lastNameField = lastNameFields[0]; - const errors = within(lastNameField.parentElement).getByRole('list'); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const errors = within(lastNameField.parentElement!).getByRole('list'); const error = within(errors).getByRole('listitem'); expect(error.innerText).toBe('This is an error from afterSubmit'); @@ -116,7 +86,8 @@ describe('FormView', () => { const lastNameFields = getAllByLabelText('Last name'); const lastNameField = lastNameFields[0]; - const errors = within(lastNameField.parentElement).getByRole('list'); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const errors = within(lastNameField.parentElement!).getByRole('list'); const error = within(errors).getByRole('listitem'); expect(error.innerText).toBe('Are you kidding me?'); }); diff --git a/apps/demo/src/views/FormView.vue b/apps/demo/src/views/FormView.vue index f5822ac..b1bbab1 100644 --- a/apps/demo/src/views/FormView.vue +++ b/apps/demo/src/views/FormView.vue @@ -139,7 +139,7 @@ diff --git a/apps/demo/src/views/__snapshots__/FormView.spec.ts.snap b/apps/demo/src/views/__snapshots__/FormView.spec.ts.snap index 825a162..8014c3a 100644 --- a/apps/demo/src/views/__snapshots__/FormView.spec.ts.snap +++ b/apps/demo/src/views/__snapshots__/FormView.spec.ts.snap @@ -1,89 +1,87 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`FormView > matches the snapshot 1`] = ` -"
-
-

Form demo

-

These forms are defined entirely in the template. The components can be placed anywhere in the template. You can even choose to manually place the Label and Errors components as well.

-
-
-
-
-

Form 1

-
-
-
- - -
Try filling in "Plankton" here -
-
-
(optioneel) - -
-
-
(optioneel) +"
+

Form demo

+

These forms are defined entirely in the template. The components can be placed anywhere in the template. You can even choose to manually place the Label and Errors components as well.

+
+
+ +
+

Form 1

+
+
+
+ + +
Try filling in "Plankton" here +
+
+
(optioneel)
-
-
[]
+
(optioneel)
-
-
-

Are you ready, Spongebob Krabs?

-
-
-
-
-
+
+
+
[]
+ +
+
+
+

Are you ready, Spongebob Krabs?

+
+
+
+
- -
-
NamenewFormisDirtytrueisValidtruevalues
{
+        
+ +
+
NamenewFormisDirtytrueisValidtruevalues
{
   "firstName": "Spongebob",
   "middleName": "Harold",
   "lastName": "Krabs",
   "email": ""
 }
Event log
-
-
-
-
-

Form 2

-

This form reuses the email field from the first form

-
-
- - -
-
This is the email label
-
This is a random div, just to show the field's components can be placed anywhere.
-
This is the email component itself
-
- This is the email Errors component. You won't see it if there are no errors. -
+
+
+ +
+

Form 2

+

This form reuses the email field from the first form

+
+
+ +
+
This is the email label
+
This is a random div, just to show the field's components can be placed anywhere.
+
This is the email component itself
+
+ This is the email Errors component. You won't see it if there are no errors. +
- -
-
NamenewForm2isDirtyfalseisValidtruevalues
{
+        
+ +
+
NamenewForm2isDirtyfalseisValidtruevalues
{
   "description": "",
   "email": ""
 }
Event log
-
diff --git a/apps/vue-form-builder/src/__tests__/form/field.spec.ts b/apps/vue-form-builder/src/__tests__/form/field.spec.ts index efe60f9..2eaca5f 100644 --- a/apps/vue-form-builder/src/__tests__/form/field.spec.ts +++ b/apps/vue-form-builder/src/__tests__/form/field.spec.ts @@ -1,4 +1,4 @@ -import {h, markRaw, ref, nextTick, toValue} from 'vue'; +import {markRaw, ref, toValue} from 'vue'; import {describe, expect, it, vi} from 'vitest'; import {flushPromises, mount} from '@vue/test-utils'; import {generateTestForm} from '../utils/generateTestForm'; @@ -19,6 +19,7 @@ describe('Form fields', () => { field: { wrapper: markRaw(FormGroup), }, + // @ts-expect-error todo fields: [ defineField({ name: 'firstName', @@ -40,10 +41,10 @@ describe('Form fields', () => { await flushPromises(); await wrapper.find('input[name="firstName"]').setValue('Hank'); - expect(price.value).toBe('50'); + expect(toValue(price)).toBe('50'); await wrapper.find('input[name="firstName"]').setValue('Jack'); - expect(price.value).toBe('100'); + expect(toValue(price)).toBe('100'); }); it('can calculate forwards based on primary input, out of a promise', async () => { @@ -58,7 +59,7 @@ describe('Form fields', () => { name: 'firstName', component: TextInput, ref: firstName, - afterUpdate: async (field, newValue) => { + afterUpdate: async (field, newValue: string) => { const remote = await optionData(newValue); field.form.model.price.ref.value = remote.price; @@ -77,12 +78,12 @@ describe('Form fields', () => { vi.advanceTimersByTime(1000); await flushPromises(); - expect(price.value).toBe('50'); + expect(toValue(price)).toBe('50'); await wrapper.find('input[name="firstName"]').setValue('John'); vi.advanceTimersByTime(1000); await flushPromises(); - expect(price.value).toBe('100'); + expect(toValue(price)).toBe('100'); vi.useRealTimers(); }); @@ -128,7 +129,7 @@ describe('Form fields', () => { await form.model.element.reset(); - expect(form.isValid.value).toBe(true); + expect(toValue(form.isValid)).toBe(true); }); it('gets filled with initial data from form config', async () => { @@ -146,27 +147,6 @@ describe('Form fields', () => { expect(toValue(form.model.toggle.ref)).toBe(false); }); - it.skip('can pass through slots', async () => { - expect.assertions(1); - - const field = defineField({ - component: h('div', () => ['this.$slots']), - name: 'element', - ref: ref(''), - slots: { - default: () => ['this.element.slots 1', h('div', () => ['this.element.slots 2'])], - }, - }); - - const {instance: form} = await generateTestForm({fields: [field], initialValues: {element: 'hello'}}); - - const wrapper = mount(MagicForm, {props: {form}}); - - await nextTick(); - - expect(wrapper.html()).toMatchSnapshot(); - }); - it('it can invalidate a field', async () => { expect.assertions(1); @@ -177,10 +157,11 @@ describe('Form fields', () => { }); const {instance: form} = await generateTestForm<{element: string}>([field]); - const fieldInstance = form.getField('element'); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const fieldInstance = form.getField('element')!; fieldInstance.setInvalid(); - expect(fieldInstance?.isValid.value).toBe(false); + expect(toValue(fieldInstance?.isValid)).toBe(false); }); it('can add an error to a field', async () => { @@ -193,9 +174,10 @@ describe('Form fields', () => { }); const {instance: form} = await generateTestForm<{element: string}>([field]); - const fieldInstance = form.getField('element'); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const fieldInstance = form.getField('element')!; fieldInstance.addError('error message'); - expect(fieldInstance?.errors.value).toEqual(['error message']); + expect(toValue(fieldInstance?.errors)).toEqual(['error message']); }); });