From fdfbd81480eda7826a54219d230cf7e9b1504904 Mon Sep 17 00:00:00 2001 From: tristan Date: Wed, 27 May 2026 10:05:24 +0200 Subject: [PATCH] feat : composant TimeWheel colonne molette infinie (MUI-39) Co-Authored-By: Claude Sonnet 4.6 --- .../malio/time/internal/TimeWheel.test.ts | 41 ++++++++++ .../malio/time/internal/TimeWheel.vue | 82 +++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 app/components/malio/time/internal/TimeWheel.test.ts create mode 100644 app/components/malio/time/internal/TimeWheel.vue diff --git a/app/components/malio/time/internal/TimeWheel.test.ts b/app/components/malio/time/internal/TimeWheel.test.ts new file mode 100644 index 0000000..2c7b183 --- /dev/null +++ b/app/components/malio/time/internal/TimeWheel.test.ts @@ -0,0 +1,41 @@ +import {describe, expect, it} from 'vitest' +import {mount} from '@vue/test-utils' +import TimeWheel from './TimeWheel.vue' + +const HOURS = Array.from({length: 24}, (_, i) => i) + +const mountWheel = (modelValue = 9) => + mount(TimeWheel, { + props: {modelValue, values: HOURS, ariaLabel: 'Heures'}, + attachTo: document.body, + }) + +describe('MalioTimeWheel', () => { + it('expose le rôle spinbutton et les attributs aria', () => { + const wrapper = mountWheel(9) + const el = wrapper.get('[role="spinbutton"]') + expect(el.attributes('aria-label')).toBe('Heures') + expect(el.attributes('aria-valuenow')).toBe('9') + expect(el.attributes('aria-valuemin')).toBe('0') + expect(el.attributes('aria-valuemax')).toBe('23') + expect(el.attributes('aria-valuetext')).toBe('09') + }) + + it('rend 3 copies des valeurs (buffer infini)', () => { + const wrapper = mountWheel() + expect(wrapper.findAll('[data-test="wheel-item"]')).toHaveLength(24 * 3) + }) + + it('émet la nouvelle valeur au clavier ArrowDown', async () => { + const wrapper = mountWheel(9) + await wrapper.get('[role="spinbutton"]').trigger('keydown', {key: 'ArrowDown'}) + expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual([10]) + }) + + it('émet la valeur cliquée', async () => { + const wrapper = mountWheel(9) + const item = wrapper.findAll('[data-test="wheel-item"]').find((w) => w.text() === '11')! + await item.trigger('click') + expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual([11]) + }) +}) diff --git a/app/components/malio/time/internal/TimeWheel.vue b/app/components/malio/time/internal/TimeWheel.vue new file mode 100644 index 0000000..5505dff --- /dev/null +++ b/app/components/malio/time/internal/TimeWheel.vue @@ -0,0 +1,82 @@ + + + + +