itube-specs 0.0.710 → 0.0.713

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/package.json +1 -1
  2. package/runtime/utils/cleaners/clean-category-card.test.ts +45 -0
  3. package/runtime/utils/cleaners/clean-category-info.test.ts +42 -0
  4. package/runtime/utils/cleaners/clean-channel-card.test.ts +44 -0
  5. package/runtime/utils/cleaners/clean-channel-info.test.ts +41 -0
  6. package/runtime/utils/cleaners/clean-mini-category-card.test.ts +31 -0
  7. package/runtime/utils/cleaners/clean-model-card.test.ts +57 -0
  8. package/runtime/utils/cleaners/clean-playlist-card.test.ts +45 -0
  9. package/runtime/utils/cleaners/clean-playlist-data.test.ts +42 -0
  10. package/runtime/utils/cleaners/clean-playlist-video.test.ts +39 -0
  11. package/runtime/utils/cleaners/clean-profile-data.test.ts +30 -0
  12. package/runtime/utils/cleaners/clean-user-playlists-card.test.ts +40 -0
  13. package/runtime/utils/cleaners/clean-video-card.test.ts +57 -0
  14. package/runtime/utils/cleaners/clean-video-data.test.ts +57 -0
  15. package/runtime/utils/converters/convert-categories-to-chips.test.ts +26 -0
  16. package/runtime/utils/converters/convert-categories-to-footer.test.ts +20 -0
  17. package/runtime/utils/converters/convert-date-to-timestamp.test.ts +38 -0
  18. package/runtime/utils/converters/convert-model-card-to-chips.test.ts +20 -0
  19. package/runtime/utils/converters/convert-query-categories.test.ts +22 -0
  20. package/runtime/utils/converters/convert-snake-keys-to-camel.test.ts +29 -0
  21. package/runtime/utils/converters/convert-string-array-to-chips.test.ts +21 -0
  22. package/runtime/utils/converters/convert-string.test.ts +78 -0
  23. package/runtime/utils/converters/group-categories-by-first-letter.test.ts +46 -0
  24. package/runtime/utils/converters/group-objects-by-first-letter.test.ts +33 -0
  25. package/runtime/utils/format-date.test.ts +18 -0
  26. package/runtime/utils/format-number.test.ts +24 -0
  27. package/runtime/utils/format-time.test.ts +24 -0
  28. package/runtime/utils/get-duration.test.ts +24 -0
  29. package/runtime/utils/get-month.test.ts +30 -0
  30. package/runtime/utils/get-multiple-query.test.ts +32 -0
  31. package/runtime/utils/get-selected-query.test.ts +24 -0
  32. package/runtime/utils/is-mobile-device.test.ts +24 -0
  33. package/runtime/utils/normalize-url.test.ts +59 -0
  34. package/runtime/utils/server/parse-api-error.test.ts +36 -0
  35. package/runtime/utils/validate-email.test.ts +32 -0
  36. package/runtime/utils/validate-password.test.ts +20 -0
  37. package/runtime/utils/validate-phone.test.ts +32 -0
  38. package/runtime/utils/validate-username.test.ts +36 -0
  39. package/runtime/utils/video-data-add-model-icon.test.ts +32 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "itube-specs",
3
3
  "type": "module",
4
- "version": "0.0.710",
4
+ "version": "0.0.713",
5
5
  "main": "./nuxt.config.ts",
6
6
  "types": "./types/index.d.ts",
