This project is a palette creator tool that allows users to generate and customize color palettes for their design projects.
at main 420 lines 13 kB view raw
1// oxlint-disable max-lines 2 3import { mount } from '@vue/test-utils'; 4 5import { DEFAULT_HEX_COLORS } from '../lib/colors'; 6import stateFactory from '../store/state'; 7import store from '../store'; 8 9import UtilityButtonsPanel from './UtilityButtonsPanel.vue'; 10 11// oxlint-disable-next-line max-lines-per-function 12describe('component UtilityButtonsPanel', () => { 13 /** @type {import('@vue/test-utils').VueWrapper} */ 14 let wrapper; 15 16 beforeEach(() => { 17 Object.assign(store.state, stateFactory()); 18 store.state.mainHSL = 'hsl(20, 20%, 20%)'; 19 store.state.allColors = [ 20 { 21 hex: '#40BFBF', 22 hsl: 'hsl(180, 50%, 50%)', 23 rgb: 'rgb(64,191,191)', 24 type: 'analogous', 25 }, 26 { 27 hex: '#4080BF', 28 hsl: 'hsl(200, 50%, 50%)', 29 rgb: 'rgb(64,128,191)', 30 type: 'complement', 31 }, 32 { 33 hex: '#B3C4D6', 34 hsl: 'hsl(220, 50%, 85%)', 35 rgb: 'rgb(179,196,214)', 36 type: 'triad', 37 }, 38 { 39 hex: '#13133D', 40 hsl: 'hsl(240, 50%, 15%)', 41 rgb: 'rgb(19,19,61)', 42 type: 'mono', 43 }, 44 { 45 hex: '#8040BF', 46 hsl: 'hsl(260, 50%, 50%)', 47 rgb: 'rgb(128,64,191)', 48 type: 'saturation', 49 }, 50 ]; 51 52 wrapper = mount(UtilityButtonsPanel, { 53 global: { plugins: [store] }, 54 }); 55 }); 56 57 afterEach(() => { 58 wrapper.unmount(); 59 vi.restoreAllMocks(); 60 }); 61 62 it('renders the component', () => { 63 expect( 64 wrapper.find('[data-testid="utility-buttons"]').exists(), 65 ).toBeTruthy(); 66 expect( 67 wrapper.find('[data-testid="random-scheme-button"]').exists(), 68 ).toBeTruthy(); 69 expect( 70 wrapper.find('[data-testid="one-shot-button"]').exists(), 71 ).toBeTruthy(); 72 }); 73 74 it('calls SET_RANDOM_SCHEME when random button is clicked', async () => { 75 const spy = vi.spyOn(store, 'dispatch').mockResolvedValue(null); 76 77 await wrapper 78 .find('[data-testid="random-scheme-button"]') 79 .trigger('click'); 80 81 expect(spy).toHaveBeenCalledWith('SET_RANDOM_SCHEME'); 82 }); 83 84 it('fills the slots with random colors', async () => { 85 await wrapper 86 .find('[data-testid="random-scheme-button"]') 87 .trigger('click'); 88 await wrapper.vm.$nextTick(); 89 90 const { slotColors, mainHSL } = store.state; 91 const slots = ['slot2', 'slot3', 'slot4', 'slot5']; 92 93 for (const slotId of slots) { 94 const color = slotColors[slotId]; 95 96 expect(color.hsl).toContain('hsl'); 97 expect(color.rgb).toContain('rgb'); 98 expect(color.hex).toContain('#'); 99 100 // Check uniqueness against main color 101 expect(color.hsl).not.toBe(mainHSL); 102 103 // Check uniqueness against other slots 104 const otherSlots = slots.filter((s) => s !== slotId); 105 for (const otherId of otherSlots) { 106 expect(color.hsl).not.toBe(slotColors[otherId].hsl); 107 } 108 } 109 }); 110 111 it('show the one-shot button always, even when the full scheme is not set', () => { 112 store.state.allColors = []; 113 expect( 114 wrapper.find('[data-testid="one-shot-button"]').exists(), 115 ).toBeTruthy(); 116 }); 117 118 it('shows all buttons when the full scheme is set', async () => { 119 const buttons = [ 120 'test-palette-button', 121 'reset-site-colors-button', 122 'set-light-text-button', 123 'set-dark-text-button', 124 'export-css-button', 125 'save-palette-button', 126 ]; 127 128 for (const button of buttons) { 129 expect( 130 wrapper.find(`[data-testid="${button}"]`).exists(), 131 ).toBeFalsy(); 132 } 133 134 await wrapper 135 .find('[data-testid="random-scheme-button"]') 136 .trigger('click'); 137 await wrapper.vm.$nextTick(); 138 139 for (const button of buttons) { 140 expect( 141 wrapper.find(`[data-testid="${button}"]`).exists(), 142 ).toBeTruthy(); 143 } 144 }); 145 146 it('sets the theme colors when the test palette button is clicked', async () => { 147 await wrapper 148 .find('[data-testid="random-scheme-button"]') 149 .trigger('click'); 150 151 await wrapper.vm.$nextTick(); 152 153 const { mainSlotColor, slotColors } = store.state; 154 155 await wrapper 156 .find('[data-testid="test-palette-button"]') 157 .trigger('click'); 158 159 const expectedColors = { 160 '--clr-accent': slotColors.slot3.hex, 161 '--clr-dark': slotColors.slot5.hex, 162 '--clr-light': slotColors.slot4.hex, 163 '--clr-main': mainSlotColor.hex, 164 '--clr-secondary': slotColors.slot2.hex, 165 }; 166 167 for (const [variable, expectedHex] of Object.entries(expectedColors)) { 168 const actualHex = getComputedStyle( 169 document.documentElement, 170 ).getPropertyValue(variable); 171 expect(actualHex).toBe(expectedHex); 172 } 173 }); 174 175 it('resets the site colors when the reset button is clicked', async () => { 176 await wrapper 177 .find('[data-testid="random-scheme-button"]') 178 .trigger('click'); 179 180 await wrapper.vm.$nextTick(); 181 182 await wrapper 183 .find('[data-testid="test-palette-button"]') 184 .trigger('click'); 185 186 await wrapper.vm.$nextTick(); 187 188 const mainColor = getComputedStyle( 189 document.documentElement, 190 ).getPropertyValue('--clr-main'); 191 192 expect(mainColor).not.toBe(DEFAULT_HEX_COLORS.MAIN); 193 194 await wrapper 195 .find('[data-testid="reset-site-colors-button"]') 196 .trigger('click'); 197 198 const variables = [ 199 '--clr-main', 200 '--clr-secondary', 201 '--clr-accent', 202 '--clr-light', 203 '--clr-dark', 204 ]; 205 206 for (const variable of variables) { 207 expect( 208 document.documentElement.style.getPropertyValue(variable), 209 ).toBe(''); 210 } 211 }); 212 213 it('sets the text color to the default light color when the light button is clicked', async () => { 214 await wrapper 215 .find('[data-testid="random-scheme-button"]') 216 .trigger('click'); 217 218 await wrapper.vm.$nextTick(); 219 220 await wrapper 221 .find('[data-testid="set-light-text-button"]') 222 .trigger('click'); 223 224 await wrapper.vm.$nextTick(); 225 226 const textColor = getComputedStyle( 227 document.documentElement, 228 ).getPropertyValue('--text-color'); 229 230 expect(textColor).toBe(DEFAULT_HEX_COLORS.LIGHT); 231 expect(store.state.textColor.hex).toBe(DEFAULT_HEX_COLORS.LIGHT); 232 }); 233 234 it('sets the text color to the default dark color when the dark button is clicked', async () => { 235 await wrapper 236 .find('[data-testid="random-scheme-button"]') 237 .trigger('click'); 238 239 await wrapper.vm.$nextTick(); 240 241 await wrapper 242 .find('[data-testid="set-dark-text-button"]') 243 .trigger('click'); 244 245 await wrapper.vm.$nextTick(); 246 247 const textColor = getComputedStyle( 248 document.documentElement, 249 ).getPropertyValue('--text-color'); 250 251 expect(textColor).toBe(DEFAULT_HEX_COLORS.DARK); 252 expect(store.state.textColor.hex).toBe(DEFAULT_HEX_COLORS.DARK); 253 }); 254 255 it('sends copyPalette event when the export css button is clicked', async () => { 256 await wrapper 257 .find('[data-testid="random-scheme-button"]') 258 .trigger('click'); 259 260 await wrapper.vm.$nextTick(); 261 262 await wrapper 263 .find('[data-testid="export-css-button"]') 264 .trigger('click'); 265 266 expect(wrapper.emitted('copyPalette')).toBeTruthy(); 267 }); 268 269 it('sends savePalette event when the save palette button is clicked', async () => { 270 await wrapper 271 .find('[data-testid="random-scheme-button"]') 272 .trigger('click'); 273 274 await wrapper.vm.$nextTick(); 275 276 await wrapper 277 .find('[data-testid="save-palette-button"]') 278 .trigger('click'); 279 280 expect(wrapper.emitted('savePalette')).toBeTruthy(); 281 }); 282 283 it('one-shot button dispatches SET_MAIN_COLOR and SET_RANDOM_SCHEME', async () => { 284 const spy = vi.spyOn(store, 'dispatch').mockResolvedValue(null); 285 286 await wrapper.find('[data-testid="one-shot-button"]').trigger('click'); 287 288 expect(spy).toHaveBeenCalledWith('SET_MAIN_COLOR'); 289 expect(spy).toHaveBeenCalledWith('SET_RANDOM_SCHEME'); 290 }); 291 292 it('one-shot button sets a full random palette and applies CSS vars', async () => { 293 await wrapper.find('[data-testid="one-shot-button"]').trigger('click'); 294 295 await wrapper.vm.$nextTick(); 296 297 const { slotColors, mainSlotColor } = store.state; 298 299 expect(mainSlotColor.hex).not.toBe(''); 300 301 const slots = ['slot2', 'slot3', 'slot4', 'slot5']; 302 for (const slotId of slots) { 303 expect(slotColors[slotId].hsl).not.toBe(''); 304 } 305 306 const expectedColors = { 307 '--clr-accent': slotColors.slot3.hex, 308 '--clr-dark': slotColors.slot5.hex, 309 '--clr-light': slotColors.slot4.hex, 310 '--clr-main': mainSlotColor.hex, 311 '--clr-secondary': slotColors.slot2.hex, 312 }; 313 314 for (const [variable, expectedHex] of Object.entries(expectedColors)) { 315 expect( 316 document.documentElement.style.getPropertyValue(variable), 317 ).toBe(expectedHex); 318 } 319 }); 320 321 it('one-shot button sets isTestingColorScheme to true', async () => { 322 await wrapper.find('[data-testid="one-shot-button"]').trigger('click'); 323 324 await wrapper.vm.$nextTick(); 325 326 expect(store.state.isTestingColorScheme).toBeTruthy(); 327 }); 328 329 it('Test this palette applies text color from palette (dark theme uses slot4)', async () => { 330 await wrapper 331 .find('[data-testid="random-scheme-button"]') 332 .trigger('click'); 333 await wrapper.vm.$nextTick(); 334 335 // default theme is dark → text should use slot4 336 const { slot4 } = store.state.slotColors; 337 338 await wrapper 339 .find('[data-testid="test-palette-button"]') 340 .trigger('click'); 341 await wrapper.vm.$nextTick(); 342 343 expect(store.state.textColor.hex).toBe(slot4.hex); 344 expect( 345 document.documentElement.style.getPropertyValue('--text-color'), 346 ).toBe(slot4.hex); 347 }); 348 349 it('Light Text uses slot4 color when testing', async () => { 350 await wrapper 351 .find('[data-testid="random-scheme-button"]') 352 .trigger('click'); 353 await wrapper.vm.$nextTick(); 354 355 store.commit('SET_IS_TESTING', true); 356 357 const { slot4 } = store.state.slotColors; 358 359 await wrapper 360 .find('[data-testid="set-light-text-button"]') 361 .trigger('click'); 362 await wrapper.vm.$nextTick(); 363 364 expect(store.state.textColor.hex).toBe(slot4.hex); 365 }); 366 367 it('Dark Text uses slot5 color when testing', async () => { 368 await wrapper 369 .find('[data-testid="random-scheme-button"]') 370 .trigger('click'); 371 await wrapper.vm.$nextTick(); 372 373 store.commit('SET_IS_TESTING', true); 374 375 const { slot5 } = store.state.slotColors; 376 377 await wrapper 378 .find('[data-testid="set-dark-text-button"]') 379 .trigger('click'); 380 await wrapper.vm.$nextTick(); 381 382 expect(store.state.textColor.hex).toBe(slot5.hex); 383 }); 384 385 it('Light Text uses theme default when not testing', async () => { 386 await wrapper 387 .find('[data-testid="random-scheme-button"]') 388 .trigger('click'); 389 await wrapper.vm.$nextTick(); 390 391 store.commit('SET_IS_TESTING', false); 392 393 await wrapper 394 .find('[data-testid="set-light-text-button"]') 395 .trigger('click'); 396 await wrapper.vm.$nextTick(); 397 398 expect(store.state.textColor.hex).toBe(DEFAULT_HEX_COLORS.LIGHT); 399 }); 400 401 // oxlint-disable-next-line max-statements 402 it('Reset restores text color to theme default', async () => { 403 await wrapper 404 .find('[data-testid="random-scheme-button"]') 405 .trigger('click'); 406 await wrapper.vm.$nextTick(); 407 408 store.commit('SET_IS_TESTING', true); 409 await store.dispatch('SET_TEXT_COLOR', 'dark'); 410 411 await wrapper 412 .find('[data-testid="reset-site-colors-button"]') 413 .trigger('click'); 414 await wrapper.vm.$nextTick(); 415 416 expect(store.state.isTestingColorScheme).toBeFalsy(); 417 // default theme is dark → textType becomes 'light' 418 expect(store.state.textColor.hex).toBe(DEFAULT_HEX_COLORS.LIGHT); 419 }); 420});