UNPKG

@maxpike/vue

Version:

Vue VariantJS: Fully configurable Vue 3 components styled with TailwindCSS

595 lines (483 loc) 14.3 kB
/* eslint-disable @typescript-eslint/no-explicit-any */ import { NormalizedOption } from '@variantjs/core'; import { mount, shallowMount } from '@vue/test-utils'; import { ref } from 'vue'; import RichSelectOption from '../../../components/TRichSelect/RichSelectOption.vue'; describe('RichSelectOption', () => { const scrollIntoViewMock = jest.fn(); window.HTMLLIElement.prototype.scrollIntoView = scrollIntoViewMock; const toggleOption = jest.fn(); const setActiveOption = jest.fn(); const optionIsSelected = jest.fn(); const optionIsActive = jest.fn(); const shown = ref(true); const option: NormalizedOption = { value: 'a', text: 'Option A', }; const deep = 0; const global = { provide: { toggleOption, setActiveOption, optionIsSelected, optionIsActive, shown, }, stubs: { RichSelectOptionsList: { template: '<div />', }, }, }; afterEach(() => { jest.clearAllMocks(); optionIsActive.mockReturnValue(false); scrollIntoViewMock.mockReset(); }); it('renders the component', () => { const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); expect(wrapper.vm.$el.tagName).toBe('LI'); expect(wrapper.vm.$el.textContent).toBe('Option A'); }); it('determines if option has children', () => { const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); expect(wrapper.vm.hasChildren).toBe(false); }); it('determines if option has children when empty', () => { const wrapper = shallowMount(RichSelectOption, { props: { option: { ...option, children: [], }, deep, }, global, }); expect(wrapper.vm.hasChildren).toBe(false); }); it('determines if option has children when not empty', () => { const wrapper = shallowMount(RichSelectOption, { props: { option: { ...option, children: [ { value: 1, text: 1 }, ], }, deep, }, global, }); expect(wrapper.vm.hasChildren).toBe(true); }); it('determines if option is selected', () => { optionIsSelected.mockReturnValue(true); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); expect(wrapper.vm.isSelected).toBe(true); }); it('determines if option is selected when false', () => { optionIsSelected.mockReturnValue(false); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); expect(wrapper.vm.isSelected).toBe(false); }); it('determines if option is active', () => { optionIsActive.mockReturnValue(true); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); jest.spyOn(wrapper.vm, 'scrollIntoViewIfNeccesary').mockImplementation(() => {}); expect(wrapper.vm.isActive).toBe(true); }); it('determines if option is active when false', () => { optionIsActive.mockReturnValue(false); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); expect(wrapper.vm.isActive).toBe(false); }); it('shows the checkmark icon if option is selected', () => { optionIsSelected.mockReturnValue(true); const wrapper = mount(RichSelectOption, { props: { option, deep, }, global, }); expect(wrapper.vm.$refs.checkIcon).toBeDefined(); }); it('hides the checkmark icon if option is not selected', () => { optionIsSelected.mockReturnValue(false); const wrapper = mount(RichSelectOption, { props: { option, deep, }, global, }); expect(wrapper.vm.$refs.checkIcon).toBeUndefined(); }); it('will scroll into the view if shown and is active', async () => { optionIsActive.mockReturnValue(true); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); wrapper.vm.$el.scrollIntoView = scrollIntoViewMock; await wrapper.vm.$nextTick(); expect(scrollIntoViewMock).toHaveBeenCalled(); }); it('will scroll into the view if active changes state', async () => { optionIsActive.mockReturnValue(true); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); await wrapper.vm.$nextTick(); // First time when created expect(scrollIntoViewMock).toHaveBeenCalledTimes(1); (wrapper.vm.$options.watch!.isActive as any).call(wrapper.vm); // Second time when state changed expect(scrollIntoViewMock).toHaveBeenCalledTimes(2); }); it('will not scroll into the view if shown but is not active', async () => { optionIsActive.mockReturnValue(false); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); wrapper.vm.$el.scrollIntoView = scrollIntoViewMock; await wrapper.vm.$nextTick(); expect(scrollIntoViewMock).not.toHaveBeenCalled(); }); it('will not scroll into the view if is active but is not shown', async () => { optionIsActive.mockReturnValue(true); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global: { provide: { ...global.provide, shown: ref(false), }, stubs: global.stubs, }, }); wrapper.vm.$el.scrollIntoView = scrollIntoViewMock; await wrapper.vm.$nextTick(); expect(scrollIntoViewMock).not.toHaveBeenCalled(); }); describe('event handlers', () => { it('calls the `mousemoveHandler` when option mousemove', () => { const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); const mousemoveHandlerSpy = jest.spyOn(wrapper.vm, 'mousemoveHandler'); wrapper.vm.$el.dispatchEvent(new MouseEvent('mousemove')); expect(mousemoveHandlerSpy).toHaveBeenCalled(); }); it('calls setActiveOption method when `mousemoveHandler` called', () => { const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); wrapper.vm.mousemoveHandler(); expect(setActiveOption).toHaveBeenCalledWith(option); }); it('doesnt call setActiveOption method when `mousemoveHandler` called and option is disabled', () => { const wrapper = shallowMount(RichSelectOption, { props: { option: { ...option, disabled: true, }, deep, }, global, }); wrapper.vm.mousemoveHandler(); expect(setActiveOption).not.toHaveBeenCalled(); }); it('calls the `mousewheelHandler` when mousewheel event', () => { const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); const mousewheelHandlerSpy = jest.spyOn(wrapper.vm, 'mousewheelHandler'); wrapper.vm.$el.dispatchEvent(new MouseEvent('mousewheel')); expect(mousewheelHandlerSpy).toHaveBeenCalled(); }); it('call setActiveOption method when `mousewheelHandler` is called ', () => { const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); wrapper.vm.mousewheelHandler(); expect(setActiveOption).toHaveBeenCalledWith(option); }); it('doesnt call setActiveOption method when `mousewheelHandler` is called and option is disabled', () => { const wrapper = shallowMount(RichSelectOption, { props: { option: { ...option, disabled: true, }, deep, }, global, }); wrapper.vm.mousewheelHandler(); expect(setActiveOption).not.toHaveBeenCalled(); }); it('calls the `clickHandler` when option clicked', () => { const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); const clickHandlerSpy = jest.spyOn(wrapper.vm, 'clickHandler'); wrapper.vm.$el.dispatchEvent(new MouseEvent('click')); expect(clickHandlerSpy).toHaveBeenCalled(); }); it('the `clickHandler` toggles the option', () => { const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); wrapper.vm.clickHandler(); expect(toggleOption).toHaveBeenCalledWith(option); }); it('doesnt call option toggle method when `clickHandler` is called and option is disabled', () => { const wrapper = shallowMount(RichSelectOption, { props: { option: { ...option, disabled: true, }, deep, }, global, }); wrapper.vm.clickHandler(); expect(toggleOption).not.toHaveBeenCalled(); }); }); describe('regular option attributes', () => { it('has the correct `aria-selected` attribute when is selected', () => { optionIsSelected.mockReturnValue(true); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); expect(wrapper.vm.$el.querySelector('button').getAttribute('aria-selected')).toBe('true'); }); it('has the correct `aria-selected` attribute when is not selected', () => { optionIsSelected.mockReturnValue(false); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); expect(wrapper.vm.$el.querySelector('button').getAttribute('aria-selected')).toBe('false'); }); it('has the role=option attribute', () => { const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); expect(wrapper.vm.$el.querySelector('button').getAttribute('role')).toBe('option'); }); it('has the tabindex=-1 attribute', () => { const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global, }); expect(wrapper.vm.$el.querySelector('button').getAttribute('tabindex')).toBe('-1'); }); it.each([1, 'foo', undefined, NaN])('adds a value attribute for regular values with %s', (value) => { const wrapper = shallowMount(RichSelectOption, { props: { option: { value, text: 'Foo', }, deep, }, global, }); expect(wrapper.vm.$el.querySelector('button').getAttribute('value')).toBe(String(value)); }); it.each([{ foo: 'bar' }, [1, 2], null])('adds a value attribute for objects %s', (value) => { const wrapper = shallowMount(RichSelectOption, { props: { option: { value, text: 'Foo', }, deep, } as any, global, }); expect(wrapper.vm.$el.querySelector('button').getAttribute('value')).toBe(JSON.stringify(value)); }); }); describe('option classes', () => { const classesList = { option: 'option', selectedHighlightedOption: 'selected-highlighted-option', selectedOption: 'selected-option', highlightedOption: 'highlighted-option', }; const configuration = { classesList }; it('adds the selectedHighlightedOption if option is selected an active', () => { optionIsSelected.mockReturnValue(true); optionIsActive.mockReturnValue(true); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global: { ...global, provide: { ...global.provide, configuration, }, }, }); expect(wrapper.vm.$el.querySelector('button').getAttribute('class')).toBe('option selected-highlighted-option'); }); it('adds the selectedOption if option is selected but is not active', () => { optionIsSelected.mockReturnValue(true); optionIsActive.mockReturnValue(false); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global: { ...global, provide: { ...global.provide, configuration, }, }, }); expect(wrapper.vm.$el.querySelector('button').getAttribute('class')).toBe('option selected-option'); }); it('adds the highlightedOption if option is active but is not selected', () => { optionIsSelected.mockReturnValue(false); optionIsActive.mockReturnValue(true); const wrapper = shallowMount(RichSelectOption, { props: { option, deep, }, global: { ...global, provide: { ...global.provide, configuration, }, }, }); expect(wrapper.vm.$el.querySelector('button').getAttribute('class')).toBe('option highlighted-option'); }); }); describe('option has children', () => { const wrapper = shallowMount(RichSelectOption, { props: { option: { value: 'foo', text: 'Foo', children: [{ value: 1, text: 1 }], }, deep: 0, }, global, }); it('has the role=optgroup attribute', () => { expect(wrapper.vm.$el.getAttribute('role')).toBe('optgroup'); }); it('has the option text', () => { expect(wrapper.vm.$el.textContent).toBe('Foo'); }); it('shows the childrenOptions component', () => { expect(wrapper.vm.$refs.childrenOptions).toBeDefined(); }); }); });