|
1 | | -import { breakpoints } from '@guardian/source/foundations'; |
2 | | -import type { Meta, StoryObj } from '@storybook/react-webpack5'; |
3 | | -import { expect, userEvent, within } from 'storybook/test'; |
4 | | -import { centreColumnDecorator } from '../../.storybook/decorators/gridDecorators'; |
5 | | -import { LoopVideo } from './LoopVideo.importable'; |
6 | | - |
7 | | -const meta = { |
8 | | - component: LoopVideo, |
9 | | - title: 'Components/LoopVideo', |
10 | | - decorators: [centreColumnDecorator], |
11 | | - render: (args) => <LoopVideo {...args} />, |
12 | | - parameters: { |
13 | | - chromatic: { |
14 | | - viewports: [breakpoints.mobile, breakpoints.wide], |
15 | | - }, |
16 | | - }, |
17 | | -} satisfies Meta<typeof LoopVideo>; |
18 | | - |
19 | | -export default meta; |
20 | | -type Story = StoryObj<typeof LoopVideo>; |
21 | | - |
22 | | -export const Default: Story = { |
23 | | - name: 'Default', |
24 | | - args: { |
25 | | - sources: [ |
26 | | - { |
27 | | - src: 'https://uploads.guim.co.uk/2025%2F06%2F20%2Ftesting+only%2C+please+ignore--3cb22b60-2c3f-48d6-8bce-38c956907cce-3.mp4', |
28 | | - mimeType: 'video/mp4', |
29 | | - }, |
30 | | - ], |
31 | | - uniqueId: 'test-video-1', |
32 | | - atomId: 'test-atom-1', |
33 | | - height: 720, |
34 | | - width: 900, |
35 | | - posterImage: |
36 | | - 'https://media.guim.co.uk/9bdb802e6da5d3fd249b5060f367b3a817965f0c/0_0_1800_1080/master/1800.jpg', |
37 | | - fallbackImage: '', |
38 | | - }, |
39 | | -}; |
40 | | - |
41 | | -export const WithM3U8File: Story = { |
42 | | - name: 'With M3U8 file', |
43 | | - args: { |
44 | | - ...Default.args, |
45 | | - sources: [ |
46 | | - { |
47 | | - src: 'https://uploads.guimcode.co.uk/2025/09/01/Loop__Japan_fireball--ace3fcf6-1378-41db-9d21-f3fc07072ab2-1.10.m3u8', |
48 | | - mimeType: 'application/x-mpegURL', |
49 | | - }, |
50 | | - { |
51 | | - src: 'https://uploads.guim.co.uk/2025%2F06%2F20%2Ftesting+only%2C+please+ignore--3cb22b60-2c3f-48d6-8bce-38c956907cce-3.mp4', |
52 | | - mimeType: 'video/mp4', |
53 | | - }, |
54 | | - ], |
55 | | - }, |
56 | | -}; |
57 | | - |
58 | | -export const Without5to4Ratio: Story = { |
59 | | - name: 'Without 5:4 aspect ratio', |
60 | | - args: { |
61 | | - ...Default.args, |
62 | | - sources: [ |
63 | | - { |
64 | | - src: 'https://uploads.guim.co.uk/2024/10/01/241001HeleneLoop_2.mp4', |
65 | | - mimeType: 'video/mp4', |
66 | | - }, |
67 | | - ], |
68 | | - height: 1080, |
69 | | - width: 1920, |
70 | | - }, |
71 | | -}; |
72 | | - |
73 | | -export const PausePlay: Story = { |
74 | | - ...Default, |
75 | | - name: 'Pause and play interaction', |
76 | | - play: async ({ canvasElement }) => { |
77 | | - const canvas = within(canvasElement); |
78 | | - const videoEl = canvas.getByTestId('loop-video'); |
79 | | - |
80 | | - await userEvent.click(videoEl, { |
81 | | - delay: 300, // Allow video to start playing. |
82 | | - }); |
83 | | - await canvas.findByTestId('play-icon'); |
84 | | - |
85 | | - const progressBar = await canvas.findByRole('progressbar'); |
86 | | - await expect(Number(progressBar.ariaValueNow)).toBeGreaterThan(0); |
87 | | - |
88 | | - // Play Video |
89 | | - await userEvent.click(videoEl); |
90 | | - await expect(canvas.queryByTestId('play-icon')).not.toBeInTheDocument(); |
91 | | - }, |
92 | | -}; |
93 | | - |
94 | | -export const UnmuteMute: Story = { |
95 | | - ...Default, |
96 | | - name: 'Unmute and mute interaction', |
97 | | - parameters: { |
98 | | - test: { |
99 | | - // The following error is received without this flag: "TypeError: ophan.trackClickComponentEvent is not a function" |
100 | | - dangerouslyIgnoreUnhandledErrors: true, |
101 | | - }, |
102 | | - }, |
103 | | - play: async ({ canvasElement }) => { |
104 | | - const canvas = within(canvasElement); |
105 | | - |
106 | | - await canvas.findByTestId('unmute-icon'); |
107 | | - |
108 | | - await userEvent.click(canvas.getByTestId('unmute-icon')); |
109 | | - await canvas.findByTestId('mute-icon'); |
110 | | - |
111 | | - await userEvent.click(canvas.getByTestId('mute-icon')); |
112 | | - await canvas.findByTestId('unmute-icon'); |
113 | | - }, |
114 | | -}; |
115 | | - |
116 | | -// Function to emulate pausing between interactions |
117 | | -function sleep(ms: number) { |
118 | | - return new Promise((resolve) => setTimeout(resolve, ms)); |
119 | | -} |
120 | | - |
121 | | -export const InteractionObserver: Story = { |
122 | | - ...Default, |
123 | | - name: 'Interaction observer', |
124 | | - render: (args) => ( |
125 | | - <div data-testid="test-container"> |
126 | | - <LoopVideo {...args} /> |
127 | | - <div style={{ height: '100vh' }}></div> |
128 | | - <p data-testid="page-end">End of page</p> |
129 | | - </div> |
130 | | - ), |
131 | | - play: async ({ canvasElement }) => { |
132 | | - const canvas = within(canvasElement); |
133 | | - |
134 | | - await sleep(500); // Allow enough time for the autoplay video to start. |
135 | | - canvas.getByTestId('page-end').scrollIntoView(); |
136 | | - |
137 | | - const progressBar = await canvas.findByRole('progressbar'); |
138 | | - const progress = Number(progressBar.ariaValueNow); |
139 | | - |
140 | | - await sleep(500); // Allow enough time to be confident that the video is paused. |
141 | | - await expect(Number(progressBar.ariaValueNow)).toEqual(progress); |
142 | | - await expect(canvas.queryByTestId('play-icon')).not.toBeInTheDocument(); |
143 | | - }, |
144 | | -}; |
| 1 | +// import { breakpoints } from '@guardian/source/foundations'; |
| 2 | +// import type { Meta, StoryObj } from '@storybook/react-webpack5'; |
| 3 | +// import { expect, userEvent, within } from 'storybook/test'; |
| 4 | +// import { centreColumnDecorator } from '../../.storybook/decorators/gridDecorators'; |
| 5 | +// import { LoopVideo } from './LoopVideo.importable'; |
| 6 | +// |
| 7 | +// const meta = { |
| 8 | +// component: LoopVideo, |
| 9 | +// title: 'Components/LoopVideo', |
| 10 | +// decorators: [centreColumnDecorator], |
| 11 | +// render: (args) => <LoopVideo {...args} />, |
| 12 | +// parameters: { |
| 13 | +// chromatic: { |
| 14 | +// viewports: [breakpoints.mobile, breakpoints.wide], |
| 15 | +// }, |
| 16 | +// }, |
| 17 | +// } satisfies Meta<typeof LoopVideo>; |
| 18 | +// |
| 19 | +// export default meta; |
| 20 | +// type Story = StoryObj<typeof LoopVideo>; |
| 21 | +// |
| 22 | +// export const Default: Story = { |
| 23 | +// name: 'Default', |
| 24 | +// args: { |
| 25 | +// sources: [ |
| 26 | +// { |
| 27 | +// src: 'https://uploads.guim.co.uk/2025%2F06%2F20%2Ftesting+only%2C+please+ignore--3cb22b60-2c3f-48d6-8bce-38c956907cce-3.mp4', |
| 28 | +// mimeType: 'video/mp4', |
| 29 | +// }, |
| 30 | +// ], |
| 31 | +// uniqueId: 'test-video-1', |
| 32 | +// atomId: 'test-atom-1', |
| 33 | +// height: 720, |
| 34 | +// width: 900, |
| 35 | +// posterImage: |
| 36 | +// 'https://media.guim.co.uk/9bdb802e6da5d3fd249b5060f367b3a817965f0c/0_0_1800_1080/master/1800.jpg', |
| 37 | +// fallbackImage: '', |
| 38 | +// }, |
| 39 | +// }; |
| 40 | +// |
| 41 | +// export const WithM3U8File: Story = { |
| 42 | +// name: 'With M3U8 file', |
| 43 | +// args: { |
| 44 | +// ...Default.args, |
| 45 | +// sources: [ |
| 46 | +// { |
| 47 | +// src: 'https://uploads.guimcode.co.uk/2025/09/01/Loop__Japan_fireball--ace3fcf6-1378-41db-9d21-f3fc07072ab2-1.10.m3u8', |
| 48 | +// mimeType: 'application/x-mpegURL', |
| 49 | +// }, |
| 50 | +// { |
| 51 | +// src: 'https://uploads.guim.co.uk/2025%2F06%2F20%2Ftesting+only%2C+please+ignore--3cb22b60-2c3f-48d6-8bce-38c956907cce-3.mp4', |
| 52 | +// mimeType: 'video/mp4', |
| 53 | +// }, |
| 54 | +// ], |
| 55 | +// }, |
| 56 | +// }; |
| 57 | +// |
| 58 | +// export const Without5to4Ratio: Story = { |
| 59 | +// name: 'Without 5:4 aspect ratio', |
| 60 | +// args: { |
| 61 | +// ...Default.args, |
| 62 | +// sources: [ |
| 63 | +// { |
| 64 | +// src: 'https://uploads.guim.co.uk/2024/10/01/241001HeleneLoop_2.mp4', |
| 65 | +// mimeType: 'video/mp4', |
| 66 | +// }, |
| 67 | +// ], |
| 68 | +// height: 1080, |
| 69 | +// width: 1920, |
| 70 | +// }, |
| 71 | +// }; |
| 72 | +// |
| 73 | +// export const PausePlay: Story = { |
| 74 | +// ...Default, |
| 75 | +// name: 'Pause and play interaction', |
| 76 | +// play: async ({ canvasElement }) => { |
| 77 | +// const canvas = within(canvasElement); |
| 78 | +// const videoEl = canvas.getByTestId('loop-video'); |
| 79 | +// |
| 80 | +// await userEvent.click(videoEl, { |
| 81 | +// delay: 300, // Allow video to start playing. |
| 82 | +// }); |
| 83 | +// await canvas.findByTestId('play-icon'); |
| 84 | +// |
| 85 | +// const progressBar = await canvas.findByRole('progressbar'); |
| 86 | +// await expect(Number(progressBar.ariaValueNow)).toBeGreaterThan(0); |
| 87 | +// |
| 88 | +// // Play Video |
| 89 | +// await userEvent.click(videoEl); |
| 90 | +// await expect(canvas.queryByTestId('play-icon')).not.toBeInTheDocument(); |
| 91 | +// }, |
| 92 | +// }; |
| 93 | +// |
| 94 | +// // temporarily disabled whilst cors errors are resolved |
| 95 | +// // export const UnmuteMute: Story = { |
| 96 | +// // ...Default, |
| 97 | +// // name: 'Unmute and mute interaction', |
| 98 | +// // parameters: { |
| 99 | +// // test: { |
| 100 | +// // // The following error is received without this flag: "TypeError: ophan.trackClickComponentEvent is not a function" |
| 101 | +// // dangerouslyIgnoreUnhandledErrors: true, |
| 102 | +// // }, |
| 103 | +// // }, |
| 104 | +// // play: async ({ canvasElement }) => { |
| 105 | +// // const canvas = within(canvasElement); |
| 106 | +// // |
| 107 | +// // await canvas.findByTestId('unmute-icon'); |
| 108 | +// // |
| 109 | +// // await userEvent.click(canvas.getByTestId('unmute-icon')); |
| 110 | +// // await canvas.findByTestId('mute-icon'); |
| 111 | +// // |
| 112 | +// // await userEvent.click(canvas.getByTestId('mute-icon')); |
| 113 | +// // await canvas.findByTestId('unmute-icon'); |
| 114 | +// // }, |
| 115 | +// // }; |
| 116 | +// |
| 117 | +// // Function to emulate pausing between interactions |
| 118 | +// function sleep(ms: number) { |
| 119 | +// return new Promise((resolve) => setTimeout(resolve, ms)); |
| 120 | +// } |
| 121 | +// |
| 122 | +// export const InteractionObserver: Story = { |
| 123 | +// ...Default, |
| 124 | +// name: 'Interaction observer', |
| 125 | +// render: (args) => ( |
| 126 | +// <div data-testid="test-container"> |
| 127 | +// <LoopVideo {...args} /> |
| 128 | +// <div style={{ height: '100vh' }}></div> |
| 129 | +// <p data-testid="page-end">End of page</p> |
| 130 | +// </div> |
| 131 | +// ), |
| 132 | +// play: async ({ canvasElement }) => { |
| 133 | +// const canvas = within(canvasElement); |
| 134 | +// |
| 135 | +// await sleep(500); // Allow enough time for the autoplay video to start. |
| 136 | +// canvas.getByTestId('page-end').scrollIntoView(); |
| 137 | +// |
| 138 | +// const progressBar = await canvas.findByRole('progressbar'); |
| 139 | +// const progress = Number(progressBar.ariaValueNow); |
| 140 | +// |
| 141 | +// await sleep(500); // Allow enough time to be confident that the video is paused. |
| 142 | +// await expect(Number(progressBar.ariaValueNow)).toEqual(progress); |
| 143 | +// await expect(canvas.queryByTestId('play-icon')).not.toBeInTheDocument(); |
| 144 | +// }, |
| 145 | +// }; |
0 commit comments