import { it, describe, expect } from 'vitest' import { mount, shallowMount } from '@vue/test-utils' import VueSelect from '@/components/Select.vue' import { mountDefault } from '@tests/helpers.js' describe('When reduce prop is defined', () => { it('determines when a reducer has been supplied', async () => { const Select = mountDefault() expect(Select.vm.isReducingValues).toBeFalsy() await Select.setProps({ reduce: () => {} }) expect(Select.vm.isReducingValues).toBeTruthy() }) it('can accept an array of objects and pre-selected value (single)', () => { const Select = shallowMount(VueSelect, { props: { reduce: (option) => option.value, modelValue: 'foo', options: [{ label: 'This is Foo', value: 'foo' }], }, }) expect(Select.vm.selectedValue).toEqual([ { label: 'This is Foo', value: 'foo' }, ]) }) it('can determine if an object is pre-selected', () => { const Select = shallowMount(VueSelect, { props: { reduce: (option) => option.id, modelValue: 'foo', options: [ { id: 'foo', label: 'This is Foo', }, ], }, }) expect( Select.vm.isOptionSelected({ id: 'foo', label: 'This is Foo', }) ).toEqual(true) }) it('can determine if an object is selected after its been chosen', () => { const Select = shallowMount(VueSelect, { props: { reduce: (option) => option.id, options: [{ id: 'foo', label: 'FooBar' }], }, }) Select.vm.select({ id: 'foo', label: 'FooBar' }) expect( Select.vm.isOptionSelected({ id: 'foo', label: 'This is FooBar', }) ).toEqual(true) }) it('can accept an array of objects and pre-selected values (multiple)', () => { const Select = shallowMount(VueSelect, { props: { multiple: true, reduce: (option) => option.value, modelValue: ['foo'], options: [ { label: 'This is Foo', value: 'foo' }, { label: 'This is Bar', value: 'bar' }, ], }, }) expect(Select.vm.selectedValue).toEqual([ { label: 'This is Foo', value: 'foo' }, ]) }) it('can deselect a pre-selected object', () => { const Select = shallowMount(VueSelect, { props: { multiple: true, reduce: (option) => option.value, options: [ { label: 'This is Foo', value: 'foo' }, { label: 'This is Bar', value: 'bar' }, ], }, }) Select.vm.$data._value = ['foo', 'bar'] Select.vm.deselect('foo') expect(Select.vm.selectedValue).toEqual(['bar']) }) it('can deselect an option when multiple is false', () => { const Select = shallowMount(VueSelect, { props: { reduce: (option) => option.value, options: [ { label: 'This is Foo', value: 'foo' }, { label: 'This is Bar', value: 'bar' }, ], }, }) Select.vm.deselect('foo') expect(Select.vm.selectedValue).toEqual([]) }) it('can use v-model syntax for a two way binding to a parent component', async () => { const Parent = mount({ data: () => ({ reduce: (option) => option.value, current: 'foo', options: [ { label: 'This is Foo', value: 'foo' }, { label: 'This is Bar', value: 'bar' }, { label: 'This is Baz', value: 'baz' }, ], }), components: { 'v-select': VueSelect }, computed: { value: { get() { return this.current }, set(value) { if (value == 'baz') return this.current = value }, }, }, template: ` `, }) const Select = Parent.getComponent({ name: 'v-select' }) expect(Select.vm.modelValue).toEqual('foo') expect(Select.vm.selectedValue).toEqual([ { label: 'This is Foo', value: 'foo' }, ]) Select.vm.select({ label: 'This is Bar', value: 'bar' }) await Select.vm.$nextTick() expect(Parent.vm.value).toEqual('bar') expect(Select.vm.selectedValue).toEqual([ { label: 'This is Bar', value: 'bar' }, ]) // Parent denies to set baz Select.vm.select({ label: 'This is Baz', value: 'baz' }) await Select.vm.$nextTick() expect(Select.vm.selectedValue).toEqual([ { label: 'This is Bar', value: 'bar' }, ]) expect(Parent.vm.value).toEqual('bar') }) it('can generate labels using a custom label key', () => { const Select = shallowMount(VueSelect, { props: { multiple: true, reduce: (option) => option.value, modelValue: ['CA'], label: 'name', options: [ { value: 'CA', name: 'Canada' }, { value: 'US', name: 'United States' }, ], }, }) expect(Select.find('.vs__selected').text()).toContain('Canada') }) it('can find the original option within this.options', () => { const optionToFind = { id: 1, label: 'Foo' } const Select = shallowMount(VueSelect, { props: { reduce: (option) => option.id, options: [optionToFind, { id: 2, label: 'Bar' }], }, }) expect(Select.vm.findOptionFromReducedValue(1)).toEqual(optionToFind) expect(Select.vm.findOptionFromReducedValue(optionToFind)).toEqual( optionToFind ) }) it('can work with falsey values', () => { const option = { value: 0, label: 'No' } const Select = shallowMount(VueSelect, { props: { reduce: (option) => option.value, options: [option, { value: 1, label: 'Yes' }], modelValue: 0, }, }) expect(Select.vm.findOptionFromReducedValue(option)).toEqual(option) expect(Select.vm.selectedValue).toEqual([option]) }) it('works with null values', () => { const option = { value: null, label: 'No' } const Select = shallowMount(VueSelect, { props: { reduce: (option) => option.value, options: [option, { value: 1, label: 'Yes' }], modelValue: null, }, }) expect(Select.vm.findOptionFromReducedValue(option)).toEqual(option) expect(Select.vm.selectedValue).toEqual([option]) }) describe('And when a reduced option is a nested object', () => { it('can determine if an object is pre-selected', () => { const nestedOption = { value: { nested: true }, label: 'foo' } const Select = shallowMount(VueSelect, { props: { reduce: (option) => option.value, modelValue: { nested: true, }, options: [nestedOption], }, }) expect(Select.vm.selectedValue).toEqual([nestedOption]) }) it('can determine if an object is selected after it is chosen', () => { const nestedOption = { value: { nested: true }, label: 'foo' } const Select = shallowMount(VueSelect, { props: { reduce: (option) => option.value, options: [nestedOption], }, }) Select.vm.select(nestedOption) expect(Select.vm.isOptionSelected(nestedOption)).toEqual(true) }) }) it('reacts correctly when value property changes', async () => { const optionToChangeTo = { id: 1, label: 'Foo' } const Select = shallowMount(VueSelect, { props: { modelValue: 2, reduce: (option) => option.id, options: [optionToChangeTo, { id: 2, label: 'Bar' }], }, }) Select.setProps({ modelValue: optionToChangeTo.id }) await Select.vm.$nextTick() expect(Select.vm.selectedValue).toEqual([optionToChangeTo]) }) describe('Reducing Tags', () => { it('tracks values that have been created by the user', async () => { const Parent = mount({ data: () => ({ selected: null, options: [] }), template: ` `, components: { 'v-select': VueSelect }, }) const Select = Parent.getComponent({ name: 'v-select' }) // When await Select.get('input').trigger('focus') Select.vm.search = 'hello' await Select.vm.$nextTick() Select.vm.typeAheadSelect() await Select.vm.$nextTick() // Then expect(Select.vm.selectedValue).toEqual([{ label: 'hello', value: -1 }]) expect(Select.vm.$refs.selectedOptions.textContent.trim()).toEqual( 'hello' ) expect(Parent.vm.selected).toEqual(-1) }) }) })