Skip to content

Commit 11a587a

Browse files
committed
refactor(tabs): ✨ convertit DsfrTabs.stories.ts en CSF3
## Pourquoi les changements ont été faits : - Moderniser le fichier stories pour utiliser Storybook CSF3 - Mettre à jour la configuration des stories pour utiliser Meta/StoryObj - Améliorer la structure du code et la maintenabilité ## Quelles modifications ont été apportées : - Conversion des 3 stories (OngletsSimples, OngletsComplexes, OngletsAvecAccordeon) en format CSF3 - Utilisation de setup() avec ref() pour la gestion d'état - Correction des imports (regroupement et formatage) - Types explicites pour les paramètres de rendu et play - DsfrTabs.vue: JSDoc déjà présent dans defineEmits
1 parent 080b6db commit 11a587a

File tree

2 files changed

+164
-161
lines changed

2 files changed

+164
-161
lines changed
Lines changed: 150 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { expect, fn, userEvent, within } from 'storybook/test'
1+
import type { Meta, StoryObj } from '@storybook/vue3'
2+
3+
import { expect, userEvent, within } from 'storybook/test'
4+
import { ref } from 'vue'
25

36
import DsfrAccordion from '../DsfrAccordion/DsfrAccordion.vue'
47
import DsfrAccordionsGroup from '../DsfrAccordion/DsfrAccordionsGroup.vue'
@@ -33,7 +36,6 @@ const meta = {
3336
title: 'Composants/DsfrTabs',
3437
args: {
3538
tabListName,
36-
title1,
3739
tabTitles,
3840
tabContents,
3941
},
@@ -58,71 +60,72 @@ const meta = {
5860
description:
5961
'Index de l’onglet selectionné',
6062
},
61-
'select-tab': {
62-
description:
63-
'Événement émis lorsque l’onglet actif change, avec en argument l’index de l’onglet sélectionné',
64-
},
65-
onSelectTab: {
66-
action: fn(),
67-
},
6863
},
69-
}
64+
} satisfies Meta<typeof DsfrTabs>
65+
7066
export default meta
7167

