test_texttrackcue.html (10940B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>Test for Bug 833386 - HTMLTrackElement</title> 5 <script src="/tests/SimpleTest/SimpleTest.js"></script> 6 <script type="text/javascript" src="manifest.js"></script> 7 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 8 </head> 9 <body> 10 <video id="v" src="seek.webm" preload="metadata"> 11 <track src="basic.vtt" kind="subtitles" id="default" default> 12 </video> 13 <script type="text/javascript"> 14 /** 15 * This test is used to test the VTTCue's different behaviors and check whether 16 * cues would be activatived correctly during video playback. 17 */ 18 var video = document.getElementById("v"); 19 var trackElement = document.getElementById("default"); 20 21 async function runTest() { 22 await waitUntiTrackLoaded(); 23 checkCueDefinition(); 24 checkFirstCueParsedContent(); 25 checkCueStartTimeAndEndtime(); 26 checkCueSizeAndPosition(); 27 checkCueSnapToLines(); 28 checkCueAlignmentAndWritingDirection(); 29 checkCueLine(); 30 checkCreatingNewCue(); 31 checkRemoveNonExistCue(); 32 checkActiveCues(); 33 checkCueRegion(); 34 await checkCActiveCuesDuringVideoPlaying(); 35 SimpleTest.finish(); 36 } 37 38 SimpleTest.waitForExplicitFinish(); 39 40 runTest(); 41 42 /** 43 * The following are test helper functions. 44 */ 45 async function waitUntiTrackLoaded() { 46 if (trackElement.readyState != 2) { 47 info(`wait until the track finishes loading`); 48 await once(trackElement, "load"); 49 } 50 is(trackElement.readyState, 2, "Track::ReadyState should be set to LOADED."); 51 is(trackElement.track.cues.length, 6, "Cue list length should be 6."); 52 } 53 54 function checkCueDefinition() { 55 // Check that the typedef of TextTrackCue works in Gecko. 56 isnot(window.TextTrackCue, undefined, "TextTrackCue should be defined."); 57 isnot(window.VTTCue, undefined, "VTTCue should be defined."); 58 } 59 60 function checkFirstCueParsedContent() { 61 // Check if first cue was parsed correctly. 62 const cue = trackElement.track.cues[0]; 63 ok(cue instanceof TextTrackCue, "Cue should be an instanceof TextTrackCue."); 64 ok(cue instanceof VTTCue, "Cue should be an instanceof VTTCue."); 65 is(cue.id, "1", "Cue's ID should be 1."); 66 is(cue.startTime, 0.5, "Cue's start time should be 0.5."); 67 is(cue.endTime, 0.7, "Cue's end time should be 0.7."); 68 is(cue.pauseOnExit, false, "Cue's pause on exit flag should be false."); 69 is(cue.text, "This", "Cue's text should be set correctly."); 70 is(cue.track, trackElement.track, "Cue's track should be defined."); 71 cue.track = null; 72 isnot(cue.track, null, "Cue's track should not be able to be set."); 73 } 74 75 function checkCueStartTimeAndEndtime() { 76 const cueList = trackElement.track.cues; 77 // Check that all cue times were not rounded 78 is(cueList[1].startTime, 1.2, "Second cue's start time should be 1.2."); 79 is(cueList[1].endTime, 2.4, "Second cue's end time should be 2.4."); 80 is(cueList[2].startTime, 2, "Third cue's start time should be 2."); 81 is(cueList[2].endTime, 3.5, "Third cue's end time should be 3.5."); 82 is(cueList[3].startTime, 2.71, "Fourth cue's start time should be 2.71."); 83 is(cueList[3].endTime, 2.91, "Fourth cue's end time should be 2.91."); 84 is(cueList[4].startTime, 3.217, "Fifth cue's start time should be 3.217."); 85 is(cueList[4].endTime, 3.989, "Fifth cue's end time should be 3.989."); 86 is(cueList[5].startTime, 3.217, "Sixth cue's start time should be 3.217."); 87 is(cueList[5].endTime, 3.989, "Sixth cue's end time should be 3.989."); 88 89 // Check that Cue setters are working correctly. 90 const cue = trackElement.track.cues[0]; 91 cue.id = "Cue 01"; 92 is(cue.id, "Cue 01", "Cue's ID should be 'Cue 01'."); 93 cue.startTime = 0.51; 94 is(cue.startTime, 0.51, "Cue's start time should be 0.51."); 95 cue.endTime = 0.71; 96 is(cue.endTime, 0.71, "Cue's end time should be 0.71."); 97 cue.pauseOnExit = true; 98 is(cue.pauseOnExit, true, "Cue's pause on exit flag should be true."); 99 video.addEventListener("pause", function() { 100 video.play(); 101 }, {once: true}); 102 } 103 104 function checkCueSizeAndPosition() { 105 function checkPercentageValue(prop, initialVal) { 106 ok(prop in cue, prop + " should be a property on VTTCue."); 107 cue[prop] = initialVal; 108 is(cue[prop], initialVal, `Cue's ${prop} should initially be ${initialVal}`); 109 [ 101, -1 ].forEach(function(val) { 110 let exceptionHappened = false; 111 try { 112 cue[prop] = val; 113 } catch(e) { 114 exceptionHappened = true; 115 is(e.name, "IndexSizeError", "Should have thrown IndexSizeError."); 116 } 117 ok(exceptionHappened, "Exception should have happened."); 118 }); 119 } 120 121 const cue = trackElement.track.cues[0]; 122 checkPercentageValue("size", 100.0); 123 cue.size = 50.5; 124 is(cue.size, 50.5, "Cue's size should be 50.5.") 125 126 // Check cue.position 127 checkPercentageValue("position", "auto"); 128 cue.position = 50.5; 129 is(cue.position, 50.5, "Cue's position value should now be 50.5."); 130 } 131 132 function checkCueSnapToLines() { 133 const cue = trackElement.track.cues[0]; 134 ok(cue.snapToLines, "Cue's snapToLines should be set by set."); 135 cue.snapToLines = false; 136 ok(!cue.snapToLines, "Cue's snapToLines should not be set."); 137 } 138 139 function checkCueAlignmentAndWritingDirection() { 140 function checkEnumValue(prop, initialVal, acceptedValues) { 141 ok(prop in cue, `${prop} should be a property on VTTCue.`); 142 is(cue[prop], initialVal, `Cue's ${prop} should be ${initialVal}`); 143 cue[prop] = "bogus"; 144 is(cue[prop], initialVal, `Cue's ${prop} should be ${initialVal}`); 145 acceptedValues.forEach(function(val) { 146 cue[prop] = val; 147 is(cue[prop], val, `Cue's ${prop} should be ${val}`); 148 if (typeof val === "string") { 149 cue[prop] = val.toUpperCase(); 150 is(cue[prop], val, `Cue's ${prop} should be ${val}`); 151 } 152 }); 153 } 154 155 const cue = trackElement.track.cues[0]; 156 checkEnumValue("align", "center", [ "start", "left", "center", "right", "end" ]); 157 checkEnumValue("lineAlign", "start", [ "start", "center", "end" ]); 158 checkEnumValue("vertical", "", [ "", "lr", "rl" ]); 159 160 cue.lineAlign = "center"; 161 is(cue.lineAlign, "center", "Cue's line align should be center."); 162 cue.lineAlign = "START"; 163 is(cue.lineAlign, "center", "Cue's line align should be center."); 164 cue.lineAlign = "end"; 165 is(cue.lineAlign, "end", "Cue's line align should be end."); 166 167 // Check that cue position align works properly 168 is(cue.positionAlign, "auto", "Cue's default position alignment should be auto."); 169 170 cue.positionAlign = "line-left"; 171 is(cue.positionAlign, "line-left", "Cue's position align should be line-left."); 172 cue.positionAlign = "auto"; 173 is(cue.positionAlign, "auto", "Cue's position align should be auto."); 174 cue.positionAlign = "line-right"; 175 is(cue.positionAlign, "line-right", "Cue's position align should be line-right."); 176 } 177 178 function checkCueLine() { 179 const cue = trackElement.track.cues[0]; 180 // Check cue.line 181 is(cue.line, "auto", "Cue's line value should initially be auto."); 182 cue.line = 0.5; 183 is(cue.line, 0.5, "Cue's line value should now be 0.5."); 184 cue.line = "auto"; 185 is(cue.line, "auto", "Cue's line value should now be auto."); 186 } 187 188 function checkCreatingNewCue() { 189 const cueList = trackElement.track.cues; 190 191 // Check that we can create and add new VTTCues 192 let vttCue = new VTTCue(3.999, 4, "foo"); 193 is(vttCue.track, null, "Cue's track should be null."); 194 trackElement.track.addCue(vttCue); 195 is(vttCue.track, trackElement.track, "Cue's track should be defined."); 196 is(cueList.length, 7, "Cue list length should now be 7."); 197 198 // Check that new VTTCue was added correctly 199 let cue = cueList[6]; 200 is(cue.startTime, 3.999, "Cue's start time should be 3.999."); 201 is(cue.endTime, 4, "Cue's end time should be 4."); 202 is(cue.text, "foo", "Cue's text should be foo."); 203 204 // Adding the same cue again should not increase the cue count. 205 trackElement.track.addCue(vttCue); 206 is(cueList.length, 7, "Cue list length should be 7."); 207 208 // Check that we are able to remove cues. 209 trackElement.track.removeCue(cue); 210 is(cueList.length, 6, "Cue list length should be 6."); 211 } 212 213 function checkRemoveNonExistCue() { 214 is(trackElement.track.cues.length, 6, "Cue list length should be 6."); 215 let exceptionHappened = false; 216 try { 217 // We should not be able to remove a cue that is not in the list. 218 trackElement.track.removeCue(new VTTCue(1, 2, "foo")); 219 } catch (e) { 220 // "NotFoundError" should be thrown when trying to remove a cue that is 221 // not in the list. 222 is(e.name, "NotFoundError", "Should have thrown NotFoundError."); 223 exceptionHappened = true; 224 } 225 // If this is false then we did not throw an error and probably removed a cue 226 // when we shouln't have. 227 ok(exceptionHappened, "Exception should have happened."); 228 is(trackElement.track.cues.length, 6, "Cue list length should still be 6."); 229 } 230 231 function checkActiveCues() { 232 video.currentTime = 2; 233 isnot(trackElement.track.activeCues, null); 234 235 trackElement.track.mode = "disabled"; 236 is(trackElement.track.activeCues, null, "No active cue when track is disabled."); 237 trackElement.track.mode = "showing"; 238 } 239 240 function checkCueRegion() { 241 let regionInfo = [ 242 { lines: 2, width: 30 }, 243 { lines: 4, width: 20 }, 244 { lines: 2, width: 30 } 245 ]; 246 247 for (let i = 0; i < regionInfo.length; i++) { 248 let cue = trackElement.track.cues[i]; 249 isnot(cue.region, null, `Cue at ${i} should have a region.`); 250 for (let key in regionInfo[i]) { 251 is(cue.region[key], regionInfo[i][key], 252 `Region should have a ${key} property with a value of ${regionInfo[i][key]}`); 253 } 254 } 255 } 256 257 async function checkCActiveCuesDuringVideoPlaying() { 258 // Test TextTrack::ActiveCues. 259 let cueInfo = [ 260 { startTime: 0.51, endTime: 0.71, ids: ["Cue 01"] }, 261 { startTime: 0.72, endTime: 1.19, ids: [] }, 262 { startTime: 1.2, endTime: 1.9, ids: [2] }, 263 { startTime: 2, endTime: 2.4, ids: [2, 2.5] }, 264 { startTime: 2.41, endTime: 2.70, ids: [2.5] }, 265 { startTime: 2.71, endTime: 2.91, ids: [2.5, 3] }, 266 { startTime: 2.92, endTime: 3.216, ids: [2.5] }, 267 { startTime: 3.217, endTime: 3.5, ids: [2.5, 4, 5] }, 268 { startTime: 3.51, endTime: 3.989, ids: [4, 5] }, 269 { startTime: 3.99, endTime: 4, ids: [] } 270 ]; 271 272 video.addEventListener("timeupdate", function() { 273 let activeCues = trackElement.track.activeCues, 274 playbackTime = video.currentTime; 275 276 for (let i = 0; i < cueInfo.length; i++) { 277 let cue = cueInfo[i]; 278 if (playbackTime >= cue.startTime && playbackTime < cue.endTime) { 279 is(activeCues.length, cue.ids.length, `There should be ${cue.ids.length} currently active cue(s).`); 280 for (let j = 0; j < cue.ids.length; j++) { 281 isnot(activeCues.getCueById(cue.ids[j]), undefined, 282 `The cue with ID ${cue.ids[j]} should be active.`); 283 } 284 break; 285 } 286 } 287 }); 288 289 info(`start video from 0s.`); 290 video.currentTime = 0; 291 video.play(); 292 await once(video, "playing"); 293 info(`video starts playing.`); 294 await once(video, "ended"); 295 } 296 297 </script> 298 </body> 299 </html>