swadhinbiswas

[email protected]
2026-07-24 22:24:11 +0600 committed NaN years ago
3ad4bf2
commit 3ad4bf2
1 file changed
+246 -0
Showing 1 changed file+246-0
▼packages/subtitle/src/index.test.ts
+246-0
1
+import { describe, it, expect, vi } from 'vitest';
2
+import { SRTParser, VTTParser, ASSParser, SubtitleRenderer } from './index.js';
3
+
4
+describe('SRTParser', () => {
5
+ it('should parse valid SRT content', () => {
6
+ const srt = `1
7
+00:00:01,000 --> 00:00:04,000
8
+Hello World
9
+
10
+2
11
+00:00:05,000 --> 00:00:08,000
12
+Second subtitle`;
13
+
14
+ const packets = SRTParser.parse(srt);
15
+ expect(packets.length).toBe(2);
16
+ expect(packets[0].text).toBe('Hello World');
17
+ expect(packets[0].startTime).toBe(1);
18
+ expect(packets[0].endTime).toBe(4);
19
+ expect(packets[1].text).toBe('Second subtitle');
20
+ });
21
+
22
+ it('should handle empty SRT', () => {
23
+ const packets = SRTParser.parse('');
24
+ expect(packets.length).toBe(0);
25
+ });
26
+
27
+ it('should handle malformed SRT', () => {
28
+ const srt = `Invalid SRT content`;
29
+ const packets = SRTParser.parse(srt);
30
+ expect(packets.length).toBe(0);
31
+ });
32
+
33
+ it('should parse timestamps correctly', () => {
34
+ const ts = SRTParser.parseTimestamp('01:30:45,500');
35
+ expect(ts).toBe(5445.5);
36
+ });
37
+});
38
+
39
+describe('VTTParser', () => {
40
+ it('should parse valid VTT content', () => {
41
+ const vtt = `WEBVTT
42
+
43
+1
44
+00:00:01.000 --> 00:00:04.000
45
+Hello World
46
+
47
+2
48
+00:00:05.000 --> 00:00:08.000
49
+Second subtitle`;
50
+
51
+ const packets = VTTParser.parse(vtt);
52
+ expect(packets.length).toBe(2);
53
+ expect(packets[0].text).toBe('Hello World');
54
+ });
55
+
56
+ it('should handle VTT with NOTE blocks', () => {
57
+ const vtt = `WEBVTT
58
+
59
+NOTE This is a comment
60
+
61
+1
62
+00:00:01.000 --> 00:00:04.000
63
+Hello World`;
64
+
65
+ const packets = VTTParser.parse(vtt);
66
+ expect(packets.length).toBe(1);
67
+ });
68
+
69
+ it('should handle empty VTT', () => {
70
+ const packets = VTTParser.parse('');
71
+ expect(packets.length).toBe(0);
72
+ });
73
+});
74
+
75
+describe('ASSParser', () => {
76
+ it('should parse valid ASS content', () => {
77
+ const ass = `[Script Info]
78
+Title: Test
79
+PlayResX: 1920
80
+PlayResY: 1080
81
+
82
+[V4+ Styles]
83
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
84
+Style: Default,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H80000000,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,1
85
+
86
+[Events]
87
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
88
+Dialogue: 0,0:00:01.00,0:00:04.00,Default,,0,0,0,,Hello World`;
89
+
90
+ const packets = ASSParser.parse(ass);
91
+ expect(packets.length).toBe(1);
92
+ expect(packets[0].text).toBe('Hello World');
93
+ expect(packets[0].startTime).toBe(1);
94
+ expect(packets[0].endTime).toBe(4);
95
+ });
96
+
97
+ it('should parse Script Info', () => {
98
+ const ass = `[Script Info]
99
+PlayResX: 1920
100
+PlayResY: 1080`;
101
+
102
+ const info = ASSParser.getASSInfo(ass);
103
+ expect(info.playResX).toBe(1920);
104
+ expect(info.playResY).toBe(1080);
105
+ });
106
+
107
+ it('should handle empty ASS', () => {
108
+ const packets = ASSParser.parse('');
109
+ expect(packets.length).toBe(0);
110
+ });
111
+
112
+ it('should strip override tags', () => {
113
+ const ass = `[Events]
114
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
115
+Dialogue: 0,0:00:01.00,0:00:04.00,Default,,0,0,0,,{\\b1}Bold{\\b0} text`;
116
+
117
+ const packets = ASSParser.parse(ass);
118
+ expect(packets.length).toBe(1);
119
+ expect(packets[0].text).toBe('Bold text');
120
+ });
121
+});
122
+
123
+describe('SubtitleRenderer', () => {
124
+ it('should initialize with canvas', () => {
125
+ const canvas = {
126
+ width: 1920,
127
+ height: 1080,
128
+ getContext: vi.fn(() => ({
129
+ clearRect: vi.fn(),
130
+ fillText: vi.fn(),
131
+ strokeText: vi.fn(),
132
+ measureText: vi.fn(() => ({ width: 100 })),
133
+ fillStyle: '',
134
+ strokeStyle: '',
135
+ lineWidth: 1,
136
+ font: '',
137
+ textAlign: 'center',
138
+ textBaseline: 'bottom'
139
+ })),
140
+ style: {}
141
+ } as unknown as HTMLCanvasElement;
142
+
143
+ const renderer = new SubtitleRenderer(canvas);
144
+ expect(renderer).toBeDefined();
145
+ });
146
+
147
+ it('should render active subtitles', () => {
148
+ const canvasEl = { width: 1920, height: 1080 };
149
+ const mockCtx = {
150
+ canvas: canvasEl,
151
+ clearRect: vi.fn(),
152
+ fillText: vi.fn(),
153
+ strokeText: vi.fn(),
154
+ measureText: vi.fn(() => ({ width: 100 })),
155
+ fillStyle: '',
156
+ strokeStyle: '',
157
+ lineWidth: 1,
158
+ font: '',
159
+ textAlign: 'center',
160
+ textBaseline: 'bottom'
161
+ };
162
+
163
+ const canvas = {
164
+ width: 1920,
165
+ height: 1080,
166
+ getContext: vi.fn(() => mockCtx),
167
+ style: {}
168
+ } as unknown as HTMLCanvasElement;
169
+
170
+ const renderer = new SubtitleRenderer(canvas);
171
+
172
+ const packets = [
173
+ { startTime: 1, endTime: 4, text: 'Hello World' },
174
+ { startTime: 5, endTime: 8, text: 'Second subtitle' }
175
+ ];
176
+
177
+ renderer.renderSubtitles(packets, 2);
178
+ expect(mockCtx.clearRect).toHaveBeenCalled();
179
+ expect(mockCtx.fillText).toHaveBeenCalled();
180
+ });
181
+
182
+ it('should not render inactive subtitles', () => {
183
+ const canvasEl = { width: 1920, height: 1080 };
184
+ const mockCtx = {
185
+ canvas: canvasEl,
186
+ clearRect: vi.fn(),
187
+ fillText: vi.fn(),
188
+ strokeText: vi.fn(),
189
+ measureText: vi.fn(() => ({ width: 100 })),
190
+ fillStyle: '',
191
+ strokeStyle: '',
192
+ lineWidth: 1,
193
+ font: '',
194
+ textAlign: 'center',
195
+ textBaseline: 'bottom'
196
+ };
197
+
198
+ const canvas = {
199
+ width: 1920,
200
+ height: 1080,
201
+ getContext: vi.fn(() => mockCtx),
202
+ style: {}
203
+ } as unknown as HTMLCanvasElement;
204
+
205
+ const renderer = new SubtitleRenderer(canvas);
206
+
207
+ const packets = [
208
+ { startTime: 1, endTime: 4, text: 'Hello World' }
209
+ ];
210
+
211
+ renderer.renderSubtitles(packets, 10); // Time outside subtitle range
212
+ expect(mockCtx.fillText).not.toHaveBeenCalled();
213
+ });
214
+
215
+ it('should set custom style', () => {
216
+ const canvas = {
217
+ width: 1920,
218
+ height: 1080,
219
+ getContext: vi.fn(() => ({
220
+ clearRect: vi.fn(),
221
+ fillText: vi.fn(),
222
+ strokeText: vi.fn(),
223
+ measureText: vi.fn(() => ({ width: 100 })),
224
+ fillStyle: '',
225
+ strokeStyle: '',
226
+ lineWidth: 1,
227
+ font: '',
228
+ textAlign: 'center',
229
+ textBaseline: 'bottom'
230
+ })),
231
+ style: {}
232
+ } as unknown as HTMLCanvasElement;
233
+
234
+ const renderer = new SubtitleRenderer(canvas);
235
+
236
+ renderer.setStyle({
237
+ fontSize: 32,
238
+ fontFamily: 'Arial',
239
+ color: '#FF0000',
240
+ outlineColor: '#000000'
241
+ });
242
+
243
+ // Should not throw
244
+ expect(true).toBe(true);
245
+ });
246
+});
0
247