@mozaic-ds/vue
Version:
Mozaic-Vue is the Vue.js implementation of ADEO Design system
204 lines (169 loc) • 7.13 kB
text/typescript
import { shallowMount, mount } from '@vue/test-utils';
import { describe, it, expect } from 'vitest';
import { nextTick } from 'vue';
import MStarRating from './MStarRating.vue';
import StarFilled24 from '@mozaic-ds/icons-vue/src/components/StarFilled24/StarFilled24.vue';
import StarHalf24 from '@mozaic-ds/icons-vue/src/components/StarHalf24/StarHalf24.vue';
function mockRect(el: Element, { left = 0, width = 100 } = {}) {
Object.defineProperty(el, 'getBoundingClientRect', {
value: () => ({
left,
width,
top: 0,
bottom: 0,
right: left + width,
height: 0,
}),
configurable: true,
});
}
describe('MStarRating', () => {
it('renders 5 stars by default', () => {
const wrapper = shallowMount(MStarRating, { props: { modelValue: 0 } });
const stars = wrapper.findAll('.mc-star-rating__icon');
expect(stars.length).toBe(5);
});
it('renders 1 star when compact mode is enabled', () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 0, compact: true },
});
const stars = wrapper.findAll('.mc-star-rating__icon');
expect(stars.length).toBe(1);
});
it('does not render half star on input mode', async () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 0, readonly: false },
});
const stars = wrapper.findAll('.mc-star-rating__icon');
const first = stars[0];
mockRect(first.element, { left: 0, width: 100 });
await first.trigger('mousemove', { clientX: 10 });
expect(wrapper.findComponent(StarHalf24).exists()).toBe(false);
});
it('render half star on readonly mode if possible', () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 1.5, readonly: true },
});
const filledStars = wrapper.findAllComponents(StarFilled24);
const halfStars = wrapper.findAllComponents(StarHalf24);
expect(filledStars.length).toBe(1);
expect(halfStars.length).toBe(1);
});
it('emits update:modelValue with the correct value when clicking a star', async () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 2, readonly: false },
});
const stars = wrapper.findAll('.mc-star-rating__icon');
const first = stars[0];
mockRect(first.element, { left: 0, width: 100 });
await first.trigger('click', { clientX: 10 });
const emitted = wrapper.emitted('update:modelValue') || [];
expect(emitted.length).toBe(1);
expect(emitted[0][0]).toBe(1);
});
it('emits the correct values when pressing ArrowRight', async () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 2, readonly: false },
});
const ratingInput = wrapper.find('.mc-star-rating__wrapper');
await ratingInput.trigger('keydown', { key: 'ArrowRight' });
const emitted = wrapper.emitted('update:modelValue') || [];
expect(emitted.length).toBe(1);
expect(emitted[0][0]).toBe(3);
});
it('emits the correct values when pressing ArrowLeft', async () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 2, readonly: false },
});
const ratingInput = wrapper.find('.mc-star-rating__wrapper');
await ratingInput.trigger('keydown', { key: 'ArrowLeft' });
const emitted = wrapper.emitted('update:modelValue') || [];
expect(emitted.length).toBe(1);
expect(emitted[0][0]).toBe(1);
});
it('does not do anything if the wrong key is pressed', async () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 2, readonly: false },
});
const ratingInput = wrapper.find('.mc-star-rating__wrapper');
await ratingInput.trigger('keydown', { key: 'ArrowUp' });
const emitted = wrapper.emitted('update:modelValue') || [];
expect(emitted.length).toBe(0);
});
it('resets hover to null on mouseleave (aria-label falls back to modelValue)', async () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 2, size: 'm', readonly: false },
});
const stars = wrapper.findAll('.mc-star-rating__icon');
const first = stars[0];
mockRect(first.element, { left: 0, width: 100 });
await first.trigger('mousemove', { clientX: 10 });
await nextTick();
// aria-label should reflect hovered value (0.5) not modelValue (2)
const root = wrapper.find('[role="slider"]');
expect(root.attributes('aria-label')).toContain('1');
// trigger mouseleave on root, hover should be cleared and aria-label revert to modelValue
await root.trigger('mouseleave');
await nextTick();
expect(root.attributes('aria-label')).toContain('2');
});
it('resets hover to null on blur (aria-label falls back to modelValue)', async () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 3, size: 'm', readonly: false },
});
const stars = wrapper.findAll('.mc-star-rating__icon');
const secondStar = stars[1];
mockRect(secondStar.element, { left: 0, width: 100 });
const root = wrapper.find('[role="slider"]');
await root.trigger('focus');
await secondStar.trigger('mousemove', { clientX: 10 });
await nextTick();
expect(root.attributes('aria-label')).toContain('2');
// blur should clear hover and revert aria-label to modelValue (3)
await root.trigger('blur');
await nextTick();
expect(root.attributes('aria-label')).toContain('3');
});
it('renders information text when text prop is provided', () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 3, text: 'Note publique' },
});
const info = wrapper.find('.mc-star-rating__info');
expect(info.exists()).toBe(true);
expect(info.text()).toBe('Note publique');
});
it('renders href when href prop is provided and text is not', () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 2, href: '/voir' },
});
const info = wrapper.find('.mc-star-rating__info');
expect(info.exists()).toBe(true);
expect(info.text()).toBe('/voir');
});
it('does not render info span when neither text nor href is provided', () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 1 },
});
const info = wrapper.find('.mc-star-rating__info');
expect(info.exists()).toBe(false);
});
it('renders router-link when href and router are provided', () => {
const wrapper = mount(MStarRating, {
props: { modelValue: 3, href: '/path', router: true },
global: { stubs: ['router-link'] },
});
expect(wrapper.element.tagName.toLowerCase()).toBe('router-link-stub');
});
it('renders an anchor when href is provided and router is falsy', () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 2, href: '#', router: false },
});
expect(wrapper.element.tagName.toLowerCase()).toBe('a');
});
it('renders a div when no href is provided', () => {
const wrapper = shallowMount(MStarRating, {
props: { modelValue: 1 },
});
expect(wrapper.element.tagName.toLowerCase()).toBe('div');
});
});