This project is a palette creator tool that allows users to generate and customize color palettes for their design projects.
1import { mount } from '@vue/test-utils';
2
3import store from '../store';
4
5import ColorVariationsPanel from './ColorVariationsPanel.vue';
6
7// oxlint-disable-next-line max-lines-per-function
8describe('component ColorVariationsPanel', () => {
9 /** @type {import('@vue/test-utils').VueWrapper} */
10 let wrapper;
11
12 beforeEach(() => {
13 store.state.allColors = [
14 {
15 hex: '#40a0bf',
16 hsl: 'hsl(200, 50%, 50%)',
17 rgb: 'rgb(64, 160, 191)',
18 type: 'complement',
19 },
20 {
21 hex: '#4095bf',
22 hsl: 'hsl(210, 50%, 50%)',
23 rgb: 'rgb(64, 149, 191)',
24 type: 'complement',
25 },
26 {
27 hex: '#408abf',
28 hsl: 'hsl(220, 50%, 50%)',
29 rgb: 'rgb(64, 138, 191)',
30 type: 'mono',
31 },
32 ];
33 store.state.copiedColor = '';
34 store.state.copiedColorIndex = null;
35
36 wrapper = mount(ColorVariationsPanel, {
37 global: { plugins: [store] },
38 });
39 });
40
41 afterEach(() => {
42 wrapper.unmount();
43 vi.restoreAllMocks();
44 });
45
46 it('renders', () => {
47 expect(wrapper.exists()).toBeTruthy();
48 });
49
50 it('shows the expanded panel content', () => {
51 expect(
52 wrapper.find('[data-testid="expanded-panel"]').exists(),
53 ).toBeTruthy();
54 });
55
56 it('renders a slot for each unique color from the store', () => {
57 const slots = wrapper.findAll('.mini-slot');
58
59 expect(slots).toHaveLength(store.getters.uniqueColors.length);
60 });
61
62 it('applies background color to each slot', () => {
63 const slots = wrapper.findAll('.mini-slot');
64
65 for (const slot of slots) {
66 expect(slot.attributes('style')).toContain('background-color');
67 }
68 });
69
70 it('renders the listbox with correct aria attributes', () => {
71 const listbox = wrapper.find('[role="listbox"]');
72
73 expect(listbox.exists()).toBeTruthy();
74 expect(listbox.attributes('aria-label')).toBe('Color variations');
75 });
76
77 it('dispatches COPY_COLOR when a slot is clicked', async () => {
78 const dispatchSpy = vi.spyOn(store, 'dispatch');
79 const firstSlot = wrapper.find('[data-testid="mini-slot-0"]');
80 await firstSlot.trigger('click');
81
82 expect(dispatchSpy).toHaveBeenCalledWith(
83 'COPY_COLOR',
84 expect.objectContaining({
85 color: expect.any(String),
86 index: 0,
87 }),
88 );
89 });
90
91 it('dispatches CLEAR_COPIED_COLOR when an already-selected slot is clicked', async () => {
92 store.state.copiedColor = 'hsl(200, 50%, 50%)';
93 store.state.copiedColorIndex = 0;
94 await wrapper.vm.$nextTick();
95
96 const dispatchSpy = vi.spyOn(store, 'dispatch');
97 await wrapper.find('[data-testid="mini-slot-0"]').trigger('click');
98
99 expect(dispatchSpy).toHaveBeenCalledWith('CLEAR_COPIED_COLOR');
100 });
101
102 it('marks copied slot with mini-slot-copied class', async () => {
103 store.state.copiedColor = 'hsl(200, 50%, 50%)';
104 store.state.copiedColorIndex = 0;
105 await wrapper.vm.$nextTick();
106 const slot1 = wrapper.find('[data-testid="mini-slot-0"]');
107 const slot2 = wrapper.find('[data-testid="mini-slot-1"]');
108
109 expect(slot1.classes()).toContain('mini-slot-copied');
110 expect(slot2.classes()).not.toContain('mini-slot-copied');
111 });
112
113 it('sets aria-selected true on the copied slot', async () => {
114 store.state.copiedColor = 'hsl(200, 50%, 50%)';
115 store.state.copiedColorIndex = 1;
116 await wrapper.vm.$nextTick();
117 const slot1 = wrapper.find('[data-testid="mini-slot-0"]');
118 const slot2 = wrapper.find('[data-testid="mini-slot-1"]');
119
120 expect(slot2.attributes('aria-selected')).toBe('true');
121 expect(slot1.attributes('aria-selected')).toBe('false');
122 });
123});