72-
export const OngletsSimples = (args) => ({
73-
components: { DsfrTabs },
74-
data () {
75-
return args
76-
},
77-
template: `
68+
type Story = StoryObj<typeof meta>
69+
70+
/**
71+
* [Voir quand l'utiliser sur la documentation du DSFR](https://www.systeme-de-design.gouv.fr/version-courante/fr/composants/onglet)
72+
*/
73+
export const OngletsSimples: Story = {
74+
render: (args: typeof meta.args) => ({
75+
components: { DsfrTabs },
76+
77+
setup () {
78+
return args
79+
},
80+
81+
template: `
7882
<DsfrTabs
7983
:tab-list-name="tabListName"
8084
:tab-titles="tabTitles"
8185
:tab-contents="tabContents"
82-
v-model="selectedIndex"
86+
v-model="modelValue"
8387
/>
8488
`,
85-
})
86-
OngletsSimples.args = {
87-
tabListName,
88-
tabTitles,
89-
tabContents,
90-
selectedIndex: 0,
91-
}
92-
OngletsSimples.play = async ({ canvasElement }) => {
93-
const canvas = within(canvasElement)
94-
// const firstTab = await canvas.getByLabelText(tabTitles[0].title)
95-
// await userEvent.click(firstTab)
96-
const tabs = canvas.getAllByRole('tab')
97-
const firstTab = tabs[0]
98-
const secondTab = tabs[1]
99-
const thirdTab = tabs[2]
100-
const fourthTab = tabs[3]
101-
const firstTabPanel = canvas.getByLabelText(tabTitles[0].title)
102-
const secondTabPanel = canvas.getByLabelText(tabTitles[1].title)
103-
const thirdTabPanel = canvas.getByLabelText(tabTitles[2].title)
104-
const fourthTabPanel = canvas.getByLabelText(tabTitles[3].title)
105-
await userEvent.click(secondTab)
106-
await userEvent.type(secondTab, '{arrowright}')
107-
expect(firstTabPanel).not.toHaveClass('fr-tabs__panel--selected')
108-
expect(secondTabPanel).not.toHaveClass('fr-tabs__panel--selected')
109-
expect(thirdTabPanel).toHaveClass('fr-tabs__panel--selected')
110-
expect(thirdTab).toHaveAttribute('aria-selected', 'true')
111-
await userEvent.type(thirdTab, '{arrowright}')
112-
await userEvent.type(fourthTab, '{arrowright}')
113-
expect(thirdTabPanel).not.toHaveClass('fr-tabs__panel--selected')
114-
expect(thirdTab).not.toHaveAttribute('aria-selected', 'true')
115-
expect(firstTabPanel).toHaveClass('fr-tabs__panel--selected')
116-
expect(firstTab).toHaveAttribute('aria-selected', 'true')
117-
await userEvent.type(firstTab, '{arrowup}')
118-
expect(firstTabPanel).not.toHaveClass('fr-tabs__panel--selected')
119-
expect(firstTab).not.toHaveAttribute('aria-selected', 'true')
120-
expect(fourthTabPanel).toHaveClass('fr-tabs__panel--selected')
121-
expect(fourthTab).toHaveAttribute('aria-selected', 'true')
122-
await userEvent.type(fourthTab, '{arrowdown}')
123-
await userEvent.tab()
124-
expect(firstTabPanel).toHaveFocus()
125-
await userEvent.tab()
89+
}),
90+
args: {
91+
tabListName,
92+
tabTitles,
93+
tabContents,
94+
modelValue: 0,
95+
},
96+
play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
97+
const canvas = within(canvasElement)
98+
const tabs = canvas.getAllByRole('tab')
99+
const firstTab = tabs[0]
100+
const secondTab = tabs[1]
101+
const thirdTab = tabs[2]
102+
const fourthTab = tabs[3]
103+
const firstTabPanel = canvas.getByLabelText(tabTitles[0].title)
104+
const secondTabPanel = canvas.getByLabelText(tabTitles[1].title)
105+
const thirdTabPanel = canvas.getByLabelText(tabTitles[2].title)
106+
const fourthTabPanel = canvas.getByLabelText(tabTitles[3].title)
107+
await userEvent.click(secondTab)
108+
await userEvent.type(secondTab, '{arrowright}')
109+
expect(firstTabPanel).not.toHaveClass('fr-tabs__panel--selected')
110+
expect(secondTabPanel).not.toHaveClass('fr-tabs__panel--selected')
111+
expect(thirdTabPanel).toHaveClass('fr-tabs__panel--selected')
112+
expect(thirdTab).toHaveAttribute('aria-selected', 'true')
113+
await userEvent.type(thirdTab, '{arrowright}')
114+
await userEvent.type(fourthTab, '{arrowright}')
115+
expect(thirdTabPanel).not.toHaveClass('fr-tabs__panel--selected')
116+
expect(thirdTab).not.toHaveAttribute('aria-selected', 'true')
117+
expect(firstTabPanel).toHaveClass('fr-tabs__panel--selected')
118+
expect(firstTab).toHaveAttribute('aria-selected', 'true')
119+
await userEvent.type(firstTab, '{arrowup}')
120+
expect(firstTabPanel).not.toHaveClass('fr-tabs__panel--selected')
121+
expect(firstTab).not.toHaveAttribute('aria-selected', 'true')
122+
expect(fourthTabPanel).toHaveClass('fr-tabs__panel--selected')
123+
expect(fourthTab).toHaveAttribute('aria-selected', 'true')
124+
await userEvent.type(fourthTab, '{arrowdown}')
125+
await userEvent.tab()
126+
expect(firstTabPanel).toHaveFocus()
127+
await userEvent.tab()
128+
},
126129
}
127130

128131
const customTabTitles = [
@@ -152,21 +155,19 @@ const customTabTitles = [
152155
},
153156
]
154157

155-
export const OngletsComplexes = (args) => ({
156-
components: { DsfrTabs, DsfrTabContent, DsfrButton },
157-
data () {
158-
return {
159-
...args,
160-
asc: true,
161-
}
162-
},
158+
export const OngletsComplexes: Story = {
159+
render: (args: typeof meta.args) => ({
160+
components: { DsfrTabs, DsfrTabContent, DsfrButton },
163161

164-
template: `
162+
setup () {
163+
return args
164+
},
165+
166+
template: `
165167
<DsfrTabs
166-
ref="tabs"
167168
:tab-list-name="tabListName"
168169
:tab-titles="tabTitles"
169-
v-model="selectedIndex"
170+
v-model="modelValue"
170171
>
171172
<DsfrTabContent
172173
panel-id="tab-content-0"
@@ -199,87 +200,84 @@ export const OngletsComplexes = (args) => ({
199200
<div style="display: flex; gap: 1rem; margin-block: 1rem;">
200201
<DsfrButton
201202
label="Activer le 1er onglet"
202-
@click="selectedIndex = 0"
203+
@click="modelValue = 0"
203204
/>
204205
<DsfrButton
205206
label="Activer le 2è onglet"
206-
@click="selectedIndex = 1"
207+
@click="modelValue = 1"
207208
/>
208209
<DsfrButton
209210
label="Activer le 3è onglet"
210-
@click="selectedIndex = 2"
211+
@click="modelValue = 2"
211212
/>
212213
<DsfrButton
213214
label="Activer le dernier onglet"
214-
@click="selectedIndex = 3"
215+
@click="modelValue = 3"
215216
/>
216217
</div>
217218
`,
218-
219-
watch: {
220-
selectedIndex (idx) {
221-
this.onSelectTab(idx)
222-
},
219+
}),
220+
args: {
221+
tabContents: [],
222+
tabListName,
223+
tabTitles: customTabTitles,
224+
},
225+
play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
226+
const canvas = within(canvasElement)
227+
const buttons = canvas.getAllByRole('button')
228+
const tabs = canvas.getAllByRole('tab')
229+
const firstTab = tabs[0]
230+
const secondTab = tabs[1]
231+
const thirdTab = tabs[2]
232+
const fourthTab = tabs[3]
233+
const firstTabPanel = canvas.getByLabelText(tabTitles[0].title)
234+
const secondTabPanel = canvas.getByLabelText(tabTitles[1].title)
235+
const thirdTabPanel = canvas.getByLabelText(tabTitles[2].title)
236+
const fourthTabPanel = canvas.getByLabelText(tabTitles[3].title)
237+
await userEvent.click(buttons[1] as HTMLButtonElement)
238+
await userEvent.type(secondTab, '{arrowright}')
239+
expect(firstTabPanel).not.toHaveClass('fr-tabs__panel--selected')
240+
expect(secondTabPanel).not.toHaveClass('fr-tabs__panel--selected')
241+
expect(thirdTabPanel).toHaveClass('fr-tabs__panel--selected')
242+
expect(thirdTab).toHaveAttribute('aria-selected', 'true')
243+
await userEvent.type(thirdTab, '{arrowright}')
244+
await userEvent.type(fourthTab, '{arrowright}')
245+
expect(thirdTabPanel).not.toHaveClass('fr-tabs__panel--selected')
246+
expect(thirdTab).not.toHaveAttribute('aria-selected', 'true')
247+
expect(firstTabPanel).toHaveClass('fr-tabs__panel--selected')
248+
expect(firstTab).toHaveAttribute('aria-selected', 'true')
249+
await userEvent.type(firstTab, '{arrowup}')
250+
expect(firstTabPanel).not.toHaveClass('fr-tabs__panel--selected')
251+
expect(firstTab).not.toHaveAttribute('aria-selected', 'true')
252+
expect(fourthTabPanel).toHaveClass('fr-tabs__panel--selected')
253+
expect(fourthTab).toHaveAttribute('aria-selected', 'true')
254+
await userEvent.type(fourthTab, '{arrowdown}')
255+
await userEvent.tab()
256+
expect(firstTabPanel).toHaveFocus()
257+
await userEvent.tab()
258+
await userEvent.click(buttons[2] as HTMLButtonElement)
259+
expect(firstTab).not.toHaveAttribute('aria-selected', 'true')
260+
expect(secondTab).not.toHaveAttribute('aria-selected', 'true')
261+
expect(thirdTab).toHaveAttribute('aria-selected', 'true')
262+
expect(fourthTab).not.toHaveAttribute('aria-selected', 'true')
223263
},
224-
})
225-
OngletsComplexes.args = {
226-
tabContents: [],
227-
tabListName,
228-
tabTitles: customTabTitles,
229-
selectedIndex: 1,
230-
}
231-
OngletsComplexes.play = async ({ canvasElement }) => {
232-
const canvas = within(canvasElement)
233-
// const firstTab = await canvas.getByLabelText(tabTitles[0].title)
234-
// await userEvent.click(firstTab)
235-
const buttons = canvas.getAllByRole('button')
236-
const tabs = canvas.getAllByRole('tab')
237-
const firstTab = tabs[0]
238-
const secondTab = tabs[1]
239-
const thirdTab = tabs[2]
240-
const fourthTab = tabs[3]
241-
const firstTabPanel = canvas.getByLabelText(tabTitles[0].title)
242-
const secondTabPanel = canvas.getByLabelText(tabTitles[1].title)
243-
const thirdTabPanel = canvas.getByLabelText(tabTitles[2].title)
244-
const fourthTabPanel = canvas.getByLabelText(tabTitles[3].title)
245-
await userEvent.click(buttons.at(1) as HTMLButtonElement)
246-
await userEvent.type(secondTab, '{arrowright}')
247-
expect(firstTabPanel).not.toHaveClass('fr-tabs__panel--selected')
248-
expect(secondTabPanel).not.toHaveClass('fr-tabs__panel--selected')
249-
expect(thirdTabPanel).toHaveClass('fr-tabs__panel--selected')
250-
expect(thirdTab).toHaveAttribute('aria-selected', 'true')
251-
await userEvent.type(thirdTab, '{arrowright}')
252-
await userEvent.type(fourthTab, '{arrowright}')
253-
expect(thirdTabPanel).not.toHaveClass('fr-tabs__panel--selected')
254-
expect(thirdTab).not.toHaveAttribute('aria-selected', 'true')
255-
expect(firstTabPanel).toHaveClass('fr-tabs__panel--selected')
256-
expect(firstTab).toHaveAttribute('aria-selected', 'true')
257-
await userEvent.type(firstTab, '{arrowup}')
258-
expect(firstTabPanel).not.toHaveClass('fr-tabs__panel--selected')
259-
expect(firstTab).not.toHaveAttribute('aria-selected', 'true')
260-
expect(fourthTabPanel).toHaveClass('fr-tabs__panel--selected')
261-
expect(fourthTab).toHaveAttribute('aria-selected', 'true')
262-
await userEvent.type(fourthTab, '{arrowdown}')
263-
await userEvent.tab()
264-
expect(firstTabPanel).toHaveFocus()
265-
await userEvent.tab()
266-
await userEvent.click(buttons.at(2) as HTMLButtonElement)
267-
expect(firstTab).not.toHaveAttribute('aria-selected', 'true')
268-
expect(secondTab).not.toHaveAttribute('aria-selected', 'true')
269-
expect(thirdTab).toHaveAttribute('aria-selected', 'true')
270-
expect(fourthTab).not.toHaveAttribute('aria-selected', 'true')
271264
}
272265

