1
1
import { breakpoints } from '@guardian/source/foundations' ;
2
2
import type { Meta , StoryObj } from '@storybook/react' ;
3
+ import { expect , userEvent , within } from '@storybook/test' ;
3
4
import { centreColumnDecorator } from '../../.storybook/decorators/gridDecorators' ;
4
5
import { LoopVideo } from './LoopVideo.importable' ;
5
6
6
- export default {
7
+ const meta = {
7
8
component : LoopVideo ,
8
9
title : 'Components/LoopVideo' ,
9
10
decorators : [ centreColumnDecorator ] ,
@@ -15,7 +16,10 @@ export default {
15
16
} ,
16
17
} satisfies Meta < typeof LoopVideo > ;
17
18
18
- export const Default = {
19
+ export default meta ;
20
+ type Story = StoryObj < typeof LoopVideo > ;
21
+
22
+ export const Default : Story = {
19
23
name : 'Default' ,
20
24
args : {
21
25
src : 'https://uploads.guim.co.uk/2025%2F06%2F20%2Ftesting+only%2C+please+ignore--3cb22b60-2c3f-48d6-8bce-38c956907cce-3.mp4' ,
@@ -26,14 +30,78 @@ export const Default = {
26
30
image : 'https://media.guim.co.uk/9bdb802e6da5d3fd249b5060f367b3a817965f0c/0_0_1800_1080/master/1800.jpg' ,
27
31
fallbackImage : '' ,
28
32
} ,
29
- } satisfies StoryObj < typeof LoopVideo > ;
33
+ } ;
30
34
31
- export const Without5to4Ratio = {
35
+ export const Without5to4Ratio : Story = {
32
36
name : 'Without 5:4 aspect ratio' ,
33
37
args : {
34
38
...Default . args ,
35
39
src : 'https://uploads.guim.co.uk/2024/10/01/241001HeleneLoop_2.mp4' ,
36
40
height : 1080 ,
37
41
width : 1920 ,
38
42
} ,
39
- } satisfies StoryObj < typeof LoopVideo > ;
43
+ } ;
44
+
45
+ export const PausePlay : Story = {
46
+ ...Default ,
47
+ play : async ( { canvasElement } ) => {
48
+ const canvas = within ( canvasElement ) ;
49
+ const videoEl = canvas . getByTestId ( 'loop-video' ) ;
50
+
51
+ await userEvent . click ( videoEl , {
52
+ delay : 300 , // Allow video to start playing.
53
+ } ) ;
54
+ await canvas . findByTestId ( 'play-icon' ) ;
55
+
56
+ const progressBar = await canvas . findByRole ( 'progressbar' ) ;
57
+ await expect ( Number ( progressBar . ariaValueNow ) ) . toBeGreaterThan ( 0 ) ;
58
+
59
+ // Play Video
60
+ await userEvent . click ( videoEl ) ;
61
+ await expect ( canvas . queryByTestId ( 'play-icon' ) ) . not . toBeInTheDocument ( ) ;
62
+ } ,
63
+ } ;
64
+
65
+ export const UnmuteMute : Story = {
66
+ ...Default ,
67
+ play : async ( { canvasElement } ) => {
68
+ const canvas = within ( canvasElement ) ;
69
+
70
+ await canvas . findByTestId ( 'unmute-icon' ) ;
71
+
72
+ await userEvent . click ( canvas . getByTestId ( 'unmute-icon' ) ) ;
73
+ await canvas . findByTestId ( 'mute-icon' ) ;
74
+
75
+ await userEvent . click ( canvas . getByTestId ( 'mute-icon' ) ) ;
76
+ await canvas . findByTestId ( 'unmute-icon' ) ;
77
+ } ,
78
+ } ;
79
+
80
+ // Function to emulate pausing between interactions
81
+ function sleep ( ms : number ) {
82
+ return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
83
+ }
84
+
85
+ export const InteractionObserver : Story = {
86
+ ...Default ,
87
+ render : ( args ) => (
88
+ < div data-testid = "test-container" >
89
+ < LoopVideo { ...args } />
90
+ < div style = { { height : '500px' } } > </ div >
91
+ < p data-testid = "page-end" > End of page</ p >
92
+ </ div >
93
+ ) ,
94
+ play : async ( { canvasElement } ) => {
95
+ const canvas = within ( canvasElement ) ;
96
+
97
+ await sleep ( 300 ) ;
98
+ canvas . getByTestId ( 'page-end' ) . scrollIntoView ( ) ;
99
+
100
+ const progressBar = await canvas . findByRole ( 'progressbar' ) ;
101
+ const progress = Number ( progressBar . ariaValueNow ) ;
102
+
103
+ await sleep ( 300 ) ;
104
+ await expect ( Number ( progressBar . ariaValueNow ) ) . toEqual ( progress ) ;
105
+ await expect ( canvas . queryByTestId ( 'play-icon' ) ) . not . toBeInTheDocument ( ) ;
106
+ } ,
107
+ } ;
0 commit comments