1
+ import assert from "assert" ;
2
+ import { client } from "../utils/httpClient" ;
3
+ import { config } from "../../src/config" ;
4
+ import sinon from "sinon" ;
5
+ import { sanitize } from "../../src/utils/youtubeID" ;
6
+
7
+ // videoID array
8
+ const badVideoIDs = [
9
+ [ "null" , "< 11" ] ,
10
+ [ "dQw4w9WgXc?" , "invalid characters" ] ,
11
+ [ "https://www.youtube.com/clip/UgkxeLPGsmKnMdm46DGml_0aa0aaAAAAA00a" , "clip URL" ] ,
12
+ [ "https://youtube.com/channel/UCaAa00aaaAA0a0a0AaaAAAA" , "channel ID (UC)" ] ,
13
+ [ "https://www.youtube.com/@LinusTechTips" , "channel @username" ] ,
14
+ [ "https://www.youtube.com/@GamersNexus" , "channel @username" ] ,
15
+ [ "https://www.youtube.com/c/LinusTechTips" , "custom channel /c/" ] ,
16
+ [ "https://www.youtube.com/c/GamersNexus" , "custom channel /c/" ] ,
17
+ [ "https://www.youtube.com/" , "home/ page URL" ] ,
18
+ [ "03224876b002487796379942f199bc22ffac46157ad2488119bccc7b03c55430" , "UUID" ] ,
19
+ [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=16s#requiredSegment=03224876b002487796379942f199bc22ffac46157ad2488119bccc7b03c55430" , "full #requiredSegments uuid" ] ,
20
+ [ "" , "empty videoID" ]
21
+
22
+ ] ;
23
+ const goodVideoIDs = [
24
+ [ "dQw4w9WgXcQ" , "standalone videoID" ] ,
25
+ [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ" , "?watch link" ] ,
26
+ [ "http://www.youtube.com/watch?v=dQw4w9WgXcQ" , "http link" ] ,
27
+ [ "www.youtube.com/watch?v=dQw4w9WgXcQ" , "no protocol link" ] ,
28
+ [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ?t=2" , "trailing &t parameter" ] ,
29
+ [ "https://youtu.be/dQw4w9WgXcQ" , "youtu.be" ] ,
30
+ [ "youtu.be/dQw4w9WgXcQ" , "no protocol youtu.be" ] ,
31
+ [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=16s#requiredSegment=00000000000" , "#requiredsegment link" ] ,
32
+ [ "https://www.youtube.com/embed/dQw4w9WgXcQ?wmode=transparent&rel=0&autohide=1&showinfo=1&fs=1&enablejsapi=0&theme=light" , "long embedded link" ] ,
33
+ [ "http://m.youtube.com/watch?v=dQw4w9WgXcQ&app=m&persist_app=1" , "force persist desktop" ] ,
34
+ [ "http://m.youtube.com/watch?v=dQw4w9WgXcQ" , "mobile" ] ,
35
+ [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ&list=PL8mG-AaA0aAa0AAa0A0A-aAaaA00aaAa0" , "/watch&list" ] ,
36
+ [ "https://www.youtube.com/embed/dQw4w9WgXcQ?list=PL8mG-AaA0aAa0AAa0A0A-aAaaA00aaAa0" , "/embed/video" ] ,
37
+ [ "dQw4w9WgXcQ\n" , "escaped newline" ] ,
38
+ [ "dQw4w9WgXcQ\t" , "escaped tab" ] ,
39
+ [ "%20dQw4w9WgXcQ%20%20%20" , "urlencoded" ] ,
40
+ [ "https://sb.ltn.fi/video/dQw4w9WgXcQ/" , "sbltnfi link" ] ,
41
+ [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ#t=0m10s" , "anchor as t parameter" ] ,
42
+ ] ;
43
+ const edgeVideoIDs = [
44
+ [ "https://www.youtube.com/embed/videoseries?list=PL8mG-Aaa0aAa1AAa0A0A-a0aaA00aaAa0" , "/videoseries" ] ,
45
+ [ "https://www.youtube.com/embed/playlist?list=PL8mG-Aaa0aAa1AAa0A0A-a0aaA00aaAa0" , "/playlist" ] ,
46
+ [ "PL8mG-Aaa0aAa1AAa0A0A-a0aaA00aaAa0" , "playlist ID" ] ,
47
+ [ "UgkxeLPGsmKnMdm46DGml_0aa0aaAAAAA00a" , "clip ID" ] ,
48
+ [ "https://www.youtube.com/GamersNexus" , "channel custom URL" ] ,
49
+ [ "https://www.youtube.com/LinusTechTips" , "channel custom URL" ] ,
50
+ ] ;
51
+ const targetVideoID = "dQw4w9WgXcQ" ;
52
+
53
+ // tests
54
+ describe ( "YouTube VideoID validation - failing tests" , ( ) => {
55
+ for ( const testCase of badVideoIDs ) {
56
+ it ( `Should error on invalid videoID - ${ testCase [ 1 ] } ` , ( ) => {
57
+ assert . equal ( sanitize ( testCase [ 0 ] ) , null ) ;
58
+ } ) ;
59
+ }
60
+ } ) ;
61
+ describe ( "YouTube VideoID validation - passing tests" , ( ) => {
62
+ for ( const testCase of goodVideoIDs ) {
63
+ it ( `Should be able to sanitize good videoID - ${ testCase [ 1 ] } ` , ( ) => {
64
+ assert . equal ( sanitize ( testCase [ 0 ] ) , targetVideoID ) ;
65
+ } ) ;
66
+ }
67
+ } ) ;
68
+ describe ( "YouTube VideoID validation - edge cases tests" , ( ) => {
69
+ for ( const testCase of edgeVideoIDs ) {
70
+ it ( `edge cases produce bad results - ${ testCase [ 1 ] } ` , ( ) => {
71
+ assert . ok ( sanitize ( testCase [ 0 ] ) ) ;
72
+ } ) ;
73
+ }
74
+ } ) ;
75
+
76
+ // stubs
77
+ const mode = "production" ;
78
+ let stub : sinon . SinonStub ;
79
+
80
+ // constants
81
+ const endpoint = "/api/skipSegments" ;
82
+ const userID = "postVideoID_user1" ;
83
+ const expectedError = `No valid videoID. YouTube videoID could not be extracted` ;
84
+
85
+
86
+ // helper functions
87
+ const postSkipSegments = ( videoID : string ) => client ( {
88
+ method : "POST" ,
89
+ url : endpoint ,
90
+ params : {
91
+ videoID,
92
+ startTime : Math . random ( ) ,
93
+ endTime : 10 ,
94
+ userID,
95
+ service : "YouTube" ,
96
+ category : "sponsor"
97
+ }
98
+ } ) ;
99
+
100
+ describe ( "VideoID Validation - postSkipSegments" , ( ) => {
101
+ before ( ( ) => stub = sinon . stub ( config , "mode" ) . value ( mode ) ) ;
102
+ after ( ( ) => stub . restore ( ) ) ;
103
+
104
+ it ( "Should return production mode if stub worked" , ( done ) => {
105
+ assert . strictEqual ( config . mode , mode ) ;
106
+ done ( ) ;
107
+ } ) ;
108
+
109
+ it ( `Should return 400 for invalid videoID` , ( done ) => {
110
+ postSkipSegments ( "123456" ) . then ( res => {
111
+ assert . strictEqual ( res . status , 400 ) ;
112
+ assert . strictEqual ( res . data , expectedError ) ;
113
+ done ( ) ;
114
+ } )
115
+ . catch ( err => done ( err ) ) ;
116
+ } ) ;
117
+
118
+ it ( `Should return 200 for valid videoID` , ( done ) => {
119
+ postSkipSegments ( "dQw4w9WgXcQ" ) . then ( res => {
120
+ assert . strictEqual ( res . status , 200 ) ;
121
+ done ( ) ;
122
+ } )
123
+ . catch ( err => done ( err ) ) ;
124
+ } ) ;
125
+ } ) ;
0 commit comments