UNPKG

@maxpike/vue

Version:

Vue VariantJS: Fully configurable Vue 3 components styled with TailwindCSS

399 lines (329 loc) 9.8 kB
/* 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); }); }); });