136 lines
5.5 KiB
TypeScript
136 lines
5.5 KiB
TypeScript
import { mount } from '@vue/test-utils';
|
|
import VTabs from './VTabs.vue';
|
|
import VTab from './VTab.vue';
|
|
import VTabList from './VTabList.vue';
|
|
import VTabPanel from './VTabPanel.vue';
|
|
import VTabPanels from './VTabPanels.vue';
|
|
import { TabsProviderKey } from './types';
|
|
import { nextTick, h } from 'vue';
|
|
|
|
// Helper to create a minimal tabs structure for testing VTabs logic
|
|
const createBasicTabsStructure = (activeTabId: string | null = 'tab1') => {
|
|
return {
|
|
components: { VTabs, VTabList, VTab, VTabPanels, VTabPanel },
|
|
template: `
|
|
<VTabs :modelValue="currentModelValue" @update:modelValue="val => currentModelValue = val" :initialTab="initialTabValue">
|
|
<VTabList>
|
|
<VTab id="tab1" title="Tab 1" />
|
|
<VTab id="tab2" title="Tab 2" />
|
|
</VTabList>
|
|
<VTabPanels>
|
|
<VTabPanel id="tab1"><p>Content 1</p></VTabPanel>
|
|
<VTabPanel id="tab2"><p>Content 2</p></VTabPanel>
|
|
</VTabPanels>
|
|
</VTabs>
|
|
`,
|
|
data() {
|
|
return {
|
|
currentModelValue: activeTabId,
|
|
initialTabValue: activeTabId, // Can be overridden in test
|
|
};
|
|
},
|
|
};
|
|
};
|
|
|
|
|
|
describe('VTabs.vue', () => {
|
|
it('initializes activeTabId with modelValue', () => {
|
|
const wrapper = mount(VTabs, {
|
|
props: { modelValue: 'second' },
|
|
slots: { default: '<VTabList><VTab id="first"/><VTab id="second"/></VTabList><VTabPanels><VTabPanel id="first"/><VTabPanel id="second"/></VTabPanels>' },
|
|
global: { components: { VTabList, VTab, VTabPanels, VTabPanel } } // Stubbing children
|
|
});
|
|
const context = wrapper.vm.$.provides[TabsProviderKey as any];
|
|
expect(context.activeTabId.value).toBe('second');
|
|
});
|
|
|
|
it('initializes activeTabId with initialTab if modelValue is not provided', () => {
|
|
const wrapper = mount(VTabs, {
|
|
props: { initialTab: 'third' },
|
|
slots: { default: '<VTabList><VTab id="first"/><VTab id="third"/></VTabList><VTabPanels><VTabPanel id="first"/><VTabPanel id="third"/></VTabPanels>' },
|
|
global: { components: { VTabList, VTab, VTabPanels, VTabPanel } }
|
|
});
|
|
const context = wrapper.vm.$.provides[TabsProviderKey as any];
|
|
expect(context.activeTabId.value).toBe('third');
|
|
});
|
|
|
|
it('updates activeTabId when modelValue prop changes', async () => {
|
|
const wrapper = mount(VTabs, {
|
|
props: { modelValue: 'one' },
|
|
slots: { default: '<VTabList><VTab id="one"/><VTab id="two"/></VTabList><VTabPanels><VTabPanel id="one"/><VTabPanel id="two"/></VTabPanels>' },
|
|
global: { components: { VTabList, VTab, VTabPanels, VTabPanel } }
|
|
});
|
|
const context = wrapper.vm.$.provides[TabsProviderKey as any];
|
|
expect(context.activeTabId.value).toBe('one');
|
|
await wrapper.setProps({ modelValue: 'two' });
|
|
expect(context.activeTabId.value).toBe('two');
|
|
});
|
|
|
|
it('emits update:modelValue when selectTab is called', async () => {
|
|
const wrapper = mount(VTabs, {
|
|
props: { modelValue: 'alpha' },
|
|
slots: { default: '<VTabList><VTab id="alpha"/><VTab id="beta"/></VTabList><VTabPanels><VTabPanel id="alpha"/><VTabPanel id="beta"/></VTabPanels>' },
|
|
global: { components: { VTabList, VTab, VTabPanels, VTabPanel } }
|
|
});
|
|
const context = wrapper.vm.$.provides[TabsProviderKey as any];
|
|
context.selectTab('beta');
|
|
await nextTick();
|
|
expect(wrapper.emitted()['update:modelValue']).toBeTruthy();
|
|
expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['beta']);
|
|
expect(context.activeTabId.value).toBe('beta');
|
|
});
|
|
|
|
it('selects the first tab if no modelValue or initialTab is provided on mount', async () => {
|
|
// This test is more involved as it requires inspecting slot children
|
|
// We need to ensure VTab components are actually rendered within the slots
|
|
const TestComponent = {
|
|
components: { VTabs, VTabList, VTab, VTabPanels, VTabPanel },
|
|
template: `
|
|
<VTabs>
|
|
<VTabList>
|
|
<VTab id="firstMounted" title="First" />
|
|
<VTab id="secondMounted" title="Second" />
|
|
</VTabList>
|
|
<VTabPanels>
|
|
<VTabPanel id="firstMounted">Content First</VTabPanel>
|
|
<VTabPanel id="secondMounted">Content Second</VTabPanel>
|
|
</VTabPanels>
|
|
</VTabs>
|
|
`,
|
|
};
|
|
const wrapper = mount(TestComponent);
|
|
await nextTick(); // Wait for onMounted hook in VTabs
|
|
|
|
// Access VTabs instance to check its internal activeTabId via provided context
|
|
const vTabsInstance = wrapper.findComponent(VTabs);
|
|
const context = vTabsInstance.vm.$.provides[TabsProviderKey as any];
|
|
expect(context.activeTabId.value).toBe('firstMounted');
|
|
});
|
|
|
|
it('does not change activeTabId if modelValue is explicitly null and no initialTab', async () => {
|
|
const TestComponent = {
|
|
components: { VTabs, VTabList, VTab, VTabPanels, VTabPanel },
|
|
template: `
|
|
<VTabs :modelValue="null">
|
|
<VTabList> <VTab id="t1" /> </VTabList>
|
|
<VTabPanels> <VTabPanel id="t1" /> </VTabPanels>
|
|
</VTabs>
|
|
`,
|
|
};
|
|
const wrapper = mount(TestComponent);
|
|
await nextTick();
|
|
const vTabsInstance = wrapper.findComponent(VTabs);
|
|
const context = vTabsInstance.vm.$.provides[TabsProviderKey as any];
|
|
expect(context.activeTabId.value).toBeNull(); // Should remain null, not default to first tab
|
|
});
|
|
|
|
|
|
it('renders its default slot content', () => {
|
|
const wrapper = mount(VTabs, {
|
|
slots: { default: '<div class="test-slot-content">Hello</div>' },
|
|
});
|
|
expect(wrapper.find('.test-slot-content').exists()).toBe(true);
|
|
expect(wrapper.text()).toContain('Hello');
|
|
});
|
|
});
|