@maxpike/vue
Version:
Vue VariantJS: Fully configurable Vue 3 components styled with TailwindCSS
399 lines (329 loc) • 9.8 kB
text/typescript
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { shallowMount } from '@vue/test-utils';
import { TButtonConfig } from '@variantjs/core';
import TButton from '../../components/TButton.vue';
describe('TButton.vue', () => {
it('renders the button', () => {
const wrapper = shallowMount(TButton);
expect(wrapper.get('button')).toBeTruthy();
});
it('renders the button with a default set of classes', () => {
const wrapper = shallowMount(TButton);
expect(wrapper.html()).toBe(`<button class="${TButtonConfig.classes}"></button>`);
});
it('renders the button without attributes if no default theme', () => {
const wrapper = shallowMount(TButton, {
global: {
provide: {
configuration: {
TButton: {
classes: undefined,
},
},
},
},
});
expect(wrapper.html()).toBe('<button></button>');
});
it('renders the button with the text in the slot', () => {
const wrapper = shallowMount(TButton, {
props: {
classes: undefined,
},
slots: {
default: 'Press me!',
},
});
expect(wrapper.html()).toBe('<button>Press me!</button>');
});
it('set the props.value as the button value', () => {
const value = 'button value';
const wrapper = shallowMount(TButton, {
props: { value },
});
expect(wrapper.vm.$el.value).toBe(value);
});
it('doesnt add the tagName as attribute', () => {
const wrapper = shallowMount(TButton, {
props: { tagName: 'a' },
});
expect(wrapper.vm.$el.attributes.tagName).toBeUndefined();
});
it('disables the button', async () => {
const wrapper = shallowMount(TButton, {
props: { disabled: false },
});
expect(wrapper.vm.$el.disabled).toBe(false);
await wrapper.setProps({ disabled: true });
expect(wrapper.vm.$el.disabled).toBe(true);
});
it('adds the configuration attribute', async () => {
const wrapper = shallowMount(TButton, {
global: {
provide: {
configuration: {
TButton: {
type: 'button',
'data-id': 'something',
},
},
},
},
});
const button = wrapper.vm.$el as HTMLButtonElement;
expect(button.type).toBe('button');
expect(button.dataset.id).toBe('something');
});
it('prioritizes the attribute over the configuratiion', async () => {
const wrapper = shallowMount(TButton, {
global: {
provide: {
configuration: {
TButton: {
type: 'button',
},
},
},
},
attrs: {
type: 'submit',
},
});
const button = wrapper.vm.$el;
expect(button.type).toBe('submit');
});
it('accepts misc button attributes', async () => {
const wrapper = shallowMount(TButton);
const values = {
id: {
default: '',
new: 'new-id',
},
autofocus: {
default: false,
new: true,
},
disabled: {
default: false,
new: true,
},
name: {
default: '',
new: 'new-name',
},
title: {
default: '',
new: 'new-title',
},
type: {
default: 'submit',
new: 'button',
},
};
const newProps: any = {};
// Check for the default values
Object.keys(values).forEach((key) => {
const elementValue = (values as any)[key];
expect(wrapper.vm.$el[elementValue.keyName || key]).toBe(elementValue.default);
newProps[key as any] = elementValue.new;
});
await wrapper.setProps(newProps);
// Check for the new values
Object.keys(values).forEach((key) => {
const elementValue = (values as any)[key];
expect(wrapper.vm.$el[elementValue.keyName || key]).toBe(elementValue.new);
});
});
it('emits native button events', () => {
const onClick = jest.fn();
const onBlur = jest.fn();
const onFocus = jest.fn();
const onKeyup = jest.fn();
const wrapper = shallowMount(TButton, {
attrs: {
onClick,
onBlur,
onFocus,
onKeyup,
},
});
const button = wrapper.vm.$el;
button.dispatchEvent(new MouseEvent('click'));
expect(onClick).toHaveBeenCalled();
button.dispatchEvent(new FocusEvent('focus'));
expect(onFocus).toHaveBeenCalled();
button.dispatchEvent(new FocusEvent('blur'));
expect(onBlur).toHaveBeenCalled();
button.dispatchEvent(new KeyboardEvent('keyup', { key: 'a' }));
expect(onKeyup).toHaveBeenCalled();
});
it('has native button methods', () => {
const wrapper = shallowMount(TButton);
const button = wrapper.vm.$el;
expect(typeof button.click).toBe('function');
expect(typeof button.focus).toBe('function');
expect(typeof button.blur).toBe('function');
});
it('triggers custom events', async () => {
const onCustom = jest.fn();
const wrapper = shallowMount(TButton, {
attrs: {
onCustom,
},
});
const button = wrapper.vm.$el as HTMLButtonElement;
const evt = new CustomEvent('custom', { detail: 'my-custom-event' });
button.dispatchEvent(evt);
expect(onCustom).toHaveBeenCalled();
});
it('default to button tag', () => {
const wrapper = shallowMount(TButton);
expect(wrapper.vm.$el.tagName).toBe('BUTTON');
});
it('accepts anchor tag', () => {
const wrapper = shallowMount(TButton, {
props: { tagName: 'a' },
});
expect(wrapper.vm.$el.tagName).toBe('A');
});
it('uses anchor tag when has href attribute', () => {
const wrapper = shallowMount(TButton, {
props: { href: 'https://www.vexilo.com/' },
});
expect(wrapper.vm.$el.tagName).toBe('A');
expect(wrapper.vm.$el.href).toBe('https://www.vexilo.com/');
});
describe('Router Link', () => {
it('has router link related props', () => {
const props = {
to: '/something',
replace: true,
activeClass: 'activeClass',
exactActiveClass: 'exactActiveClass',
custom: true,
ariaCurrentValue: 'location',
};
type RouterProps = typeof props;
const wrapper = shallowMount(TButton, {
props: props as any,
});
Object.keys(props).forEach((key) => {
expect((wrapper.vm as any)[key]).toBe(props[key as keyof RouterProps]);
});
});
it('doesnt have a router link component by default', () => {
const wrapper = shallowMount(TButton);
expect(wrapper.vm.routerLinkComponentAvailable).toBe(false);
});
it('can determine when a router link component is available', () => {
const RouterLink = {
name: 'RouterLink',
template: '',
};
const wrapper = shallowMount(TButton, {
global: {
components: {
RouterLink,
},
},
});
expect(wrapper.vm.routerLinkComponentAvailable).toBe(true);
});
it('determine that a router link component is available if has a NuxtLink', () => {
const NuxtLink = {
name: 'NuxtLink',
template: '',
};
const wrapper = shallowMount(TButton, {
global: {
components: {
NuxtLink,
},
},
});
(wrapper.vm.$options.components as any).NuxtLink = {};
expect(wrapper.vm.routerLinkComponentAvailable).toBe(true);
});
it('uses a router-link when `to` prop is defined and the route link component is available', () => {
const RouterLink = {
name: 'RouterLink',
template: '',
};
const wrapper = shallowMount(TButton, {
global: {
components: {
RouterLink,
},
},
props: {
to: '/some-place',
classes: undefined,
},
});
expect(wrapper.vm.useRouterLink).toBe(true);
expect(wrapper.getComponent(RouterLink)).toBeTruthy();
});
it('doesnt use a router-link when `to` prop is not defined even if route link component is available', () => {
const RouterLink = {
name: 'RouterLink',
template: '',
};
const wrapper = shallowMount(TButton, {
global: {
components: {
RouterLink,
},
},
});
expect(wrapper.vm.useRouterLink).toBe(false);
});
it('uses a nuxt-link when `to` prop is defined and the nuxt-link component is available', () => {
const NuxtLink = {
name: 'NuxtLink',
template: '',
};
const wrapper = shallowMount(TButton, {
global: {
components: {
NuxtLink,
},
},
props: {
to: '/some-place',
classes: undefined,
},
});
expect(wrapper.vm.useRouterLink).toBe(true);
expect(wrapper.getComponent(NuxtLink)).toBeTruthy();
});
it('adds the routerLink related prop', () => {
const props: any = {
to: '/something',
replace: true,
activeClass: 'activeClass',
exactActiveClass: 'exactActiveClass',
custom: true,
ariaCurrentValue: 'location',
};
const RouterLink = {
name: 'RouterLink',
template: '',
props: Object.keys(props),
};
const wrapper = shallowMount(TButton, {
global: {
components: {
RouterLink,
},
},
props: {
...props,
href: '/something',
},
});
const component = wrapper.getComponent(RouterLink);
expect(component.props()).toEqual(props);
});
});
});