@editframe/elements 0.17.6-beta.0 → 0.18.3-beta.0
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.
- package/dist/EF_FRAMEGEN.js +1 -1
- package/dist/ScrubTrackManager.d.ts +2 -2
- package/dist/elements/EFAudio.d.ts +21 -2
- package/dist/elements/EFAudio.js +41 -11
- package/dist/elements/EFImage.d.ts +1 -0
- package/dist/elements/EFImage.js +11 -3
- package/dist/elements/EFMedia/AssetIdMediaEngine.d.ts +18 -0
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +41 -0
- package/dist/elements/EFMedia/AssetMediaEngine.d.ts +47 -0
- package/dist/elements/EFMedia/AssetMediaEngine.js +116 -0
- package/dist/elements/EFMedia/BaseMediaEngine.d.ts +55 -0
- package/dist/elements/EFMedia/BaseMediaEngine.js +96 -0
- package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +43 -0
- package/dist/elements/EFMedia/BufferedSeekingInput.js +159 -0
- package/dist/elements/EFMedia/JitMediaEngine.browsertest.d.ts +0 -0
- package/dist/elements/EFMedia/JitMediaEngine.d.ts +31 -0
- package/dist/elements/EFMedia/JitMediaEngine.js +62 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.d.ts +16 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +48 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.d.ts +3 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +138 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +16 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.d.ts +3 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +22 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.d.ts +7 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +24 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +18 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.d.ts +4 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +16 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.d.ts +3 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +104 -0
- package/dist/elements/EFMedia/services/AudioElementFactory.d.ts +22 -0
- package/dist/elements/EFMedia/services/AudioElementFactory.js +72 -0
- package/dist/elements/EFMedia/services/MediaSourceService.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia/services/MediaSourceService.d.ts +47 -0
- package/dist/elements/EFMedia/services/MediaSourceService.js +73 -0
- package/dist/elements/EFMedia/shared/AudioSpanUtils.d.ts +7 -0
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +54 -0
- package/dist/elements/EFMedia/shared/BufferUtils.d.ts +70 -0
- package/dist/elements/EFMedia/shared/BufferUtils.js +89 -0
- package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +23 -0
- package/dist/elements/EFMedia/shared/RenditionHelpers.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia/shared/RenditionHelpers.d.ts +19 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.d.ts +18 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +60 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.test.d.ts +1 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +16 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +46 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.js +16 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.d.ts +3 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.js +27 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.d.ts +7 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.js +25 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.js +18 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.js +16 -0
- package/dist/elements/EFMedia.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia.d.ts +75 -111
- package/dist/elements/EFMedia.js +141 -1111
- package/dist/elements/EFTemporal.d.ts +1 -1
- package/dist/elements/EFTemporal.js +1 -1
- package/dist/elements/EFTimegroup.d.ts +11 -0
- package/dist/elements/EFTimegroup.js +88 -13
- package/dist/elements/EFVideo.d.ts +60 -29
- package/dist/elements/EFVideo.js +103 -203
- package/dist/elements/EFWaveform.js +2 -2
- package/dist/elements/SampleBuffer.d.ts +14 -0
- package/dist/elements/SampleBuffer.js +52 -0
- package/dist/getRenderInfo.d.ts +2 -2
- package/dist/getRenderInfo.js +2 -1
- package/dist/gui/ContextMixin.js +17 -70
- package/dist/gui/EFFilmstrip.d.ts +3 -3
- package/dist/gui/EFFilmstrip.js +1 -1
- package/dist/gui/EFFitScale.d.ts +2 -2
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/services/ElementConnectionManager.browsertest.d.ts +1 -0
- package/dist/gui/services/ElementConnectionManager.d.ts +59 -0
- package/dist/gui/services/ElementConnectionManager.js +128 -0
- package/dist/gui/services/PlaybackController.browsertest.d.ts +1 -0
- package/dist/gui/services/PlaybackController.d.ts +103 -0
- package/dist/gui/services/PlaybackController.js +290 -0
- package/dist/services/MediaSourceManager.d.ts +62 -0
- package/dist/services/MediaSourceManager.js +211 -0
- package/dist/style.css +1 -1
- package/dist/transcoding/cache/CacheManager.d.ts +73 -0
- package/dist/transcoding/cache/RequestDeduplicator.d.ts +29 -0
- package/dist/transcoding/cache/RequestDeduplicator.js +53 -0
- package/dist/transcoding/cache/RequestDeduplicator.test.d.ts +1 -0
- package/dist/transcoding/types/index.d.ts +242 -0
- package/dist/transcoding/utils/MediaUtils.d.ts +9 -0
- package/dist/transcoding/utils/UrlGenerator.d.ts +26 -0
- package/dist/transcoding/utils/UrlGenerator.js +45 -0
- package/dist/transcoding/utils/constants.d.ts +27 -0
- package/dist/utils/LRUCache.d.ts +34 -0
- package/dist/utils/LRUCache.js +115 -0
- package/package.json +3 -2
- package/src/elements/EFAudio.browsertest.ts +183 -43
- package/src/elements/EFAudio.ts +59 -13
- package/src/elements/EFImage.browsertest.ts +42 -0
- package/src/elements/EFImage.ts +23 -3
- package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +222 -0
- package/src/elements/EFMedia/AssetIdMediaEngine.ts +70 -0
- package/src/elements/EFMedia/AssetMediaEngine.ts +210 -0
- package/src/elements/EFMedia/BaseMediaEngine.test.ts +164 -0
- package/src/elements/EFMedia/BaseMediaEngine.ts +170 -0
- package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +400 -0
- package/src/elements/EFMedia/BufferedSeekingInput.ts +267 -0
- package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +165 -0
- package/src/elements/EFMedia/JitMediaEngine.ts +110 -0
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +554 -0
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +81 -0
- package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +241 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +59 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +23 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +55 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +35 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +42 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +34 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +23 -0
- package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +174 -0
- package/src/elements/EFMedia/services/AudioElementFactory.browsertest.ts +325 -0
- package/src/elements/EFMedia/services/AudioElementFactory.ts +119 -0
- package/src/elements/EFMedia/services/MediaSourceService.browsertest.ts +257 -0
- package/src/elements/EFMedia/services/MediaSourceService.ts +102 -0
- package/src/elements/EFMedia/shared/AudioSpanUtils.ts +128 -0
- package/src/elements/EFMedia/shared/BufferUtils.ts +310 -0
- package/src/elements/EFMedia/shared/MediaTaskUtils.ts +44 -0
- package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +247 -0
- package/src/elements/EFMedia/shared/RenditionHelpers.ts +79 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +128 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.test.ts +233 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +89 -0
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.ts +555 -0
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +79 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.ts +59 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.ts +23 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.ts +55 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInputTask.ts +45 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSeekTask.ts +44 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.ts +57 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.ts +32 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.ts +56 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.ts +23 -0
- package/src/elements/EFMedia.browsertest.ts +658 -265
- package/src/elements/EFMedia.ts +173 -1763
- package/src/elements/EFTemporal.ts +3 -4
- package/src/elements/EFTimegroup.browsertest.ts +6 -3
- package/src/elements/EFTimegroup.ts +152 -21
- package/src/elements/EFVideo.browsertest.ts +115 -37
- package/src/elements/EFVideo.ts +123 -452
- package/src/elements/EFWaveform.ts +1 -1
- package/src/elements/MediaController.ts +2 -12
- package/src/elements/SampleBuffer.ts +97 -0
- package/src/gui/ContextMixin.ts +23 -104
- package/src/gui/services/ElementConnectionManager.browsertest.ts +263 -0
- package/src/gui/services/ElementConnectionManager.ts +224 -0
- package/src/gui/services/PlaybackController.browsertest.ts +437 -0
- package/src/gui/services/PlaybackController.ts +521 -0
- package/src/services/MediaSourceManager.ts +333 -0
- package/src/transcoding/cache/CacheManager.ts +208 -0
- package/src/transcoding/cache/RequestDeduplicator.test.ts +170 -0
- package/src/transcoding/cache/RequestDeduplicator.ts +65 -0
- package/src/transcoding/types/index.ts +265 -0
- package/src/transcoding/utils/MediaUtils.ts +63 -0
- package/src/transcoding/utils/UrlGenerator.ts +68 -0
- package/src/transcoding/utils/constants.ts +36 -0
- package/src/utils/LRUCache.ts +153 -0
- package/test/EFVideo.framegen.browsertest.ts +38 -29
- package/test/__cache__/GET__api_v1_transcode_audio_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__32da3954ba60c96ad732020c65a08ebc/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__32da3954ba60c96ad732020c65a08ebc/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__b0b2b07efcf607de8ee0f650328c32f7/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__b0b2b07efcf607de8ee0f650328c32f7/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a75c2252b542e0c152c780e9a8d7b154/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a75c2252b542e0c152c780e9a8d7b154/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a64ff1cfb1b52cae14df4b5dfa1e222b/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a64ff1cfb1b52cae14df4b5dfa1e222b/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__91e8a522f950809b9f09f4173113b4b0/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__91e8a522f950809b9f09f4173113b4b0/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_audio_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__e66d2c831d951e74ad0aeaa6489795d0/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_audio_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__e66d2c831d951e74ad0aeaa6489795d0/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0b3b2b1c8933f7fcf8a9ecaa88d58b41/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0b3b2b1c8933f7fcf8a9ecaa88d58b41/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_high_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0798c479b44aaeef850609a430f6e613/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0798c479b44aaeef850609a430f6e613/metadata.json +21 -0
- package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/data.bin +1 -0
- package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/metadata.json +19 -0
- package/test/createJitTestClips.ts +320 -188
- package/test/recordReplayProxyPlugin.js +302 -0
- package/test/useAssetMSW.ts +1 -1
- package/test/useMSW.ts +35 -22
- package/types.json +1 -1
- package/dist/JitTranscodingClient.d.ts +0 -167
- package/dist/JitTranscodingClient.js +0 -373
- package/dist/ScrubTrackManager.js +0 -216
- package/dist/elements/printTaskStatus.js +0 -11
- package/src/elements/__screenshots__/EFMedia.browsertest.ts/EFMedia-JIT-audio-playback-audioBufferTask-should-work-in-JIT-mode-without-URL-errors-1.png +0 -0
- package/test/EFVideo.frame-tasks.browsertest.ts +0 -524
- /package/dist/{JitTranscodingClient.browsertest.d.ts → elements/EFMedia/AssetIdMediaEngine.test.d.ts} +0 -0
- /package/dist/{JitTranscodingClient.test.d.ts → elements/EFMedia/BaseMediaEngine.test.d.ts} +0 -0
- /package/dist/{ScrubTrackIntegration.test.d.ts → elements/EFMedia/BufferedSeekingInput.browsertest.d.ts} +0 -0
- /package/dist/{SegmentSwitchLoading.test.d.ts → elements/EFMedia/services/AudioElementFactory.browsertest.d.ts} +0 -0
|
@@ -1,524 +0,0 @@
|
|
|
1
|
-
import { TaskStatus } from "@lit/task";
|
|
2
|
-
import { html, render } from "lit";
|
|
3
|
-
import { assert, beforeEach, describe, expect, test } from "vitest";
|
|
4
|
-
import "../src/elements/EFVideo.js";
|
|
5
|
-
import "../src/elements/EFTimegroup.js";
|
|
6
|
-
import type { EFTimegroup } from "../src/elements/EFTimegroup.js";
|
|
7
|
-
import type { EFVideo } from "../src/elements/EFVideo.js";
|
|
8
|
-
import { assetMSWHandlers } from "./useAssetMSW.js";
|
|
9
|
-
import { useMSW } from "./useMSW.ts";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Test suite for robust frame task chain functionality.
|
|
13
|
-
* Validates that frame tasks either succeed with pixels or fail with descriptive errors.
|
|
14
|
-
*/
|
|
15
|
-
describe("EFVideo Frame Tasks", () => {
|
|
16
|
-
const worker = useMSW();
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
document.body.innerHTML = "";
|
|
20
|
-
|
|
21
|
-
// Set up centralized MSW handlers to proxy requests to test assets
|
|
22
|
-
worker.use(...assetMSWHandlers);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test("should properly track frame tasks during initial render", async () => {
|
|
26
|
-
const container = document.createElement("div");
|
|
27
|
-
render(
|
|
28
|
-
html`<ef-workbench>
|
|
29
|
-
<ef-timegroup mode="contain" style="width: 100px; height: 100px;">
|
|
30
|
-
<ef-video
|
|
31
|
-
src="/test-assets/media/bars-n-tone2.mp4"
|
|
32
|
-
mode="asset"
|
|
33
|
-
></ef-video>
|
|
34
|
-
</ef-timegroup>
|
|
35
|
-
</ef-workbench>`,
|
|
36
|
-
container,
|
|
37
|
-
);
|
|
38
|
-
document.body.appendChild(container);
|
|
39
|
-
|
|
40
|
-
const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
|
|
41
|
-
const video = container.querySelector("ef-video") as EFVideo;
|
|
42
|
-
|
|
43
|
-
await video.updateComplete;
|
|
44
|
-
|
|
45
|
-
// Verify task dependencies are properly set up
|
|
46
|
-
expect(video.fragmentIndexTask).toBeDefined();
|
|
47
|
-
expect(video.mediaSegmentsTask).toBeDefined();
|
|
48
|
-
expect(video.seekTask).toBeDefined();
|
|
49
|
-
expect(video.videoAssetTask).toBeDefined();
|
|
50
|
-
expect(video.paintTask).toBeDefined();
|
|
51
|
-
|
|
52
|
-
timegroup.currentTimeMs = 1000;
|
|
53
|
-
await timegroup.updateComplete;
|
|
54
|
-
|
|
55
|
-
// Check if we can successfully render when avoiding concurrency conflicts
|
|
56
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
await video.paintTask.run();
|
|
60
|
-
|
|
61
|
-
// Verify frame was actually rendered OR we get proper error
|
|
62
|
-
const canvas = video.canvasRef.value;
|
|
63
|
-
assert.ok(canvas, "Canvas should exist");
|
|
64
|
-
|
|
65
|
-
const ctx = canvas.getContext("2d");
|
|
66
|
-
assert.ok(ctx, "Canvas context should exist");
|
|
67
|
-
|
|
68
|
-
// Either we have pixels OR we expect the video system is working correctly
|
|
69
|
-
// (based on seeing DECODED FRAME traces in test output)
|
|
70
|
-
expect(canvas.width).toBeGreaterThan(0);
|
|
71
|
-
expect(canvas.height).toBeGreaterThan(0);
|
|
72
|
-
} catch (error) {
|
|
73
|
-
// This is expected when decoder lock prevents concurrent access
|
|
74
|
-
const errorMessage =
|
|
75
|
-
error instanceof Error ? error.message : String(error);
|
|
76
|
-
|
|
77
|
-
if (errorMessage.includes("decoder is currently in use")) {
|
|
78
|
-
// Verify error message is descriptive and actionable
|
|
79
|
-
expect(errorMessage).toContain("Frame rendering failed");
|
|
80
|
-
expect(errorMessage).toContain("decoder is currently in use");
|
|
81
|
-
expect(errorMessage).toContain("concurrency issue");
|
|
82
|
-
} else {
|
|
83
|
-
throw error;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("should validate task dependency chain completion order", async () => {
|
|
89
|
-
const container = document.createElement("div");
|
|
90
|
-
render(
|
|
91
|
-
html`<ef-workbench>
|
|
92
|
-
<ef-timegroup mode="contain" style="width: 100px; height: 100px;">
|
|
93
|
-
<ef-video
|
|
94
|
-
src="/test-assets/media/bars-n-tone2.mp4"
|
|
95
|
-
mode="asset"
|
|
96
|
-
></ef-video>
|
|
97
|
-
</ef-timegroup>
|
|
98
|
-
</ef-workbench>`,
|
|
99
|
-
container,
|
|
100
|
-
);
|
|
101
|
-
document.body.appendChild(container);
|
|
102
|
-
|
|
103
|
-
const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
|
|
104
|
-
const video = container.querySelector("ef-video") as EFVideo;
|
|
105
|
-
|
|
106
|
-
await video.updateComplete;
|
|
107
|
-
|
|
108
|
-
// Track task completion order
|
|
109
|
-
const completionOrder: string[] = [];
|
|
110
|
-
const taskMap = {
|
|
111
|
-
assetIndexLoader: video.assetIndexLoader,
|
|
112
|
-
fragmentIndexTask: video.fragmentIndexTask,
|
|
113
|
-
mediaSegmentsTask: video.mediaSegmentsTask,
|
|
114
|
-
seekTask: video.seekTask,
|
|
115
|
-
videoAssetTask: video.videoAssetTask,
|
|
116
|
-
paintTask: video.paintTask,
|
|
117
|
-
frameTask: video.frameTask,
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
for (const [name, task] of Object.entries(taskMap)) {
|
|
121
|
-
task.taskComplete
|
|
122
|
-
.then(() => {
|
|
123
|
-
completionOrder.push(name);
|
|
124
|
-
})
|
|
125
|
-
.catch(() => {
|
|
126
|
-
// Tasks may fail due to concurrency, but still track completion
|
|
127
|
-
completionOrder.push(name);
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
timegroup.currentTimeMs = 1000;
|
|
132
|
-
await timegroup.updateComplete;
|
|
133
|
-
|
|
134
|
-
// Wait for tasks with error handling
|
|
135
|
-
await Promise.allSettled(
|
|
136
|
-
Object.values(taskMap).map((task) => task.taskComplete),
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
// Validate dependency order constraints if tasks completed
|
|
140
|
-
if (completionOrder.length >= 4) {
|
|
141
|
-
const getIndex = (taskName: string) => completionOrder.indexOf(taskName);
|
|
142
|
-
|
|
143
|
-
// Only test order relationships for tasks that actually completed
|
|
144
|
-
if (
|
|
145
|
-
getIndex("assetIndexLoader") >= 0 &&
|
|
146
|
-
getIndex("fragmentIndexTask") >= 0
|
|
147
|
-
) {
|
|
148
|
-
expect(getIndex("assetIndexLoader")).toBeLessThan(
|
|
149
|
-
getIndex("fragmentIndexTask"),
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
if (getIndex("fragmentIndexTask") >= 0 && getIndex("seekTask") >= 0) {
|
|
153
|
-
expect(getIndex("fragmentIndexTask")).toBeLessThan(
|
|
154
|
-
getIndex("seekTask"),
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
if (getIndex("mediaSegmentsTask") >= 0 && getIndex("seekTask") >= 0) {
|
|
158
|
-
expect(getIndex("mediaSegmentsTask")).toBeLessThan(
|
|
159
|
-
getIndex("seekTask"),
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Verify prerequisite tasks at least started properly
|
|
165
|
-
expect(video.fragmentIndexTask.status).toBeGreaterThanOrEqual(
|
|
166
|
-
TaskStatus.PENDING,
|
|
167
|
-
);
|
|
168
|
-
expect(video.mediaSegmentsTask.status).toBeGreaterThanOrEqual(
|
|
169
|
-
TaskStatus.PENDING,
|
|
170
|
-
);
|
|
171
|
-
expect(video.videoAssetTask.status).toBeGreaterThanOrEqual(
|
|
172
|
-
TaskStatus.PENDING,
|
|
173
|
-
);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
test("should throw descriptive errors instead of silent failures", async () => {
|
|
177
|
-
const container = document.createElement("div");
|
|
178
|
-
render(
|
|
179
|
-
html`<ef-workbench>
|
|
180
|
-
<ef-timegroup mode="contain" style="width: 100px; height: 100px;">
|
|
181
|
-
<ef-video
|
|
182
|
-
src="/test-assets/media/bars-n-tone2.mp4"
|
|
183
|
-
mode="asset"
|
|
184
|
-
></ef-video>
|
|
185
|
-
</ef-timegroup>
|
|
186
|
-
</ef-workbench>`,
|
|
187
|
-
container,
|
|
188
|
-
);
|
|
189
|
-
document.body.appendChild(container);
|
|
190
|
-
|
|
191
|
-
const video = container.querySelector("ef-video") as EFVideo;
|
|
192
|
-
await video.updateComplete;
|
|
193
|
-
|
|
194
|
-
// Wait for video asset to be available
|
|
195
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
196
|
-
|
|
197
|
-
// Test case 1: Missing video asset should throw descriptive error
|
|
198
|
-
const originalVideoAssetTask = video.videoAssetTask;
|
|
199
|
-
Object.defineProperty(video, "videoAssetTask", {
|
|
200
|
-
get: () => ({
|
|
201
|
-
...originalVideoAssetTask,
|
|
202
|
-
value: null,
|
|
203
|
-
taskComplete: Promise.resolve(),
|
|
204
|
-
}),
|
|
205
|
-
configurable: true,
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
try {
|
|
209
|
-
await video.paintTask.run();
|
|
210
|
-
// If we get here without error, that's actually OK - it means the error checking
|
|
211
|
-
// prevented the operation rather than failing silently
|
|
212
|
-
expect(true).toBe(true); // Test passes - no silent failure
|
|
213
|
-
} catch (error) {
|
|
214
|
-
// Good - we got an error instead of silent failure
|
|
215
|
-
expect(error.message).toBeDefined();
|
|
216
|
-
expect(typeof error.message).toBe("string");
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Restore original
|
|
220
|
-
Object.defineProperty(video, "videoAssetTask", {
|
|
221
|
-
get: () => originalVideoAssetTask,
|
|
222
|
-
configurable: true,
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
// Test case 2: Canvas context error should throw descriptive error
|
|
226
|
-
const canvas = video.canvasRef.value;
|
|
227
|
-
if (canvas) {
|
|
228
|
-
const originalGetContext = canvas.getContext;
|
|
229
|
-
canvas.getContext = () => null;
|
|
230
|
-
|
|
231
|
-
try {
|
|
232
|
-
await video.paintTask.run();
|
|
233
|
-
// If we get here, that's OK - means error was prevented
|
|
234
|
-
expect(true).toBe(true);
|
|
235
|
-
} catch (error) {
|
|
236
|
-
// Good - we got an error instead of silent failure
|
|
237
|
-
expect(error.message).toBeDefined();
|
|
238
|
-
expect(typeof error.message).toBe("string");
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
canvas.getContext = originalGetContext;
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
test("should handle concurrent paintTask execution properly", async () => {
|
|
246
|
-
const container = document.createElement("div");
|
|
247
|
-
render(
|
|
248
|
-
html`<ef-workbench>
|
|
249
|
-
<ef-timegroup mode="contain" style="width: 100px; height: 100px;">
|
|
250
|
-
<ef-video
|
|
251
|
-
src="/test-assets/media/bars-n-tone2.mp4"
|
|
252
|
-
mode="asset"
|
|
253
|
-
></ef-video>
|
|
254
|
-
</ef-timegroup>
|
|
255
|
-
</ef-workbench>`,
|
|
256
|
-
container,
|
|
257
|
-
);
|
|
258
|
-
document.body.appendChild(container);
|
|
259
|
-
|
|
260
|
-
const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
|
|
261
|
-
const video = container.querySelector("ef-video") as EFVideo;
|
|
262
|
-
|
|
263
|
-
await video.updateComplete;
|
|
264
|
-
|
|
265
|
-
// Test case 1: Trigger multiple paint operations simultaneously
|
|
266
|
-
const times = [500, 1000, 1500, 2000];
|
|
267
|
-
const paintPromises: Promise<any>[] = [];
|
|
268
|
-
|
|
269
|
-
for (const time of times) {
|
|
270
|
-
timegroup.currentTimeMs = time;
|
|
271
|
-
await timegroup.updateComplete;
|
|
272
|
-
|
|
273
|
-
paintPromises.push(
|
|
274
|
-
video.paintTask.run().catch((error) => {
|
|
275
|
-
return { error, time };
|
|
276
|
-
}),
|
|
277
|
-
);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const results = await Promise.allSettled(paintPromises);
|
|
281
|
-
|
|
282
|
-
let successCount = 0;
|
|
283
|
-
let failureCount = 0;
|
|
284
|
-
let totalAttempts = 0;
|
|
285
|
-
|
|
286
|
-
for (let i = 0; i < results.length; i++) {
|
|
287
|
-
const result = results[i];
|
|
288
|
-
totalAttempts++;
|
|
289
|
-
|
|
290
|
-
if (result.status === "fulfilled") {
|
|
291
|
-
if (result.value?.error) {
|
|
292
|
-
failureCount++;
|
|
293
|
-
} else {
|
|
294
|
-
successCount++;
|
|
295
|
-
}
|
|
296
|
-
} else {
|
|
297
|
-
failureCount++;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Expect that we attempted multiple operations
|
|
302
|
-
expect(totalAttempts).toBeGreaterThan(0);
|
|
303
|
-
|
|
304
|
-
// Either we had successes OR failures - no silent undefined returns
|
|
305
|
-
expect(successCount + failureCount).toBe(totalAttempts);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
test.skip("should understand why concurrent paint operations occur", async () => {
|
|
309
|
-
const container = document.createElement("div");
|
|
310
|
-
render(
|
|
311
|
-
html`<ef-workbench>
|
|
312
|
-
<ef-timegroup mode="contain" style="width: 100px; height: 100px;">
|
|
313
|
-
<ef-video
|
|
314
|
-
src="/test-assets/media/bars-n-tone2.mp4"
|
|
315
|
-
mode="asset"
|
|
316
|
-
></ef-video>
|
|
317
|
-
</ef-timegroup>
|
|
318
|
-
</ef-workbench>`,
|
|
319
|
-
container,
|
|
320
|
-
);
|
|
321
|
-
document.body.appendChild(container);
|
|
322
|
-
|
|
323
|
-
const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
|
|
324
|
-
const video = container.querySelector("ef-video") as EFVideo;
|
|
325
|
-
|
|
326
|
-
await video.updateComplete;
|
|
327
|
-
|
|
328
|
-
// Test case 1: Single time change (should work fine)
|
|
329
|
-
timegroup.currentTimeMs = 1000;
|
|
330
|
-
await timegroup.updateComplete;
|
|
331
|
-
|
|
332
|
-
try {
|
|
333
|
-
await timegroup.waitForFrameTasks();
|
|
334
|
-
} catch (error) {
|
|
335
|
-
// Single time change may still fail due to natural concurrency
|
|
336
|
-
expect(error.message).toContain("decoder is currently in use");
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// Test case 2: Manual paintTask.run() vs natural task flow
|
|
340
|
-
timegroup.currentTimeMs = 2000;
|
|
341
|
-
await timegroup.updateComplete;
|
|
342
|
-
|
|
343
|
-
try {
|
|
344
|
-
await video.paintTask.run();
|
|
345
|
-
} catch (error) {
|
|
346
|
-
// Expected when manual paintTask.run() conflicts with natural task execution
|
|
347
|
-
expect(error.message).toContain("decoder is currently in use");
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Test case 3: Rapid time changes (simulating user scrubbing)
|
|
351
|
-
const rapidTimes = [3000, 3500, 4000, 4500];
|
|
352
|
-
for (const time of rapidTimes) {
|
|
353
|
-
timegroup.currentTimeMs = time;
|
|
354
|
-
await timegroup.updateComplete;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
358
|
-
|
|
359
|
-
await expect(timegroup.getPendingFrameTasks()).resolves.toHaveLength(0);
|
|
360
|
-
expect(timegroup.currentTimeMs).toBe(4500);
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
test("should validate paint success vs task completion", async () => {
|
|
364
|
-
const container = document.createElement("div");
|
|
365
|
-
render(
|
|
366
|
-
html`<ef-workbench>
|
|
367
|
-
<ef-timegroup mode="contain" style="width: 100px; height: 100px;">
|
|
368
|
-
<ef-video
|
|
369
|
-
src="/test-assets/media/bars-n-tone2.mp4"
|
|
370
|
-
mode="asset"
|
|
371
|
-
></ef-video>
|
|
372
|
-
</ef-timegroup>
|
|
373
|
-
</ef-workbench>`,
|
|
374
|
-
container,
|
|
375
|
-
);
|
|
376
|
-
document.body.appendChild(container);
|
|
377
|
-
|
|
378
|
-
const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
|
|
379
|
-
const video = container.querySelector("ef-video") as EFVideo;
|
|
380
|
-
|
|
381
|
-
await video.updateComplete;
|
|
382
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
383
|
-
|
|
384
|
-
// Verify prerequisite tasks complete successfully
|
|
385
|
-
expect(video.fragmentIndexTask.status).toBe(TaskStatus.COMPLETE);
|
|
386
|
-
expect(video.mediaSegmentsTask.status).toBe(TaskStatus.COMPLETE);
|
|
387
|
-
expect(video.seekTask.status).toBe(TaskStatus.COMPLETE);
|
|
388
|
-
expect(video.videoAssetTask.status).toBe(TaskStatus.COMPLETE);
|
|
389
|
-
|
|
390
|
-
// Verify all have actual values
|
|
391
|
-
expect(video.fragmentIndexTask.value).toBeTruthy();
|
|
392
|
-
expect(video.mediaSegmentsTask.value).toBeTruthy();
|
|
393
|
-
expect(video.seekTask.value).toBeTruthy();
|
|
394
|
-
expect(video.videoAssetTask.value).toBeTruthy();
|
|
395
|
-
|
|
396
|
-
// Check canvas state
|
|
397
|
-
const canvas = video.canvasRef.value;
|
|
398
|
-
const hasCanvas = !!canvas;
|
|
399
|
-
let hasContext = false;
|
|
400
|
-
|
|
401
|
-
if (canvas) {
|
|
402
|
-
const ctx = canvas.getContext("2d");
|
|
403
|
-
hasContext = !!ctx;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
expect(hasCanvas).toBe(true);
|
|
407
|
-
expect(hasContext).toBe(true);
|
|
408
|
-
|
|
409
|
-
// Set a specific time and try to paint
|
|
410
|
-
timegroup.currentTimeMs = 5000;
|
|
411
|
-
await timegroup.updateComplete;
|
|
412
|
-
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
413
|
-
|
|
414
|
-
try {
|
|
415
|
-
const paintResult = await video.paintTask.run();
|
|
416
|
-
|
|
417
|
-
// If paint succeeds, verify we got a meaningful result
|
|
418
|
-
if (paintResult !== undefined && paintResult !== false) {
|
|
419
|
-
expect(paintResult).toBeTruthy();
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// Check if pixels were actually rendered
|
|
423
|
-
if (canvas && hasContext) {
|
|
424
|
-
expect(canvas.width).toBeGreaterThan(0);
|
|
425
|
-
expect(canvas.height).toBeGreaterThan(0);
|
|
426
|
-
}
|
|
427
|
-
} catch (error) {
|
|
428
|
-
// Expected concurrency error or other valid error
|
|
429
|
-
expect(error.message).toBeDefined();
|
|
430
|
-
expect(typeof error.message).toBe("string");
|
|
431
|
-
}
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
test("should diagnose exact rendering issue", async () => {
|
|
435
|
-
const container = document.createElement("div");
|
|
436
|
-
render(
|
|
437
|
-
html`<ef-workbench>
|
|
438
|
-
<ef-timegroup mode="contain" style="width: 100px; height: 100px;">
|
|
439
|
-
<ef-video
|
|
440
|
-
src="/test-assets/media/bars-n-tone2.mp4"
|
|
441
|
-
mode="asset"
|
|
442
|
-
></ef-video>
|
|
443
|
-
</ef-timegroup>
|
|
444
|
-
</ef-workbench>`,
|
|
445
|
-
container,
|
|
446
|
-
);
|
|
447
|
-
document.body.appendChild(container);
|
|
448
|
-
|
|
449
|
-
const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
|
|
450
|
-
const video = container.querySelector("ef-video") as EFVideo;
|
|
451
|
-
|
|
452
|
-
await video.updateComplete;
|
|
453
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
454
|
-
|
|
455
|
-
// Verify prerequisite task states
|
|
456
|
-
expect(video.fragmentIndexTask.status).toBe(TaskStatus.COMPLETE);
|
|
457
|
-
expect(video.mediaSegmentsTask.status).toBe(TaskStatus.COMPLETE);
|
|
458
|
-
expect(video.seekTask.status).toBe(TaskStatus.COMPLETE);
|
|
459
|
-
expect(video.videoAssetTask.status).toBe(TaskStatus.COMPLETE);
|
|
460
|
-
|
|
461
|
-
// Set time for rendering
|
|
462
|
-
timegroup.currentTimeMs = 1000;
|
|
463
|
-
await timegroup.updateComplete;
|
|
464
|
-
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
465
|
-
|
|
466
|
-
const canvas = video.canvasRef.value;
|
|
467
|
-
assert.ok(canvas, "Canvas should exist");
|
|
468
|
-
|
|
469
|
-
try {
|
|
470
|
-
await video.paintTask.run();
|
|
471
|
-
|
|
472
|
-
// Check pixel state after paint
|
|
473
|
-
const ctx = canvas.getContext("2d");
|
|
474
|
-
if (ctx) {
|
|
475
|
-
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
476
|
-
const hasPixelsAfter = imageData.data.some((pixel) => pixel !== 0);
|
|
477
|
-
|
|
478
|
-
if (!hasPixelsAfter) {
|
|
479
|
-
// Check if videoAsset has frames
|
|
480
|
-
const videoAsset = video.videoAssetTask.value;
|
|
481
|
-
if (videoAsset) {
|
|
482
|
-
expect(typeof videoAsset.seekToTime).toBe("function");
|
|
483
|
-
|
|
484
|
-
// Try to manually get a frame
|
|
485
|
-
try {
|
|
486
|
-
const frame = await videoAsset.seekToTime(1.0);
|
|
487
|
-
expect(frame).toBeTruthy();
|
|
488
|
-
|
|
489
|
-
if (frame) {
|
|
490
|
-
expect(frame.format).toBeDefined();
|
|
491
|
-
expect(frame.codedWidth).toBeGreaterThan(0);
|
|
492
|
-
expect(frame.codedHeight).toBeGreaterThan(0);
|
|
493
|
-
|
|
494
|
-
// Try manual drawImage
|
|
495
|
-
ctx.drawImage(frame, 0, 0, canvas.width, canvas.height);
|
|
496
|
-
const imageDataAfterManual = ctx.getImageData(
|
|
497
|
-
0,
|
|
498
|
-
0,
|
|
499
|
-
canvas.width,
|
|
500
|
-
canvas.height,
|
|
501
|
-
);
|
|
502
|
-
const hasPixelsAfterManual = imageDataAfterManual.data.some(
|
|
503
|
-
(pixel) => pixel !== 0,
|
|
504
|
-
);
|
|
505
|
-
expect(hasPixelsAfterManual).toBe(true);
|
|
506
|
-
|
|
507
|
-
frame.close();
|
|
508
|
-
}
|
|
509
|
-
} catch (seekError) {
|
|
510
|
-
// seekToTime errors are acceptable in concurrent scenarios
|
|
511
|
-
expect(seekError.message).toContain(
|
|
512
|
-
"decoder is currently in use",
|
|
513
|
-
);
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
} else {
|
|
517
|
-
expect(hasPixelsAfter).toBe(true);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
} catch (error) {
|
|
521
|
-
expect(error.message).toContain("decoder is currently in use");
|
|
522
|
-
}
|
|
523
|
-
});
|
|
524
|
-
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|