273-
export const OngletsAvecAccordeon = (args) => ({
274-
components: { DsfrTabs, DsfrTabContent, DsfrAccordionsGroup, DsfrAccordion },
275-
data () {
276-
return {
277-
...args,
278-
asc: true,
279-
}
280-
},
266+
export const OngletsAvecAccordeon: Story = {
267+
render: (args: typeof meta.args) => ({
268+
components: { DsfrTabs, DsfrTabContent, DsfrAccordionsGroup, DsfrAccordion },
269+
270+
setup () {
271+
const selectedTabIndex = ref(0)
272+
const selectedAccordion = ref()
273+
return {
274+
...args,
275+
selectedTabIndex,
276+
selectedAccordion,
277+
}
278+
},
281279

282-
template: `
280+
template: `
283281
<DsfrTabs
284282
:tab-list-name="tabListName"
285283
:tab-titles="tabTitles"
@@ -319,32 +317,23 @@ export const OngletsAvecAccordeon = (args) => ({
319317
</DsfrTabContent>
320318
</DsfrTabs>
321319
`,
322-
323-
methods: {
324-
selectTab (idx) {
325-
this.onSelectTab(idx)
326-
this.asc = this.selectedTabIndex < idx
327-
this.selectedTabIndex = idx
328-
},
320+
}),
321+
args: {
322+
tabContents: [],
323+
tabListName,
324+
tabTitles: customTabTitles.slice(0, 2),
325+
title1: 'Un titre d’accordéon 1',
326+
title2: 'Un titre d’accordéon 2',
327+
title3: 'Un titre d’accordéon 3',
328+
},
329+
play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
330+
const canvas = within(canvasElement)
331+
const thirdAccordionTitle = canvas.getByText('Un titre d\'accordéon 3')
332+
const thirdAccordion = canvas.getByText('Contenu de l\'accordéon 3')
333+
expect(thirdAccordionTitle).toBeVisible()
334+
expect(thirdAccordion).not.toBeVisible()
335+
await userEvent.click(thirdAccordionTitle)
336+
await delay(500)
337+
expect(thirdAccordion).toBeVisible()
329338
},
330-
})
331-
OngletsAvecAccordeon.args = {
332-
tabContents: [],
333-
tabListName,
334-
tabTitles: customTabTitles.slice(0, 2),
335-
selectedTabIndex: 0,
336-
title1: 'Un titre d’accordéon 1',
337-
title2: 'Un titre d’accordéon 2',
338-
title3: 'Un titre d’accordéon 3',
339-
selectedAccordion: undefined,
340-
}
341-
OngletsAvecAccordeon.play = async ({ canvasElement }) => {
342-
const canvas = within(canvasElement)
343-
const thirdAccordionTitle = canvas.getByText(OngletsAvecAccordeon.args.title3)
344-
const thirdAccordion = canvas.getByText('Contenu de l’accordéon 3')
345-
expect(thirdAccordionTitle).toBeVisible()
346-
expect(thirdAccordion).not.toBeVisible()
347-
userEvent.click(thirdAccordionTitle)
348-
await delay(500)
349-
expect(thirdAccordion).toBeVisible()
350339
}

0 commit comments

Comments
 (0)