mitlist/fe/src/components/valerie/VAlert.spec.ts

128 lines
5.1 KiB
TypeScript

import { mount } from '@vue/test-utils';
import VAlert from './VAlert.vue';
import VIcon from './VIcon.vue'; // VAlert uses VIcon
import { nextTick } from 'vue';
// Mock VIcon
vi.mock('./VIcon.vue', () => ({
name: 'VIcon',
props: ['name'],
template: '<i :class="`mock-icon icon-${name}`"></i>',
}));
describe('VAlert.vue', () => {
it('renders message prop when no default slot', () => {
const messageText = 'This is a test alert.';
const wrapper = mount(VAlert, { props: { message: messageText } });
expect(wrapper.find('.alert-content').text()).toBe(messageText);
});
it('renders default slot content instead of message prop', () => {
const slotContent = '<strong>Custom Alert Content</strong>';
const wrapper = mount(VAlert, {
props: { message: 'Ignored message' },
slots: { default: slotContent },
});
expect(wrapper.find('.alert-content').html()).toContain(slotContent);
});
it('applies correct class based on type prop', () => {
const wrapperInfo = mount(VAlert, { props: { type: 'info' } });
expect(wrapperInfo.classes()).toContain('alert-info');
const wrapperSuccess = mount(VAlert, { props: { type: 'success' } });
expect(wrapperSuccess.classes()).toContain('alert-success');
const wrapperWarning = mount(VAlert, { props: { type: 'warning' } });
expect(wrapperWarning.classes()).toContain('alert-warning');
const wrapperError = mount(VAlert, { props: { type: 'error' } });
expect(wrapperError.classes()).toContain('alert-error');
});
it('shows close button and emits events when closable is true', async () => {
const wrapper = mount(VAlert, { props: { closable: true, modelValue: true } });
const closeButton = wrapper.find('.alert-close-btn');
expect(closeButton.exists()).toBe(true);
await closeButton.trigger('click');
expect(wrapper.emitted()['update:modelValue']).toBeTruthy();
expect(wrapper.emitted()['update:modelValue'][0]).toEqual([false]);
expect(wrapper.emitted()['close']).toBeTruthy();
// Check if alert is hidden after internalModelValue updates (due to transition)
await nextTick(); // Allow internalModelValue to update and transition to start
// Depending on how transition is handled, the element might still be in DOM but display:none
// or completely removed. VAlert uses v-if, so it should be removed.
// Forcing internalModelValue directly for test simplicity if needed, or wait for transition.
// wrapper.vm.internalModelValue = false; // If directly manipulating for test
// await nextTick();
expect(wrapper.find('.alert').exists()).toBe(false); // After click and model update, it should be gone
});
it('does not show close button when closable is false (default)', () => {
const wrapper = mount(VAlert);
expect(wrapper.find('.alert-close-btn').exists()).toBe(false);
});
it('displays icon by default and uses type-specific default icons', () => {
const wrapperSuccess = mount(VAlert, { props: { type: 'success' } });
expect(wrapperSuccess.find('.alert-icon').exists()).toBe(true);
expect(wrapperSuccess.find('.icon-check-circle').exists()).toBe(true); // Mocked VIcon class
const wrapperError = mount(VAlert, { props: { type: 'error' } });
expect(wrapperError.find('.icon-alert-octagon').exists()).toBe(true);
});
it('displays custom icon when icon prop is provided', () => {
const customIconName = 'custom-bell';
const wrapper = mount(VAlert, { props: { icon: customIconName } });
expect(wrapper.find('.alert-icon').exists()).toBe(true);
expect(wrapper.find(`.icon-${customIconName}`).exists()).toBe(true);
});
it('does not display icon when showIcon is false', () => {
const wrapper = mount(VAlert, { props: { showIcon: false } });
expect(wrapper.find('.alert-icon').exists()).toBe(false);
});
it('renders actions slot content', () => {
const actionsContent = '<button>Retry</button>';
const wrapper = mount(VAlert, {
slots: { actions: actionsContent },
});
const actionsDiv = wrapper.find('.alert-actions');
expect(actionsDiv.exists()).toBe(true);
expect(actionsDiv.html()).toContain(actionsContent);
});
it('does not render .alert-actions if slot is not provided', () => {
const wrapper = mount(VAlert);
expect(wrapper.find('.alert-actions').exists()).toBe(false);
});
it('is visible by default (modelValue true)', () => {
const wrapper = mount(VAlert);
expect(wrapper.find('.alert').exists()).toBe(true);
});
it('is hidden when modelValue is initially false', () => {
const wrapper = mount(VAlert, { props: { modelValue: false } });
expect(wrapper.find('.alert').exists()).toBe(false);
});
it('updates visibility when modelValue prop changes', async () => {
const wrapper = mount(VAlert, { props: { modelValue: true } });
expect(wrapper.find('.alert').exists()).toBe(true);
await wrapper.setProps({ modelValue: false });
// Wait for transition if any, or internalModelValue update
await nextTick();
expect(wrapper.find('.alert').exists()).toBe(false);
await wrapper.setProps({ modelValue: true });
await nextTick();
expect(wrapper.find('.alert').exists()).toBe(true);
});
});