Skip to content

Commit

Permalink
feat: added ErrorMessage component
Browse files Browse the repository at this point in the history
  • Loading branch information
logaretm committed Jun 22, 2020
1 parent 79a3260 commit 9570412
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 0 deletions.
50 changes: 50 additions & 0 deletions packages/core/src/ErrorMessage.ts
@@ -0,0 +1,50 @@
import { inject, h, defineComponent, computed, Ref } from 'vue';
import { normalizeChildren } from './utils';

export const ErrorMessage = defineComponent({
props: {
as: {
type: String,
default: undefined,
},
name: {
type: String,
required: true,
},
},
setup(props, ctx) {
const errors = (inject('$_veeFormErrors', undefined) as unknown) as Ref<Record<string, string>>;
const message = computed<string | undefined>(() => {
return errors.value[props.name];
});

return () => {
const children = normalizeChildren(ctx, {
message: message.value,
});

const tag = props.as;

// If no tag was specified and there are children
// render the slot as is without wrapping it
if (!tag && children.length) {
return children;
}

// If no children in slot
// render whatever specified and fallback to a <span> with the message in it's contents
if (!children.length) {
console.log('nooo');
return h(tag || 'span', message.value);
}

return h(
tag,
{
...ctx.attrs,
},
children
);
};
},
});
1 change: 1 addition & 0 deletions packages/core/src/Form.ts
Expand Up @@ -27,6 +27,7 @@ export const Form = defineComponent({
});

provide('$_veeForm', form);
provide('$_veeFormErrors', errors);
const unwrappedMeta = useRefsObjToComputed(meta);

const slotProps = computed(() => {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Expand Up @@ -3,5 +3,6 @@ export { defineRule } from './defineRule';
export { configure } from './config';
export { Field } from './Field';
export { Form } from './Form';
export { ErrorMessage } from './ErrorMessage';
export { useField } from './useField';
export { useForm } from './useForm';
96 changes: 96 additions & 0 deletions packages/core/tests/ErrorMessage.spec.ts
@@ -0,0 +1,96 @@
import flushPromises from 'flush-promises';
import { defineRule, ErrorMessage } from '@vee-validate/core';
import { mountWithHoc, setValue } from './helpers';

describe('<ErrorMessage />', () => {
const REQUIRED_MESSAGE = `This field is required`;
defineRule('required', value => {
if (!value) {
return REQUIRED_MESSAGE;
}

return true;
});

// TODO: Causes infinite loop for some reason
test.skip('shows error messages for a field', async () => {
const wrapper = mountWithHoc({
components: {
ErrorMessage,
},
template: `
<VForm as="form">
<Field name="field" rules="required" as="input" />
<ErrorMessage name="field" id="error" />
<button>Validate</button>
</VForm>
`,
});

const error = wrapper.$el.querySelector('#error');
expect(error.tagName).toBe('SPAN');
const input = wrapper.$el.querySelector('input');
await flushPromises();
expect(error.textContent).toBe('');

wrapper.$el.querySelector('button').click();
await flushPromises();

expect(error.textContent).toBe(REQUIRED_MESSAGE);
setValue(input, '12');
wrapper.$el.querySelector('button').click();
await flushPromises();

expect(error.textContent).toBe('');
});

test('render with "as" prop', async () => {
const wrapper = mountWithHoc({
components: {
ErrorMessage,
},
template: `
<VForm as="form">
<Field name="field" rules="required" as="input" />
<ErrorMessage as="div" name="field" id="error" />
<button>Validate</button>
</VForm>
`,
});

const error = wrapper.$el.querySelector('#error');

expect(error.tagName).toBe('DIV');
wrapper.$el.querySelector('button').click();
await flushPromises();

expect(error.textContent).toBe(REQUIRED_MESSAGE);
});

test('render with scoped slots', async () => {
const wrapper = mountWithHoc({
components: {
ErrorMessage,
},
template: `
<VForm as="form">
<Field name="field" rules="required" as="input" />
<ErrorMessage name="field" v-slot="{ message }">
<p id="error">{{ message }}</p>
</ErrorMessage>
<button>Validate</button>
</VForm>
`,
});

const error = wrapper.$el.querySelector('#error');
expect(error.tagName).toBe('P');
wrapper.$el.querySelector('button').click();
await flushPromises();

expect(error.textContent).toBe(REQUIRED_MESSAGE);
});
});

0 comments on commit 9570412

Please sign in to comment.