7
7
  "scripts": {
@@ -0,0 +1,45 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanCategoryCard } from './clean-category-card';
3
+
4
+ describe('cleanCategoryCard', () => {
5
+ it('полные данные', () => {
6
+ const raw = {
7
+ name: 'teen',
8
+ title: 'Teen',
9
+ videosCount: 100,
10
+ video_thumb_urls: {
11
+ webp: { '320x180': 'https://img.com/small.webp' },
12
+ },
13
+ guid: 'abc-123',
14
+ description: 'Test desc',
15
+ icon: 'icon.svg',
16
+ };
17
+ const result = cleanCategoryCard(raw as any);
18
+ expect(result).toEqual({
19
+ name: 'teen',
20
+ title: 'Teen',
21
+ videosCount: 100,
22
+ thumbUrls: { webp: { '320x180': 'https://img.com/small.webp' } },
23
+ guid: 'abc-123',
24
+ description: 'Test desc',
25
+ icon: 'icon.svg',
26
+ });
27
+ });
28
+
29
+ it('пустые данные → дефолты', () => {
30
+ const result = cleanCategoryCard({} as any);
31
+ expect(result.name).toBe('');
32
+ expect(result.title).toBe('');
33
+ expect(result.videosCount).toBe(0);
34
+ expect(result.thumbUrls).toBeUndefined();
35
+ expect(result.guid).toBe('');
36
+ expect(result.description).toBe('');
37
+ expect(result.icon).toBe('');
38
+ });
39
+
40
+ it('thumbUrls без нужного размера', () => {
41
+ const raw = { video_thumb_urls: { webp: {} } };
42
+ const result = cleanCategoryCard(raw as any);
43
+ expect(result.thumbUrls).toEqual({ webp: { '320x180': '' } });
44
+ });
45
+ });
@@ -0,0 +1,42 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanCategoryInfo } from './clean-category-info';
3
+
4
+ describe('cleanCategoryInfo', () => {
5
+ it('полные данные', () => {
6
+ const raw = {
7
+ guid: 'abc',
8
+ title: 'Teen',
9
+ videosCount: 50,
10
+ description: 'desc',
11
+ fullDescription: 'full desc',
12
+ related: [{ title: 'MILF', name: 'milf' }],
13
+ meta_description: 'meta desc',
14
+ meta_title: 'meta title',
15
+ header: 'h1 header',
16
+ };
17
+ const result = cleanCategoryInfo(raw as any);
18
+ expect(result.guid).toBe('abc');
19
+ expect(result.title).toBe('Teen');
20
+ expect(result.videosCount).toBe(50);
21
+ expect(result.fullDescription).toBe('full desc');
22
+ expect(result.metaDescription).toBe('meta desc');
23
+ expect(result.metaTitle).toBe('meta title');
24
+ expect(result.header).toBe('h1 header');
25
+ expect(result.related).toEqual([
26
+ { title: 'MILF', value: 'milf', prefix: 'categories' },
27
+ ]);
28
+ });
29
+
30
+ it('пустые данные → дефолты', () => {
31
+ const result = cleanCategoryInfo({} as any);
32
+ expect(result.guid).toBe('');
33
+ expect(result.title).toBe('');
34
+ expect(result.videosCount).toBe(0);
35
+ expect(result.description).toBe('');
36
+ expect(result.fullDescription).toBe('');
37
+ expect(result.related).toEqual([]);
38
+ expect(result.metaDescription).toBe('');
39
+ expect(result.metaTitle).toBe('');
40
+ expect(result.header).toBe('');
41
+ });
42
+ });
@@ -0,0 +1,44 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanChannelCard } from './clean-channel-card';
3
+
4
+ describe('cleanChannelCard', () => {
5
+ it('полные данные', () => {
6
+ const raw = {
7
+ guid: 'ch-1',
8
+ name: 'Channel',
9
+ url: '/channel/1',
10
+ videos_count: 200,
11
+ is_network: true,
12
+ updated: 1700000000,
13
+ avatar_url: 'https://img.com/avatar.jpg',
14
+ video_thumb_urls: {
15
+ webp: {
16
+ '320x180': 'https://img.com/s.webp',
17
+ '480x270': 'https://img.com/m.webp',
18
+ },
19
+ },
20
+ description: 'Channel desc',
21
+ };
22
+ const result = cleanChannelCard(raw as any);
23
+ expect(result.guid).toBe('ch-1');
24
+ expect(result.name).toBe('Channel');
25
+ expect(result.videosCount).toBe(200);
26
+ expect(result.isNetwork).toBe(true);
27
+ expect(result.avatarUrl).toBe('https://img.com/avatar.jpg');
28
+ expect(result.thumbUrls).toEqual({
29
+ webp: {
30
+ '320x180': 'https://img.com/s.webp',
31
+ '480x270': 'https://img.com/m.webp',
32
+ },
33
+ });
34
+ });
35
+
36
+ it('пустые данные → дефолты', () => {
37
+ const result = cleanChannelCard({} as any);
38
+ expect(result.guid).toBe('');
39
+ expect(result.name).toBe('');
40
+ expect(result.videosCount).toBe(0);
41
+ expect(result.isNetwork).toBe(false);
42
+ expect(result.thumbUrls).toBeUndefined();
43
+ });
44
+ });
@@ -0,0 +1,41 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanChannelInfo } from './clean-channel-info';
3
+
4
+ describe('cleanChannelInfo', () => {
5
+ it('полные данные', () => {
6
+ const raw = {
7
+ guid: 'ch-1',
8
+ name: 'Channel Name',
9
+ url: '/channel/1',
10
+ description: 'desc',
11
+ videos_count: 100,
12
+ is_network: false,
13
+ updated: 1700000000,
14
+ avatar_url: 'https://img.com/avatar.jpg',
15
+ video_thumb_urls: { webp: { '320x180': 'https://img.com/s.webp' } },
16
+ tags: ['tag1', 'tag2'],
17
+ };
18
+ const result = cleanChannelInfo(raw as any);
19
+ expect(result.title).toBe('Channel Name');
20
+ expect(result.img).toBe('https://img.com/avatar.jpg');
21
+ expect(result.tags).toEqual(['tag1', 'tag2']);
22
+ });
23
+
24
+ it('без avatar_url → берёт thumb', () => {
25
+ const raw = {
26
+ avatar_url: '',
27
+ video_thumb_urls: { webp: { '320x180': 'https://img.com/thumb.webp' } },
28
+ };
29
+ const result = cleanChannelInfo(raw as any);
30
+ expect(result.img).toBe('https://img.com/thumb.webp');
31
+ });
32
+
33
+ it('пустые данные с пустым webp → дефолты', () => {
34
+ const raw = { video_thumb_urls: { webp: {} } };
35
+ const result = cleanChannelInfo(raw as any);
36
+ expect(result.guid).toBe('');
37
+ expect(result.title).toBe('');
38
+ expect(result.videosCount).toBe(0);
39
+ expect(result.tags).toEqual([]);
40
+ });
41
+ });
@@ -0,0 +1,31 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanMiniCategoryCard } from './clean-mini-category-card';
3
+
4
+ describe('cleanMiniCategoryCard', () => {
5
+ it('полные данные', () => {
6
+ const raw = {
7
+ name: 'teen',
8
+ title: 'Teen',
9
+ is_top: true,
10
+ videosCount: 50,
11
+ icon: 'icon.svg',
12
+ };
13
+ const result = cleanMiniCategoryCard(raw as any);
14
+ expect(result).toEqual({
15
+ name: 'teen',
16
+ title: 'Teen',
17
+ isTop: true,
18
+ videosCount: 50,
19
+ icon: 'icon.svg',
20
+ });
21
+ });
22
+
23
+ it('пустые данные → дефолты', () => {
24
+ const result = cleanMiniCategoryCard({} as any);
25
+ expect(result.name).toBe('');
26
+ expect(result.title).toBe('');
27
+ expect(result.isTop).toBe(false);
28
+ expect(result.videosCount).toBe(0);
29
+ expect(result.icon).toBeUndefined();
30
+ });
31
+ });
@@ -0,0 +1,57 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanModelCard } from './clean-model-card';
3
+
4
+ const makeRaw = (overrides = {}) => ({
5
+ title: 'Model Name',
6
+ videos_count: 10,
7
+ video_thumb_urls: { webp: { '320x180': 'https://img.com/s.webp' } },
8
+ primary_image_url: 'https://img.com/primary.jpg',
9
+ guid: 'model-1',
10
+ parameters: [
11
+ { name: 'birthplace_country', values: [{ title: 'USA', name: 'usa' }] },
12
+ { name: 'age', values: [{ title: '25' }] },
13
+ { name: 'height_cm', values: [{ title: '170' }] },
14
+ { name: 'weight_kg', values: [{ title: '55' }] },
15
+ ],
16
+ ...overrides,
17
+ });
18
+
19
+ describe('cleanModelCard', () => {
20
+ it('полные данные', () => {
21
+ const result = cleanModelCard(makeRaw() as any);
22
+ expect(result.title).toBe('Model Name');
23
+ expect(result.videosCount).toBe(10);
24
+ expect(result.thumbUrl).toBe('https://img.com/s.webp');
25
+ expect(result.guid).toBe('model-1');
26
+ expect(result.country).toEqual({ title: 'USA', name: 'usa' });
27
+ });
28
+
29
+ it('параметры: age, height, weight', () => {
30
+ const result = cleanModelCard(makeRaw() as any);
31
+ expect(result.parameters).toEqual([
32
+ { title: 'age', value: '25' },
33
+ { title: 'height_cm', value: '170' },
34
+ { title: 'weight_kg', value: '55' },
35
+ ]);
36
+ });
37
+
38
+ it('без age → параметры без age', () => {
39
+ const raw = makeRaw({
40
+ parameters: [
41
+ { name: 'birthplace_country', values: [{ title: 'USA', name: 'usa' }] },
42
+ { name: 'height_cm', values: [{ title: '170' }] },
43
+ ],
44
+ });
45
+ const result = cleanModelCard(raw as any);
46
+ expect(result.parameters).toEqual([
47
+ { title: 'height_cm', value: '170' },
48
+ ]);
49
+ });
50
+
51
+ it('пустые параметры', () => {
52
+ const raw = makeRaw({ parameters: [] });
53
+ const result = cleanModelCard(raw as any);
54
+ expect(result.country).toEqual({ title: '', name: '' });
55
+ expect(result.parameters).toEqual([]);
56
+ });
57
+ });
@@ -0,0 +1,45 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanPlaylistCard } from './clean-playlist-card';
3
+
4
+ describe('cleanPlaylistCard', () => {
5
+ it('полные данные', () => {
6
+ const raw = {
7
+ created: 1700000000,
8
+ id: 'pl-1',
9
+ name: 'My Playlist',
10
+ username: 'user1',
11
+ playlist_type: 'public',
12
+ thumbs: [
13
+ { urls: { webp: { '320x180': 'https://img.com/s1.webp', '480x270': 'https://img.com/m1.webp' } } },
14
+ ],
15
+ videos_count: 5,
16
+ first_video_id: 'v-1',
17
+ search_tags: 'tag1,tag2',
18
+ views: 100,
19
+ likes: 10,
20
+ dislikes: 2,
21
+ };
22
+ const result = cleanPlaylistCard(raw as any);
23
+ expect(result.id).toBe('pl-1');
24
+ expect(result.name).toBe('My Playlist');
25
+ expect(result.playlistType).toBe('public');
26
+ expect(result.videosCount).toBe(5);
27
+ expect(result.thumbUrls).toHaveLength(1);
28
+ expect(result.thumbUrls![0]).toEqual({
29
+ webp: {
30
+ '320x180': 'https://img.com/s1.webp',
31
+ '480x270': 'https://img.com/m1.webp',
32
+ },
33
+ });
34
+ });
35
+
36
+ it('пустые данные → дефолты', () => {
37
+ const result = cleanPlaylistCard({} as any);
38
+ expect(result.id).toBe('');
39
+ expect(result.name).toBe('');
40
+ expect(result.videosCount).toBe(0);
41
+ expect(result.views).toBe(0);
42
+ expect(result.likes).toBe(0);
43
+ expect(result.dislikes).toBe(0);
44
+ });
45
+ });
@@ -0,0 +1,42 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanPlaylistData } from './clean-playlist-data';
3
+
4
+ describe('cleanPlaylistData', () => {
5
+ it('полные данные', () => {
6
+ const raw = {
7
+ updated: 1700000000,
8
+ id: 'pl-1',
9
+ name: 'Playlist',
10
+ username: 'user1',
11
+ playlist_type: 'private',
12
+ videos_count: 10,
13
+ first_video_id: 'v-1',
14
+ search_tags: 'tags',
15
+ views: 200,
16
+ likes: 20,
17
+ dislikes: 3,
18
+ };
19
+ const result = cleanPlaylistData(raw as any);
20
+ expect(result).toEqual({
21
+ updated: 1700000000,
22
+ id: 'pl-1',
23
+ name: 'Playlist',
24
+ username: 'user1',
25
+ playlistType: 'private',
26
+ videosCount: 10,
27
+ firstVideoId: 'v-1',
28
+ searchTags: 'tags',
29
+ views: 200,
30
+ likes: 20,
31
+ dislikes: 3,
32
+ });
33
+ });
34
+
35
+ it('пустые данные → дефолты', () => {
36
+ const result = cleanPlaylistData({} as any);
37
+ expect(result.updated).toBe(0);
38
+ expect(result.id).toBe('');
39
+ expect(result.videosCount).toBe(0);
40
+ expect(result.views).toBe(0);
41
+ });
42
+ });
@@ -0,0 +1,39 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanPlaylistVideo } from './clean-playlist-video';
3
+
4
+ describe('cleanPlaylistVideo', () => {
5
+ it('полные данные', () => {
6
+ const raw = {
7
+ guid: 'v-1',
8
+ duration: 300,
9
+ title: 'Video Title',
10
+ id: 'id-1',
11
+ thumb_urls: {
12
+ webp: {
13
+ '320x180': 'https://img.com/s.webp',
14
+ '480x270': 'https://img.com/m.webp',
15
+ },
16
+ },
17
+ md5: 'abc123',
18
+ };
19
+ const result = cleanPlaylistVideo(raw as any);
20
+ expect(result.guid).toBe('v-1');
21
+ expect(result.duration).toBe(300);
22
+ expect(result.title).toBe('Video Title');
23
+ expect(result.thumbUrls).toEqual({
24
+ webp: {
25
+ '320x180': 'https://img.com/s.webp',
26
+ '480x270': 'https://img.com/m.webp',
27
+ },
28
+ });
29
+ });
30
+
31
+ it('пустые данные → дефолты', () => {
32
+ const result = cleanPlaylistVideo({} as any);
33
+ expect(result.guid).toBe('');
34
+ expect(result.duration).toBe(0);
35
+ expect(result.title).toBe('');
36
+ expect(result.thumbUrls).toBeUndefined();
37
+ expect(result.md5).toBe('');
38
+ });
39
+ });
@@ -0,0 +1,30 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanProfileData } from './clean-profile-data';
3
+
4
+ describe('cleanProfileData', () => {
5
+ it('полные данные', () => {
6
+ const raw = {
7
+ username: 'john',
8
+ email: 'john@test.com',
9
+ avatar: 'https://img.com/avatar.jpg',
10
+ country: 'US',
11
+ city: 'NYC',
12
+ birthday: 946684800,
13
+ gender: 'male',
14
+ created: 1700000000,
15
+ };
16
+ const result = cleanProfileData(raw as any);
17
+ expect(result).toEqual(raw);
18
+ });
19
+
20
+ it('пустые данные → дефолты', () => {
21
+ const result = cleanProfileData({} as any);
22
+ expect(result.username).toBe('');
23
+ expect(result.email).toBe('');
24
+ expect(result.avatar).toBe('');
25
+ expect(result.country).toBe('');
26
+ expect(result.birthday).toBe(0);
27
+ expect(result.gender).toBe('');
28
+ expect(result.created).toBe(0);
29
+ });
30
+ });
@@ -0,0 +1,40 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanUserPlaylistCard } from './clean-user-playlists-card';
3
+
4
+ describe('cleanUserPlaylistCard', () => {
5
+ it('полные данные', () => {
6
+ const raw = {
7
+ created: 1700000000,
8
+ id: 'pl-1',
9
+ name: 'My Playlist',
10
+ username: 'user1',
11
+ playlistType: 'public',
12
+ thumbs: [
13
+ 'https://img.com/1.webp',
14
+ 'https://img.com/2.webp',
15
+ 'https://img.com/3.webp',
16
+ 'https://img.com/4.webp',
17
+ 'https://img.com/5.webp',
18
+ ],
19
+ videoCount: 10,
20
+ firstVideoID: 'v-1',
21
+ };
22
+ const result = cleanUserPlaylistCard(raw as any);
23
+ expect(result.id).toBe('pl-1');
24
+ expect(result.playlistType).toBe('public');
25
+ expect(result.videosCount).toBe(10);
26
+ expect(result.firstVideoId).toBe('v-1');
27
+ expect(result.thumbUrls).toHaveLength(4); // slice(0, 4)
28
+ expect(result.thumbUrls![0]).toEqual({
29
+ webp: { '320x180': 'https://img.com/1.webp' },
30
+ });
31
+ });
32
+
33
+ it('пустые данные → дефолты', () => {
34
+ const result = cleanUserPlaylistCard({} as any);
35
+ expect(result.id).toBe('');
36
+ expect(result.name).toBe('');
37
+ expect(result.videosCount).toBe(0);
38
+ expect(result.thumbUrls).toEqual([]);
39
+ });
40
+ });
@@ -0,0 +1,57 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanVideoCard } from './clean-video-card';
3
+
4
+ describe('cleanVideoCard', () => {
5
+ it('полные данные', () => {
6
+ const raw = {
7
+ guid: 'v-1',
8
+ quality: '1080p',
9
+ duration: 600,
10
+ title: 'Video Title',
11
+ views: 1000,
12
+ id: 'id-1',
13
+ tags: 'tag1,tag2',
14
+ is_new: true,
15
+ channel: { avatar_url: 'https://img.com/ch.jpg', name: 'Channel' },
16
+ url: '/video/1',
17
+ preview_url: 'https://img.com/preview.mp4',
18
+ thumb_urls: {
19
+ webp: {
20
+ '320x180': 'https://img.com/s.webp',
21
+ '480x270': 'https://img.com/m.webp',
22
+ },
23
+ },
24
+ md5: 'abc',
25
+ thumb_number: 3,
26
+ models: [{ title: 'Model A' }, { title: 'Model B' }],
27
+ };
28
+ const result = cleanVideoCard(raw as any);
29
+ expect(result.guid).toBe('v-1');
30
+ expect(result.quality).toBe('1080p');
31
+ expect(result.isNew).toBe(true);
32
+ expect(result.channelName).toBe('Channel');
33
+ expect(result.channelAvatar).toBe('https://img.com/ch.jpg');
34
+ expect(result.models).toEqual(['Model A', 'Model B']);
35
+ expect(result.thumbNum).toBe(3);
36
+ expect(result.thumbUrls).toEqual({
37
+ webp: {
38
+ '320x180': 'https://img.com/s.webp',
39
+ '480x270': 'https://img.com/m.webp',
40
+ },
41
+ });
42
+ });
43
+
44
+ it('пустые данные → дефолты', () => {
45
+ const result = cleanVideoCard({} as any);
46
+ expect(result.guid).toBe('');
47
+ expect(result.quality).toBe('');
48
+ expect(result.duration).toBe(0);
49
+ expect(result.views).toBe(0);
50
+ expect(result.isNew).toBe(false);
51
+ expect(result.channelAvatar).toBe('');
52
+ expect(result.channelName).toBe('');
53
+ expect(result.thumbUrls).toBeUndefined();
54
+ expect(result.models).toEqual([]);
55
+ expect(result.thumbNum).toBe(0);
56
+ });
57
+ });
@@ -0,0 +1,57 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { cleanVideoData } from './clean-video-data';
3
+
4
+ describe('cleanVideoData', () => {
5
+ it('полные данные', () => {
6
+ const raw = {
7
+ guid: 'v-1',
8
+ md5: 'abc',
9
+ quality: '1080p',
10
+ duration: 600,
11
+ title: 'Title',
12
+ header: 'Header',
13
+ views: 1000,
14
+ likes: 100,
15
+ id: 'id-1',
16
+ tags: 'tag1',
17
+ models: 'model1',
18
+ categories: 'cat1',
19
+ actions: { liked: true },
20
+ channel: { name: 'Channel', avatar_url: 'https://img.com/ch.jpg' },
21
+ url: '/video/1',
22
+ preview_url: 'https://img.com/preview.mp4',
23
+ thumb_urls: { webp: { '320x180': 'small' } },
24
+ vtt_url: '/vtt',
25
+ vtt_sprite_url: '/sprite',
26
+ created: 1700000000,
27
+ video_url: '/stream',
28
+ is_deleted: false,
29
+ thumb_number: 5,
30
+ description: 'desc',
31
+ dislikes: 3,
32
+ };
33
+ const result = cleanVideoData(raw as any);
34
+ expect(result.guid).toBe('v-1');
35
+ expect(result.channelName).toBe('Channel');
36
+ expect(result.thumbUrls).toEqual({ webp: { '320x180': 'small' } });
37
+ expect(result.vttUrl).toBe('/vtt');
38
+ expect(result.videoUrl).toBe('/stream');
39
+ expect(result.isDeleted).toBe(false);
40
+ expect(result.thumbNum).toBe(5);
41
+ });
42
+
43
+ it('пустые данные → дефолты', () => {
44
+ const result = cleanVideoData({} as any);
45
+ expect(result.guid).toBe('');
46
+ expect(result.duration).toBe(0);
47
+ expect(result.views).toBe(0);
48
+ expect(result.likes).toBe(0);
49
+ expect(result.channelName).toBe('');
50
+ expect(result.channelAvatar).toBe('');
51
+ expect(result.thumbUrls).toBeUndefined();
52
+ expect(result.isDeleted).toBe(false);
53
+ expect(result.created).toBe(0);
54
+ expect(result.actions).toBe(null);
55
+ expect(result.dislikes).toBe(0);
56
+ });
57
+ });
@@ -0,0 +1,26 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { convertCategoriesToChips } from './convert-categories-to-chips';
3
+
4
+ describe('convertCategoriesToChips', () => {
5
+ it('конвертирует массив категорий в чипсы', () => {
6
+ const items = [
7
+ { title: 'Teen', name: 'teen' },
8
+ { title: 'MILF', name: 'milf' },
9
+ ];
10
+ const result = convertCategoriesToChips(items as any, 'categories');
11
+ expect(result).toEqual([
12
+ { title: 'Teen', value: 'teen', prefix: 'categories' },
13
+ { title: 'MILF', value: 'milf', prefix: 'categories' },
14
+ ]);
15
+ });
16
+
17
+ it('пустой массив', () => {
18
+ expect(convertCategoriesToChips([], 'categories')).toEqual([]);
19
+ });
20
+
21
+ it('использует переданный prefix', () => {
22
+ const items = [{ title: 'A', name: 'a' }];
23
+ const result = convertCategoriesToChips(items as any, 'models');
24
+ expect(result[0].prefix).toBe('models');
25
+ });
26
+ });
@@ -0,0 +1,20 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { convertCategoriesToFooter } from './convert-categories-to-footer';
3
+
4
+ describe('convertCategoriesToFooter', () => {
5
+ it('конвертирует категории в футер', () => {
6
+ const items = [
7
+ { title: 'Teen', name: 'teen' },
8
+ { title: 'MILF', name: 'milf' },
9
+ ];
10
+ const result = convertCategoriesToFooter(items as any);
11
+ expect(result).toEqual([
12
+ { title: 'Teen', name: 'teen' },
13
+ { title: 'MILF', name: 'milf' },
14
+ ]);
15
+ });
16
+
17
+ it('пустой массив', () => {
18
+ expect(convertCategoriesToFooter([])).toEqual([]);
19
+ });
20
+ });
@@ -0,0 +1,38 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { convertDateToTimestamp } from './convert-date-to-timestamp';
3
+
4
+ const c = convertDateToTimestamp();
5
+
6
+ describe('convertDateToTimestamp', () => {
7
+ describe('toUnix', () => {
8
+ it('валидная дата', () => {
9
+ expect(c.toUnix('2025-01-01')).toBe(Date.UTC(2025, 0, 1) / 1000);
10
+ });
11
+
12
+ it('начало эпохи', () => {
13
+ expect(c.toUnix('1970-01-01')).toBe(0);
14
+ });
15
+
16
+ it('невалидная дата → null', () => {
17
+ expect(c.toUnix('invalid')).toBe(null);
18
+ });
19
+ });
20
+
21
+ describe('fromUnix', () => {
22
+ it('timestamp → дата', () => {
23
+ expect(c.fromUnix(0)).toBe('1970-01-01');
24
+ });
25
+
26
+ it('конкретная дата', () => {
27
+ const ts = Date.UTC(2024, 2, 5) / 1000;
28
+ expect(c.fromUnix(ts)).toBe('2024-03-05');
29
+ });
30
+ });
31
+
32
+ describe('roundtrip', () => {
33
+ it('toUnix → fromUnix', () => {
34
+ const date = '2024-03-05';
35
+ expect(c.fromUnix(c.toUnix(date)!)).toBe(date);
36
+ });
37
+ });
38
+ });