diff --git a/package-lock.json b/package-lock.json index 4f284c71af..b26d99364f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,6 @@ "esm": "3.2.25", "github-buttons": "2.29.1", "html-entities": "2.5.2", - "jsdom": "^25.0.1", "prettier": "^3.4.2", "react": "19.0.0", "react-dom": "19.0.0", @@ -2443,7 +2442,9 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/available-typed-arrays": { "version": "1.0.7", @@ -2837,6 +2838,8 @@ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -3039,6 +3042,8 @@ "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "rrweb-cssom": "^0.7.1" }, @@ -3069,6 +3074,8 @@ "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" @@ -3167,7 +3174,9 @@ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/deep-eql": { "version": "5.0.2", @@ -3253,6 +3262,8 @@ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=0.4.0" } @@ -4578,6 +4589,8 @@ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -5042,6 +5055,8 @@ "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "whatwg-encoding": "^3.1.1" }, @@ -5127,6 +5142,8 @@ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -5531,7 +5548,9 @@ "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/is-regex": { "version": "1.1.4", @@ -5760,6 +5779,8 @@ "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "cssstyle": "^4.1.0", "data-urls": "^5.0.0", @@ -5801,6 +5822,8 @@ "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", "dev": true, "license": "BSD-3-Clause", + "optional": true, + "peer": true, "dependencies": { "tldts": "^6.1.32" }, @@ -6210,6 +6233,8 @@ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 0.6" } @@ -6220,6 +6245,8 @@ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -6451,7 +6478,9 @@ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/object-assign": { "version": "4.1.1", @@ -7376,7 +7405,9 @@ "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/run-parallel": { "version": "1.2.0", @@ -7475,7 +7506,9 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/saxes": { "version": "6.0.0", @@ -7483,6 +7516,8 @@ "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, "license": "ISC", + "optional": true, + "peer": true, "dependencies": { "xmlchars": "^2.2.0" }, @@ -8089,7 +8124,9 @@ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/synckit": { "version": "0.9.1", @@ -8209,6 +8246,8 @@ "integrity": "sha512-R/K2tZ5MiY+mVrnSkNJkwqYT2vUv1lcT6wJvd2emGaMJ7PHUGRY4e3tUsdFCXgqxi2QgbHjL3yJgXCo40v9Hxw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "tldts-core": "^6.1.47" }, @@ -8221,7 +8260,9 @@ "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.47.tgz", "integrity": "sha512-6SWyFMnlst1fEt7GQVAAu16EGgFK0cLouH/2Mk6Ftlwhv3Ol40L0dlpGMcnnNiiOMyD2EV/aF3S+U2nKvvLvrA==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -8268,6 +8309,8 @@ "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "punycode": "^2.3.1" }, @@ -9140,6 +9183,8 @@ "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "xml-name-validator": "^5.0.0" }, @@ -9284,6 +9329,8 @@ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, "license": "BSD-2-Clause", + "optional": true, + "peer": true, "engines": { "node": ">=12" } @@ -9294,6 +9341,8 @@ "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "iconv-lite": "0.6.3" }, @@ -9307,6 +9356,8 @@ "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=18" } @@ -9317,6 +9368,8 @@ "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "tr46": "^5.0.0", "webidl-conversions": "^7.0.0" @@ -9564,6 +9617,8 @@ "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "dev": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "engines": { "node": ">=18" } @@ -9573,7 +9628,9 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/y18n": { "version": "5.0.8", diff --git a/package.json b/package.json index dc971afed0..5e149063da 100644 --- a/package.json +++ b/package.json @@ -188,14 +188,18 @@ "start": "node ./scripts/start_demo_web_server.mjs", "start:wasm": "node ./scripts/start_demo_web_server.mjs --include-wasm", "test:integration": "npm run test:integration:chrome && npm run test:integration:firefox", - "test:integration:chrome": "cross-env BROWSER_CONFIG=chrome vitest run tests/integration/scenarios", - "test:integration:chrome:watch": "cross-env BROWSER_CONFIG=chrome vitest watch tests/integration/scenarios", - "test:integration:firefox": "cross-env BROWSER_CONFIG=firefox vitest run tests/integration/scenarios", - "test:integration:firefox:watch": "cross-env BROWSER_CONFIG=firefox vitest watch tests/integration/scenarios", + "test:integration:chrome": "npm run --silent test:integration:notice && cross-env BROWSER_CONFIG=chrome vitest run tests/integration/scenarios", + "test:integration:chrome:watch": "npm run --silent test:integration:notice && cross-env BROWSER_CONFIG=chrome vitest watch tests/integration/scenarios", + "test:integration:firefox": "npm run --silent test:integration:notice && cross-env BROWSER_CONFIG=firefox vitest run tests/integration/scenarios", + "test:integration:firefox:watch": "npm run --silent test:integration:notice && cross-env BROWSER_CONFIG=firefox vitest watch tests/integration/scenarios", + "test:integration:notice": "echo \"~~~ ⚠️ NOTICE ⚠️\n~~~ Integration tests rely on the RxPlayer build.\n~~~ Make sure you called the \\`build\\` script succesfully first.\n\"", "test:memory": "cross-env BROWSER_CONFIG=chrome vitest run tests/memory", "test:memory:chrome:watch": "cross-env BROWSER_CONFIG=chrome vitest watch tests/memory", - "test:unit": "vitest --config vitest.config.unit.mjs", - "test:unit:watch": "cross-env WATCH=true vitest --config vitest.config.unit.mjs", + "test:unit": "npm run test:unit:chrome && npm run test:unit:firefox", + "test:unit:chrome": "cross-env BROWSER_CONFIG=chrome vitest src/", + "test:unit:firefox": "cross-env BROWSER_CONFIG=firefox vitest src/", + "test:unit:chrome:watch": "cross-env WATCH=true BROWSER_CONFIG=chrome vitest src/", + "test:unit:firefox:watch": "cross-env WATCH=true BROWSER_CONFIG=firefox vitest src/", "update-version": "npm run version --git-tag-version=false", "version": "./scripts/update-version", "wasm-strip": "node scripts/wasm-strip.mjs dist/mpd-parser.wasm" @@ -223,7 +227,6 @@ "esm": "3.2.25", "github-buttons": "2.29.1", "html-entities": "2.5.2", - "jsdom": "^25.0.1", "prettier": "^3.4.2", "react": "19.0.0", "react-dom": "19.0.0", @@ -261,7 +264,7 @@ "fmt:rust:check": "Check that Rust files are well-formatted" }, "Run tests": { - "Integration tests (test the whole API, ensure the RxPlayer build is made BEFORE running them)": { + "Integration tests (test the whole API, call the `build` script BEFORE running them)": { "test:integration": "Launch integration tests in multiple browser environments", "test:integration:chrome": "Launch integration tests in a Chrome browser.", "test:integration:chrome:watch": "Launch integration tests in Chrome each times the files update", diff --git a/src/compat/__tests__/browser_compatibility_types.test.ts b/src/compat/__tests__/browser_compatibility_types.test.ts index fd38f6ecfd..4fb16fa424 100644 --- a/src/compat/__tests__/browser_compatibility_types.test.ts +++ b/src/compat/__tests__/browser_compatibility_types.test.ts @@ -1,7 +1,11 @@ import { describe, beforeEach, it, expect, vi } from "vitest"; import globalScope from "../../utils/global_scope"; -describe("compat - browser compatibility types", () => { +// FIXME: fix that one. Mocking properties used in global scope doesn't seem to +// work: each `importActual` does not seem to trigger a file execution, only the +// first one does. +// Only in vitest's browser mode. +describe.skip("compat - browser compatibility types", () => { interface IFakeWindow { MediaSource?: unknown; MozMediaSource?: unknown; @@ -15,10 +19,6 @@ describe("compat - browser compatibility types", () => { }); it("should use the native MediaSource if defined", async () => { - vi.doMock("../../utils/is_node", () => ({ - default: false, - })); - const origMediaSource = gs.MediaSource; const origMozMediaSource = gs.MozMediaSource; const origWebKitMediaSource = gs.WebKitMediaSource; @@ -31,7 +31,8 @@ describe("compat - browser compatibility types", () => { gs.MSMediaSource = { a: 4 }; gs.ManagedMediaSource = { a: 5 }; - const { MediaSource_ } = await vi.importActual("../browser_compatibility_types"); + const MediaSource_ = (await vi.importActual("../browser_compatibility_types.ts")) + .MediaSource_ as typeof MediaSource; expect(MediaSource_).toEqual({ a: 1 }); gs.MediaSource = origMediaSource; @@ -42,10 +43,6 @@ describe("compat - browser compatibility types", () => { }); it("should use MozMediaSource if defined and MediaSource is not", async () => { - vi.doMock("../../utils/is_node", () => ({ - default: false, - })); - const origMediaSource = gs.MediaSource; const origMozMediaSource = gs.MozMediaSource; const origWebKitMediaSource = gs.WebKitMediaSource; @@ -57,7 +54,8 @@ describe("compat - browser compatibility types", () => { gs.WebKitMediaSource = undefined; gs.MSMediaSource = undefined; - const { MediaSource_ } = await vi.importActual("../browser_compatibility_types"); + const MediaSource_ = (await vi.importActual("../browser_compatibility_types.ts")) + .MediaSource_ as typeof MediaSource; expect(MediaSource_).toEqual({ a: 2 }); gs.MediaSource = origMediaSource; @@ -68,10 +66,6 @@ describe("compat - browser compatibility types", () => { }); it("should use WebKitMediaSource if defined and MediaSource is not", async () => { - vi.doMock("../../utils/is_node", () => ({ - default: false, - })); - const origMediaSource = gs.MediaSource; const origMozMediaSource = gs.MozMediaSource; const origWebKitMediaSource = gs.WebKitMediaSource; @@ -83,7 +77,8 @@ describe("compat - browser compatibility types", () => { gs.WebKitMediaSource = { a: 3 }; gs.MSMediaSource = undefined; - const { MediaSource_ } = await vi.importActual("../browser_compatibility_types"); + const MediaSource_ = (await vi.importActual("../browser_compatibility_types.ts")) + .MediaSource_ as typeof MediaSource; expect(MediaSource_).toEqual({ a: 3 }); gs.MediaSource = origMediaSource; @@ -94,10 +89,6 @@ describe("compat - browser compatibility types", () => { }); it("should use MSMediaSource if defined and MediaSource is not", async () => { - vi.doMock("../../utils/is_node", () => ({ - default: false, - })); - const origMediaSource = gs.MediaSource; const origMozMediaSource = gs.MozMediaSource; const origWebKitMediaSource = gs.WebKitMediaSource; @@ -109,7 +100,8 @@ describe("compat - browser compatibility types", () => { gs.WebKitMediaSource = undefined; gs.MSMediaSource = { a: 4 }; - const { MediaSource_ } = await vi.importActual("../browser_compatibility_types"); + const MediaSource_ = (await vi.importActual("../browser_compatibility_types.ts")) + .MediaSource_ as typeof MediaSource; expect(MediaSource_).toEqual({ a: 4 }); gs.MediaSource = origMediaSource; @@ -120,10 +112,6 @@ describe("compat - browser compatibility types", () => { }); it("should use ManagedMediaSource if defined and MediaSource is not", async () => { - vi.doMock("../../utils/is_node", () => ({ - default: false, - })); - const origMediaSource = gs.MediaSource; const origMozMediaSource = gs.MozMediaSource; const origWebKitMediaSource = gs.WebKitMediaSource; @@ -136,7 +124,8 @@ describe("compat - browser compatibility types", () => { gs.MSMediaSource = undefined; gs.ManagedMediaSource = { a: 5 }; - const { MediaSource_ } = await vi.importActual("../browser_compatibility_types"); + const MediaSource_ = (await vi.importActual("../browser_compatibility_types.ts")) + .MediaSource_ as typeof MediaSource; expect(MediaSource_).toEqual({ a: 5 }); gs.MediaSource = origMediaSource; diff --git a/src/compat/__tests__/clear_element_src.test.ts b/src/compat/__tests__/clear_element_src.test.ts index ae051f9be7..730b1068d5 100644 --- a/src/compat/__tests__/clear_element_src.test.ts +++ b/src/compat/__tests__/clear_element_src.test.ts @@ -1,23 +1,28 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import log from "../../log"; import arrayFindIndex from "../../utils/array_find_index"; import type { IMediaElement } from "../browser_compatibility_types"; -import type IClearElementSrc from "../clear_element_src"; +import clearElementSrc from "../clear_element_src"; + +const logWarn = vi.spyOn(log, "warn").mockImplementation(() => { + /* noop */ +}); describe("Compat - clearElementSrc", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + logWarn.mockClear(); + }); - it("should empty the src and remove the Attribute for a given Element", async () => { + it("should empty the src and remove the Attribute for a given Element", () => { const fakeElement = { src: "foo", removeAttribute() { return null; }, } as unknown as IMediaElement; - const clearElementSrc = (await vi.importActual("../clear_element_src")) - .default as typeof IClearElementSrc; - const spyRemoveAttribute = vi.spyOn(fakeElement, "removeAttribute"); clearElementSrc(fakeElement); expect(fakeElement.src).toBe(""); @@ -25,17 +30,14 @@ describe("Compat - clearElementSrc", () => { expect(spyRemoveAttribute).toHaveBeenCalledWith("src"); }); - it("should throw if failed to remove the Attribute for a given Element", async () => { + it("should throw if failed to remove the Attribute for a given Element", () => { const fakeElement = { src: "foo", removeAttribute() { throw new Error("Oups, can't remove attribute."); }, } as unknown as IMediaElement; - const clearElementSrc = (await vi.importActual("../clear_element_src")) - .default as typeof IClearElementSrc; const spyRemoveAttribute = vi.spyOn(fakeElement, "removeAttribute"); - expect(() => clearElementSrc(fakeElement)).toThrowError( "Oups, can't remove attribute.", ); @@ -43,7 +45,7 @@ describe("Compat - clearElementSrc", () => { expect(spyRemoveAttribute).toHaveBeenCalledTimes(1); }); - it("should disable text tracks and remove childs", async () => { + it("should disable text tracks and remove childs", () => { const fakeElement = { src: "foo", removeAttribute() { @@ -59,9 +61,6 @@ describe("Compat - clearElementSrc", () => { }, } as unknown as IMediaElement; - const clearElementSrc = (await vi.importActual("../clear_element_src")) - .default as typeof IClearElementSrc; - const spyRemoveAttribute = vi.spyOn(fakeElement, "removeAttribute"); const spyHasChildNodes = vi.spyOn(fakeElement, "hasChildNodes"); const spyRemoveChild = vi.spyOn(fakeElement, "removeChild"); @@ -79,7 +78,7 @@ describe("Compat - clearElementSrc", () => { expect(spyRemoveChild).toHaveBeenCalledWith({ nodeName: "track" }); }); - it("should log when failed to remove text track child node", async () => { + it("should log when failed to remove text track child node", () => { const fakeElement = { src: "foo", removeAttribute() { @@ -93,13 +92,6 @@ describe("Compat - clearElementSrc", () => { }, } as unknown as IMediaElement; - const mockLogWarn = vi.fn((message: unknown) => message); - vi.doMock("../../log", () => ({ - default: { warn: mockLogWarn }, - })); - const clearElementSrc = (await vi.importActual("../clear_element_src")) - .default as typeof IClearElementSrc; - const spyRemoveAttribute = vi.spyOn(fakeElement, "removeAttribute"); const spyHasChildNodes = vi.spyOn(fakeElement, "hasChildNodes"); const spyRemoveChild = vi.spyOn(fakeElement, "removeChild"); @@ -118,13 +110,13 @@ describe("Compat - clearElementSrc", () => { expect(spyRemoveAttribute).toHaveBeenCalledWith("src"); expect(spyHasChildNodes).toHaveBeenCalledTimes(1); expect(spyRemoveChild).toHaveBeenCalledTimes(2); - expect(mockLogWarn).toHaveBeenCalledTimes(2); - expect(mockLogWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(2); + expect(logWarn).toHaveBeenCalledWith( "Compat: Could not remove text track child from element.", ); }); - it("should not remove audio child node if on firefox and no text tracks", async () => { + it("should not remove audio child node if on firefox and no text tracks", () => { const fakeElement = { src: "foo", removeAttribute() { @@ -136,9 +128,6 @@ describe("Compat - clearElementSrc", () => { removeChild: () => null, } as unknown as IMediaElement; - const clearElementSrc = (await vi.importActual("../clear_element_src")) - .default as typeof IClearElementSrc; - const spyRemoveAttribute = vi.spyOn(fakeElement, "removeAttribute"); const spyHasChildNodes = vi.spyOn(fakeElement, "hasChildNodes"); const spyRemoveChild = vi.spyOn(fakeElement, "removeChild"); @@ -153,7 +142,7 @@ describe("Compat - clearElementSrc", () => { expect(spyRemoveChild).not.toHaveBeenCalled(); }); - it("should not handle text tracks nodes is has no child nodes", async () => { + it("should not handle text tracks nodes is has no child nodes", () => { const fakeElement = { src: "foo", removeAttribute() { @@ -165,9 +154,6 @@ describe("Compat - clearElementSrc", () => { removeChild: () => null, } as unknown as IMediaElement; - const clearElementSrc = (await vi.importActual("../clear_element_src")) - .default as typeof IClearElementSrc; - const spyRemoveAttribute = vi.spyOn(fakeElement, "removeAttribute"); const spyHasChildNodes = vi.spyOn(fakeElement, "hasChildNodes"); const spyRemoveChild = vi.spyOn(fakeElement, "removeChild"); @@ -182,7 +168,7 @@ describe("Compat - clearElementSrc", () => { expect(spyRemoveChild).not.toHaveBeenCalled(); }); - it("should not throw if the textTracks attribute is `null`", async () => { + it("should not throw if the textTracks attribute is `null`", () => { const fakeElement = { src: "foo", removeAttribute() { @@ -194,9 +180,6 @@ describe("Compat - clearElementSrc", () => { removeChild: () => null, } as unknown as IMediaElement; - const clearElementSrc = (await vi.importActual("../clear_element_src")) - .default as typeof IClearElementSrc; - const spyRemoveAttribute = vi.spyOn(fakeElement, "removeAttribute"); const spyHasChildNodes = vi.spyOn(fakeElement, "hasChildNodes"); const spyRemoveChild = vi.spyOn(fakeElement, "removeChild"); @@ -211,7 +194,7 @@ describe("Compat - clearElementSrc", () => { expect(spyRemoveChild).not.toHaveBeenCalled(); }); - it("should not throw if the textTracks attribute is `undefined`", async () => { + it("should not throw if the textTracks attribute is `undefined`", () => { const fakeElement = { src: "foo", removeAttribute() { @@ -223,9 +206,6 @@ describe("Compat - clearElementSrc", () => { removeChild: () => null, } as unknown as IMediaElement; - const clearElementSrc = (await vi.importActual("../clear_element_src")) - .default as typeof IClearElementSrc; - const spyRemoveAttribute = vi.spyOn(fakeElement, "removeAttribute"); const spyHasChildNodes = vi.spyOn(fakeElement, "hasChildNodes"); const spyRemoveChild = vi.spyOn(fakeElement, "removeChild"); diff --git a/src/compat/__tests__/is_codec_supported.test.ts b/src/compat/__tests__/is_codec_supported.test.ts index b457760819..a2e7969261 100644 --- a/src/compat/__tests__/is_codec_supported.test.ts +++ b/src/compat/__tests__/is_codec_supported.test.ts @@ -1,64 +1,55 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IIsCodecSupported from "../is_codec_supported"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import isCodecSupported from "../is_codec_supported"; + +const mocks = vi.hoisted(() => { + return { + default: { + MediaSource_: {} as unknown, + }, + }; +}); + +vi.mock("../browser_compatibility_types", () => { + return mocks; +}); describe("Compat - isCodecSupported", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + mocks.default.MediaSource_ = {}; + }); - it("should return false if MediaSource is not supported in the current device", async () => { - vi.doMock("../browser_compatibility_types", () => { - return { - MediaSource_: undefined, - }; - }); - const isCodecSupported = (await vi.importActual("../is_codec_supported")) - .default as typeof IIsCodecSupported; + it("should return false if MediaSource is not supported in the current device", () => { + mocks.default.MediaSource_ = undefined; expect(isCodecSupported("foo")).toEqual(false); expect(isCodecSupported("")).toEqual(false); }); - it("should return true in any case if the MediaSource does not have the right function", async () => { - vi.doMock("../browser_compatibility_types", () => { - return { - MediaSource_: { isTypeSupported: undefined }, - }; - }); - const isCodecSupported = (await vi.importActual("../is_codec_supported")) - .default as typeof IIsCodecSupported; + it("should return true in any case if the MediaSource does not have the right function", () => { + mocks.default.MediaSource_ = { isTypeSupported: undefined }; expect(isCodecSupported("foo")).toEqual(true); expect(isCodecSupported("")).toEqual(true); }); - it("should return true if MediaSource.isTypeSupported returns true", async () => { - vi.doMock("../browser_compatibility_types", () => { - return { - MediaSource_: { - isTypeSupported(_codec: string) { - return true; - }, - }, - }; - }); - const isCodecSupported = (await vi.importActual("../is_codec_supported")) - .default as typeof IIsCodecSupported; + it("should return true if MediaSource.isTypeSupported returns true", () => { + mocks.default.MediaSource_ = { + isTypeSupported(_codec: string) { + return true; + }, + }; expect(isCodecSupported("foo")).toEqual(true); expect(isCodecSupported("")).toEqual(true); }); - it("should return false if MediaSource.isTypeSupported returns false", async () => { - vi.doMock("../browser_compatibility_types", () => { - return { - MediaSource_: { - isTypeSupported(_codec: string) { - return false; - }, - }, - }; - }); - const isCodecSupported = (await vi.importActual("../is_codec_supported")) - .default as typeof IIsCodecSupported; - expect(isCodecSupported("foo")).toEqual(false); - expect(isCodecSupported("")).toEqual(false); + it("should return false if MediaSource.isTypeSupported returns false", () => { + mocks.default.MediaSource_ = { + isTypeSupported(_codec: string) { + return false; + }, + }; + expect(isCodecSupported("oohjustlikeweneversaidgoodbye")).toEqual(false); + expect(isCodecSupported("ontheinternetwaitingtosayhi")).toEqual(false); }); }); diff --git a/src/compat/__tests__/is_vtt_cue.test.ts b/src/compat/__tests__/is_vtt_cue.test.ts index 6a8301a747..e3b27bffdf 100644 --- a/src/compat/__tests__/is_vtt_cue.test.ts +++ b/src/compat/__tests__/is_vtt_cue.test.ts @@ -1,6 +1,6 @@ -import { describe, it, expect, vi } from "vitest"; +import { describe, it, expect } from "vitest"; import globalScope from "../../utils/global_scope"; -import type IIsVTTCue from "../is_vtt_cue"; +import isVTTCue from "../is_vtt_cue"; describe("Compat - isVTTCue", () => { interface IFakeWindow { @@ -18,16 +18,15 @@ describe("Compat - isVTTCue", () => { } const gs = globalScope as IFakeWindow; - it("should return true if the given cue is an instance of a vtt cue", async () => { + it("should return true if the given cue is an instance of a vtt cue", () => { const originalVTTCue = globalScope.VTTCue; gs.VTTCue = MockVTTCue; const cue = new VTTCue(0, 10, ""); - const isVTTCue = (await vi.importActual("../is_vtt_cue")).default as typeof IIsVTTCue; expect(isVTTCue(cue)).toEqual(true); globalScope.VTTCue = originalVTTCue; }); - it("should return false if the given cue is not an instance of a vtt cue", async () => { + it("should return false if the given cue is not an instance of a vtt cue", () => { const originalVTTCue = globalScope.VTTCue; gs.VTTCue = MockVTTCue; const cue = { @@ -35,17 +34,15 @@ describe("Compat - isVTTCue", () => { endTime: 10, text: "toto", } as unknown as VTTCue; - const isVTTCue = (await vi.importActual("../is_vtt_cue")).default as typeof IIsVTTCue; expect(isVTTCue(cue)).toEqual(false); globalScope.VTTCue = originalVTTCue; }); - it("should return false in any case if the global scope does not define a VTTCue", async () => { + it("should return false in any case if the global scope does not define a VTTCue", () => { const originalVTTCue = globalScope.VTTCue; gs.VTTCue = MockVTTCue; const cue = new VTTCue(0, 10, ""); delete gs.VTTCue; - const isVTTCue = (await vi.importActual("../is_vtt_cue")).default as typeof IIsVTTCue; expect(isVTTCue(cue)).toEqual(false); globalScope.VTTCue = originalVTTCue; }); diff --git a/src/compat/__tests__/make_vtt_cue.test.ts b/src/compat/__tests__/make_vtt_cue.test.ts index 0f4c77a23b..0ed502108a 100644 --- a/src/compat/__tests__/make_vtt_cue.test.ts +++ b/src/compat/__tests__/make_vtt_cue.test.ts @@ -1,8 +1,16 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import log from "../../log"; import globalScope from "../../utils/global_scope"; -import type IMakeCue from "../make_vtt_cue"; +import makeCue from "../make_vtt_cue"; + +const logWarn = vi.spyOn(log, "warn").mockImplementation(() => { + /* noop */ +}); describe("Compat - makeVTTCue", () => { + afterEach(() => { + logWarn.mockClear(); + }); class MockVTTCue { public startTime: number; public endTime: number; @@ -27,14 +35,9 @@ describe("Compat - makeVTTCue", () => { gs.TextTrackCue = ogTextTrackCue; }); - it("should throw if nor VTTCue nor TextTrackCue is available", async () => { - const mockLog = { warn: vi.fn() }; + it("should throw if nor VTTCue nor TextTrackCue is available", () => { gs.VTTCue = undefined; gs.TextTrackCue = undefined; - vi.doMock("../../log", () => ({ - default: mockLog, - })); - const makeCue = (await vi.importActual("../make_vtt_cue")).default as typeof IMakeCue; let result: unknown; let error: unknown; try { @@ -45,31 +48,21 @@ describe("Compat - makeVTTCue", () => { expect(error).toBeInstanceOf(Error); expect((error as Error).message).toEqual("VTT cues not supported in your target"); expect(result).toBe(undefined); - expect(mockLog.warn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should warn and not create anything if start time is after end time", async () => { - const mockLog = { warn: vi.fn() }; + it("should warn and not create anything if start time is after end time", () => { gs.VTTCue = MockVTTCue; - vi.doMock("../../log", () => ({ - default: mockLog, - })); - const makeCue = (await vi.importActual("../make_vtt_cue")).default as typeof IMakeCue; const result = makeCue(12, 10, "toto"); expect(result).toBeNull(); - expect(mockLog.warn).toHaveBeenCalledTimes(1); - expect(mockLog.warn).toHaveBeenCalledWith("Compat: Invalid cue times: 12 - 10"); + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith("Compat: Invalid cue times: 12 - 10"); }); - it("should create a new VTT Cue in other cases", async () => { - const mockLog = { warn: vi.fn() }; + it("should create a new VTT Cue in other cases", () => { gs.VTTCue = MockVTTCue; - vi.doMock("../../log", () => ({ - default: mockLog, - })); - const makeCue = (await vi.importActual("../make_vtt_cue")).default as typeof IMakeCue; const result = makeCue(10, 12, "toto"); expect(result).toEqual(new MockVTTCue(10, 12, "toto")); - expect(mockLog.warn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); }); diff --git a/src/compat/__tests__/remove_cue.test.ts b/src/compat/__tests__/remove_cue.test.ts index 54bdf80372..8331e14550 100644 --- a/src/compat/__tests__/remove_cue.test.ts +++ b/src/compat/__tests__/remove_cue.test.ts @@ -1,18 +1,12 @@ import { describe, beforeEach, afterEach, it, expect, vi } from "vitest"; +import log from "../../log"; import arrayFindIndex from "../../utils/array_find_index"; import EnvDetector, { mockEnvironment, resetEnvironment } from "../env_detector"; import removeCue from "../remove_cue"; -const mocks = vi.hoisted(() => { - return { - logWarn: vi.fn(), - }; +const logWarn = vi.spyOn(log, "warn").mockImplementation(() => { + /* noop */ }); -vi.mock("../../log", () => ({ - default: { - warn: mocks.logWarn, - }, -})); describe("compat - removeCue", () => { beforeEach(() => { @@ -20,7 +14,7 @@ describe("compat - removeCue", () => { }); afterEach(() => { resetEnvironment(); - mocks.logWarn.mockReset(); + logWarn.mockClear(); }); it("should remove cue from track if not on firefox", () => { @@ -169,10 +163,8 @@ describe("compat - removeCue", () => { expect(fakeTrack.cues?.length).toBe(1); expect(fakeTrack.mode).toBe("showing"); - expect(mocks.logWarn).toHaveBeenCalledTimes(1); - expect(mocks.logWarn).toHaveBeenCalledWith( - "Compat: Could not remove cue from text track.", - ); + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith("Compat: Could not remove cue from text track."); expect(mockRemoveCue).toHaveBeenCalledTimes(1); expect(mockRemoveCue).toHaveBeenLastCalledWith(fakeCue); }); @@ -194,10 +186,8 @@ describe("compat - removeCue", () => { expect(fakeTrack.cues?.length).toBe(1); expect(fakeTrack.mode).toBe("showing"); - expect(mocks.logWarn).toHaveBeenCalledTimes(1); - expect(mocks.logWarn).toHaveBeenCalledWith( - "Compat: Could not remove cue from text track.", - ); + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith("Compat: Could not remove cue from text track."); expect(mockRemoveCue).toHaveBeenCalledTimes(1); expect(mockRemoveCue).toHaveBeenLastCalledWith({ id: "1" }); }); diff --git a/src/compat/browser_compatibility_types.ts b/src/compat/browser_compatibility_types.ts index 34b6acc55e..559f21bb93 100644 --- a/src/compat/browser_compatibility_types.ts +++ b/src/compat/browser_compatibility_types.ts @@ -469,4 +469,11 @@ export type { ICompatVTTCue, ICompatVTTCueConstructor, }; -export { MediaSource_, isManagedMediaSource, READY_STATES }; + +/** Various globals in an object so they are easier to mock. */ +const BROWSER_GLOBALS = { + MediaSource_, + isManagedMediaSource, + READY_STATES, +}; +export default BROWSER_GLOBALS; diff --git a/src/compat/is_codec_supported.ts b/src/compat/is_codec_supported.ts index 67152d7805..04cb4c43d7 100644 --- a/src/compat/is_codec_supported.ts +++ b/src/compat/is_codec_supported.ts @@ -17,7 +17,7 @@ import log from "../log"; import isNullOrUndefined from "../utils/is_null_or_undefined"; import isWorker from "../utils/is_worker"; -import { MediaSource_ } from "./browser_compatibility_types"; +import BROWSER_GLOBALS from "./browser_compatibility_types"; /** * Setting this value limit the number of entries in the support map @@ -40,6 +40,7 @@ const supportMap: Map = new Map(); * @returns {Boolean} */ export default function isCodecSupported(mimeType: string): boolean { + const { MediaSource_ } = BROWSER_GLOBALS; if (isNullOrUndefined(MediaSource_)) { if (isWorker) { log.error("Compat: Cannot request codec support in a worker without MSE."); diff --git a/src/core/adaptive/__tests__/buffer_based_chooser.test.ts b/src/core/adaptive/__tests__/buffer_based_chooser.test.ts index e6ccc64f69..0c311b03ff 100644 --- a/src/core/adaptive/__tests__/buffer_based_chooser.test.ts +++ b/src/core/adaptive/__tests__/buffer_based_chooser.test.ts @@ -1,20 +1,25 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IBufferBasedChooser from "../buffer_based_chooser"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import log from "../../../log"; +import BufferBasedChooser from "../buffer_based_chooser"; import { ScoreConfidenceLevel } from "../utils/representation_score_calculator"; +const logDebug = vi.spyOn(log, "debug").mockImplementation(() => { + /* noop */ +}); +const logInfo = vi.spyOn(log, "info").mockImplementation(() => { + /* noop */ +}); + describe("BufferBasedChooser", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + logDebug.mockClear(); + logInfo.mockClear(); + }); - it("should return the first bitrate if the current bitrate is undefined", async () => { - const logger = { debug: vi.fn() }; - vi.doMock("../../../log", () => ({ - default: logger, - })); - const BufferBasedChooser = (await vi.importActual("../buffer_based_chooser")) - .default as typeof IBufferBasedChooser; - + it("should return the first bitrate if the current bitrate is undefined", () => { let bbc = new BufferBasedChooser([]); bbc.onAddedSegment({ bufferGap: 0, speed: 1 }); expect(bbc.getLastEstimate()).toEqual(undefined); @@ -69,14 +74,7 @@ describe("BufferBasedChooser", () => { expect(bbc.getLastEstimate()).toEqual(1); }); - it("should log an error and return the first bitrate if the given bitrate does not exist", async () => { - const logger = { debug: vi.fn(), info: vi.fn() }; - vi.doMock("../../../log", () => ({ - default: logger, - })); - const BufferBasedChooser = (await vi.importActual("../buffer_based_chooser")) - .default as typeof IBufferBasedChooser; - + it("should log an error and return the first bitrate if the given bitrate does not exist", () => { const bbc = new BufferBasedChooser([10, 20]); bbc.onAddedSegment({ bufferGap: 0, @@ -85,20 +83,13 @@ describe("BufferBasedChooser", () => { currentScore: undefined, }); expect(bbc.getLastEstimate()).toEqual(10); - expect(logger.info).toHaveBeenCalledTimes(1); - expect(logger.info).toHaveBeenCalledWith( + expect(logInfo).toHaveBeenCalledTimes(1); + expect(logInfo).toHaveBeenCalledWith( "ABR: Current Bitrate not found in the calculated levels", ); }); - it("should not go to the next bitrate if we don't have a high enough maintainability score", async () => { - const logger = { debug: vi.fn() }; - vi.doMock("../../../log", () => ({ - default: logger, - })); - const BufferBasedChooser = (await vi.importActual("../buffer_based_chooser")) - .default as typeof IBufferBasedChooser; - + it("should not go to the next bitrate if we don't have a high enough maintainability score", () => { let bbc = new BufferBasedChooser([10, 20, 40]); bbc.onAddedSegment({ bufferGap: 16, @@ -154,14 +145,7 @@ describe("BufferBasedChooser", () => { expect(bbc.getLastEstimate()).toEqual(20); }); - it("should go to the next bitrate if the current one is maintainable and we have more buffer than the next level", async () => { - const logger = { debug: vi.fn() }; - vi.doMock("../../../log", () => ({ - default: logger, - })); - const BufferBasedChooser = (await vi.importActual("../buffer_based_chooser")) - .default as typeof IBufferBasedChooser; - + it("should go to the next bitrate if the current one is maintainable and we have more buffer than the next level", () => { let bbc = new BufferBasedChooser([10, 20, 40]); bbc.onAddedSegment({ bufferGap: 16, @@ -217,14 +201,7 @@ describe("BufferBasedChooser", () => { expect(bbc.getLastEstimate()).toEqual(40); }); - it("should stay at the current bitrate if it is maintainable but we have a buffer inferior to the next level", async () => { - const logger = { debug: vi.fn() }; - vi.doMock("../../../log", () => ({ - default: logger, - })); - const BufferBasedChooser = (await vi.importActual("../buffer_based_chooser")) - .default as typeof IBufferBasedChooser; - + it("should stay at the current bitrate if it is maintainable but we have a buffer inferior to the next level", () => { let bbc = new BufferBasedChooser([10, 20, 40]); bbc.onAddedSegment({ bufferGap: 6, @@ -271,14 +248,7 @@ describe("BufferBasedChooser", () => { expect(bbc.getLastEstimate()).toEqual(20); }); - it("should stay at the current bitrate if we are currently at the maximum one", async () => { - const logger = { debug: vi.fn() }; - vi.doMock("../../../log", () => ({ - default: logger, - })); - const BufferBasedChooser = (await vi.importActual("../buffer_based_chooser")) - .default as typeof IBufferBasedChooser; - + it("should stay at the current bitrate if we are currently at the maximum one", () => { let bbc = new BufferBasedChooser([10, 20, 40]); bbc.onAddedSegment({ bufferGap: 100000000000, @@ -304,14 +274,7 @@ describe("BufferBasedChooser", () => { expect(bbc.getLastEstimate()).toEqual(40); }); - it("should stay at the current bitrate if the current one is not maintainable due to the speed", async () => { - const logger = { debug: vi.fn() }; - vi.doMock("../../../log", () => ({ - default: logger, - })); - const BufferBasedChooser = (await vi.importActual("../buffer_based_chooser")) - .default as typeof IBufferBasedChooser; - + it("should stay at the current bitrate if the current one is not maintainable due to the speed", () => { let bbc = new BufferBasedChooser([10, 20, 40]); bbc.onAddedSegment({ bufferGap: 15, @@ -358,14 +321,7 @@ describe("BufferBasedChooser", () => { expect(bbc.getLastEstimate()).toEqual(20); }); - it("should lower bitrate if the current one is not maintainable due to the speed", async () => { - const logger = { debug: vi.fn() }; - vi.doMock("../../../log", () => ({ - default: logger, - })); - const BufferBasedChooser = (await vi.importActual("../buffer_based_chooser")) - .default as typeof IBufferBasedChooser; - + it("should lower bitrate if the current one is not maintainable due to the speed", () => { let bbc = new BufferBasedChooser([10, 20, 40]); bbc.onAddedSegment({ bufferGap: 15, @@ -412,14 +368,7 @@ describe("BufferBasedChooser", () => { expect(bbc.getLastEstimate()).toEqual(10); }); - it("should not lower bitrate if the current one is not maintainable due to the speed but confidence on the score is low", async () => { - const logger = { debug: vi.fn() }; - vi.doMock("../../../log", () => ({ - default: logger, - })); - const BufferBasedChooser = (await vi.importActual("../buffer_based_chooser")) - .default as typeof IBufferBasedChooser; - + it("should not lower bitrate if the current one is not maintainable due to the speed but confidence on the score is low", () => { let bbc = new BufferBasedChooser([10, 20, 40]); bbc.onAddedSegment({ bufferGap: 15, @@ -475,14 +424,7 @@ describe("BufferBasedChooser", () => { expect(bbc.getLastEstimate()).toEqual(20); }); - it("should not go to the next bitrate if we do not know if it is maintainable", async () => { - const logger = { debug: vi.fn() }; - vi.doMock("../../../log", () => ({ - default: logger, - })); - const BufferBasedChooser = (await vi.importActual("../buffer_based_chooser")) - .default as typeof IBufferBasedChooser; - + it("should not go to the next bitrate if we do not know if it is maintainable", () => { let bbc = new BufferBasedChooser([10, 20, 40]); bbc.onAddedSegment({ bufferGap: 15, diff --git a/src/errors/__tests__/format_error.test.ts b/src/errors/__tests__/format_error.test.ts index ef30092447..3eacd7e6cf 100644 --- a/src/errors/__tests__/format_error.test.ts +++ b/src/errors/__tests__/format_error.test.ts @@ -1,29 +1,34 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IFormatError from "../format_error"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import formatError from "../format_error"; +import OtherError from "../other_error"; +const mocks = vi.hoisted(() => { + return { + isKnownError: vi.fn(), + }; +}); + +vi.mock("../is_known_error", () => { + return { + default: mocks.isKnownError, + }; +}); describe("errors - formatError", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + mocks.isKnownError.mockReset(); + }); - it("should just return the error if it is a Custom Error", async () => { - vi.doMock("../is_known_error", () => ({ - default: () => true, - })); - const formatError = (await vi.importActual("../format_error")) - .default as typeof IFormatError; + it("should just return the error if it is a Custom Error", () => { + mocks.isKnownError.mockImplementation(() => true); const error1 = new Error("Aaaaaa"); expect(formatError(error1, { defaultCode: "NONE", defaultReason: "a" })).toBe(error1); }); - it("should stringify error if it is an Error but not a Custom Error", async () => { - vi.doMock("../is_known_error", () => ({ - default: () => false, - })); - const OtherError = (await vi.importActual("../other_error")) - .default as typeof IFormatError; - const formatError = (await vi.importActual("../format_error")) - .default as typeof IFormatError; + it("should stringify error if it is an Error but not a Custom Error", () => { + mocks.isKnownError.mockImplementation(() => false); const error1 = new Error("Abcdef"); const formattedError = formatError(error1, { defaultCode: "NONE", @@ -34,14 +39,8 @@ describe("errors - formatError", () => { expect(formattedError.code).toBe("NONE"); }); - it("should stringify error if it is an Error but not a Custom Error", async () => { - vi.doMock("../is_known_error", () => ({ - default: () => false, - })); - const OtherError = (await vi.importActual("../other_error")) - .default as typeof IFormatError; - const formatError = (await vi.importActual("../format_error")) - .default as typeof IFormatError; + it("should stringify error if it is an Error but not a Custom Error", () => { + mocks.isKnownError.mockImplementation(() => false); const error1 = {}; const formattedError = formatError(error1, { defaultCode: "NONE", diff --git a/src/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.ts b/src/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.ts index 40fbd1ebe2..e0668df2cc 100644 --- a/src/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.ts +++ b/src/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { MediaSource_ } from "../../../compat/browser_compatibility_types"; import type { IMediaElement } from "../../../compat/browser_compatibility_types"; +import BROWSER_GLOBALS from "../../../compat/browser_compatibility_types"; import log from "../../../log"; import { resetMediaElement, @@ -45,6 +45,7 @@ export default function prepareSourceBuffer( cleanUpSignal: CancellationSignal, ): Promise { return createCancellablePromise(cleanUpSignal, (resolve, reject) => { + const { MediaSource_ } = BROWSER_GLOBALS; if (isNullOrUndefined(MediaSource_)) { throw new Error("No MediaSource Object was found in the current browser."); } diff --git a/src/experimental/tools/mediaCapabilitiesProber/__tests__/capabilities.test.ts b/src/experimental/tools/mediaCapabilitiesProber/__tests__/capabilities.test.ts index fdbbf6ffaf..24ad897346 100644 --- a/src/experimental/tools/mediaCapabilitiesProber/__tests__/capabilities.test.ts +++ b/src/experimental/tools/mediaCapabilitiesProber/__tests__/capabilities.test.ts @@ -1,24 +1,20 @@ import { describe, it, expect, vi } from "vitest"; -import type IGetProbedConfiguration from "../capabilities"; +import getProbedConfiguration from "../capabilities"; import type { ICapabilitiesTypes } from "../capabilities"; +vi.mock("../utils.ts", () => ({ + extend: vi.fn(), + filterConfigurationWithCapabilities: vi.fn(() => ({ key: "test" })), +})); + describe("MediaCapabilitiesProber - getProbedConfiguration", () => { - it("should return result from filtered configuration", async () => { - const expectedResult = { key: "test" }; - const mockExtend = vi.fn(() => ({})); - const mockFilterConfigurationWithCapabilities = vi.fn(() => expectedResult); - vi.doMock("../utils.ts", () => ({ - extend: mockExtend, - filterConfigurationWithCapabilities: mockFilterConfigurationWithCapabilities, - })); - const getProbedConfiguration = (await vi.importActual("../capabilities")) - .default as typeof IGetProbedConfiguration; + it("should return result from filtered configuration", () => { expect( getProbedConfiguration({}, [ "Athos", "Portos", "Aramis", ] as unknown as ICapabilitiesTypes[]), - ).toEqual(expectedResult); + ).toEqual({ key: "test" }); }); }); diff --git a/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/DRMInfos.test.ts b/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/DRMInfos.test.ts index a38af90068..aef9549ea1 100644 --- a/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/DRMInfos.test.ts +++ b/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/DRMInfos.test.ts @@ -1,16 +1,24 @@ -import { describe, afterEach, it, expect, vi } from "vitest"; -import type IProbeDRMInfos from "../../probers/DRMInfos"; +import { describe, afterEach, it, expect, vi, beforeEach } from "vitest"; +import probeDRMInfos from "../../probers/DRMInfos"; import { ProberStatus } from "../../types"; +const compatEmeMock = vi.hoisted(() => { + return { + default: { requestMediaKeySystemAccess: undefined as unknown }, + }; +}); +vi.mock("../../../../../compat/eme", () => compatEmeMock); + describe("MediaCapabilitiesProber probers - DRMInfos", () => { - afterEach(() => { + beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + compatEmeMock.default.requestMediaKeySystemAccess = undefined; + }); - it("should throw if no keySystem provided", async () => { + it("should throw if no keySystem provided", () => { const configuration = {}; - const probeDRMInfos = (await vi.importActual("../../probers/DRMInfos")) - .default as typeof IProbeDRMInfos; // eslint-disable-next-line @typescript-eslint/no-floating-promises expect(probeDRMInfos(configuration)).rejects.toEqual( "MediaCapabilitiesProber >>> API_CALL: " + @@ -18,12 +26,10 @@ describe("MediaCapabilitiesProber probers - DRMInfos", () => { ); }); - it("should throw if no type of keySystem provided", async () => { + it("should throw if no type of keySystem provided", () => { const configuration = { keySystem: {}, }; - const probeDRMInfos = (await vi.importActual("../../probers/DRMInfos")) - .default as typeof IProbeDRMInfos; // eslint-disable-next-line @typescript-eslint/no-floating-promises expect(probeDRMInfos(configuration)).rejects.toEqual( "MediaCapabilitiesProber >>> API_CALL: " + @@ -31,17 +37,12 @@ describe("MediaCapabilitiesProber probers - DRMInfos", () => { ); }); - it("should resolve with `NotSupported` if no requestMediaKeySystemAccess", async () => { + it("should resolve with `NotSupported` if no requestMediaKeySystemAccess", () => { const configuration = { keySystem: { type: "clearkick", }, }; - vi.doMock("../../../../../compat/eme", () => ({ - default: {}, - })); - const probeDRMInfos = (await vi.importActual("../../probers/DRMInfos")) - .default as typeof IProbeDRMInfos; // eslint-disable-next-line @typescript-eslint/no-floating-promises expect(probeDRMInfos(configuration)).resolves.toEqual([ ProberStatus.NotSupported, @@ -60,11 +61,7 @@ describe("MediaCapabilitiesProber probers - DRMInfos", () => { getConfiguration: () => ({}), }); }); - vi.doMock("../../../../../compat/eme", () => ({ - default: { requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess }, - })); - const probeDRMInfos = (await vi.importActual("../../probers/DRMInfos")) - .default as typeof IProbeDRMInfos; + compatEmeMock.default.requestMediaKeySystemAccess = mockRequestMediaKeySystemAccess; await probeDRMInfos(configuration) .then((res: unknown) => { expect(res).toEqual([ @@ -87,12 +84,8 @@ describe("MediaCapabilitiesProber probers - DRMInfos", () => { const mockRequestMediaKeySystemAccess = vi.fn(() => { return Promise.reject(new Error()); }); - vi.doMock("../../../../../compat/eme", () => ({ - default: { requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess }, - })); + compatEmeMock.default.requestMediaKeySystemAccess = mockRequestMediaKeySystemAccess; - const probeDRMInfos = (await vi.importActual("../../probers/DRMInfos")) - .default as typeof IProbeDRMInfos; await probeDRMInfos(configuration) .then((res: unknown) => { expect(res).toEqual([ diff --git a/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/HDCPPolicy.test.ts b/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/HDCPPolicy.test.ts index 2713a333da..c2a9958513 100644 --- a/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/HDCPPolicy.test.ts +++ b/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/HDCPPolicy.test.ts @@ -1,37 +1,38 @@ -import { describe, afterEach, it, expect, vi } from "vitest"; -import type IProbeHDCPPolicy from "../../probers/HDCPPolicy"; +import { describe, afterEach, it, expect, vi, beforeEach } from "vitest"; +import probeHDCPPolicy from "../../probers/HDCPPolicy"; import { ProberStatus } from "../../types"; +const compatEmeMock = vi.hoisted(() => { + return { + default: { + requestMediaKeySystemAccess: undefined as unknown, + }, + }; +}); +vi.mock("../../../../../compat/eme", () => compatEmeMock); + describe("MediaCapabilitiesProber probers - HDCPPolicy", () => { - afterEach(() => { + beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + compatEmeMock.default.requestMediaKeySystemAccess = undefined; + }); - it("should throw if no requestMediaKeySystemAccess", async () => { - vi.doMock("../../../../../compat/eme", () => ({ - default: vi.fn(), - })); - const probeHDCPPolicy = (await vi.importActual("../../probers/HDCPPolicy")) - .default as typeof IProbeHDCPPolicy; + it("should throw if no requestMediaKeySystemAccess", () => { // eslint-disable-next-line @typescript-eslint/no-floating-promises expect(probeHDCPPolicy({})).rejects.toEqual( "MediaCapabilitiesProber >>> API_CALL: API not available", ); }); - it("should throw if no hdcp attribute in config", async () => { + it("should throw if no hdcp attribute in config", () => { const mockRequestMediaKeySystemAccess = vi.fn(() => { return Promise.resolve({ getConfiguration: () => ({}), }); }); - vi.doMock("../../../../../compat/eme", () => ({ - default: { - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }, - })); - const probeHDCPPolicy = (await vi.importActual("../../probers/HDCPPolicy")) - .default as typeof IProbeHDCPPolicy; + compatEmeMock.default.requestMediaKeySystemAccess = mockRequestMediaKeySystemAccess; // eslint-disable-next-line @typescript-eslint/no-floating-promises expect(probeHDCPPolicy({})).rejects.toEqual( "MediaCapabilitiesProber >>> API_CALL: " + @@ -48,15 +49,7 @@ describe("MediaCapabilitiesProber probers - HDCPPolicy", () => { createMediaKeys: mockCreateMediaKeys, }); }); - vi.doMock("../../../../../compat/eme", () => ({ - default: { - requestMediaKeySystemAccess: mockRequestMediaKeySystemAcces, - }, - })); - - const probeHDCPPolicy = (await vi.importActual("../../probers/HDCPPolicy")) - .default as typeof IProbeHDCPPolicy; - + compatEmeMock.default.requestMediaKeySystemAccess = mockRequestMediaKeySystemAcces; await probeHDCPPolicy({ hdcp: "1.1" }).then(([res]: [unknown]) => { expect(res).toEqual(ProberStatus.Unknown); expect(mockCreateMediaKeys).toHaveBeenCalledTimes(1); @@ -75,15 +68,7 @@ describe("MediaCapabilitiesProber probers - HDCPPolicy", () => { createMediaKeys: mockCreateMediaKeys, }); }); - vi.doMock("../../../../../compat/eme", () => ({ - default: { - requestMediaKeySystemAccess: mockRequestMediaKeySystemAcces, - }, - })); - - const probeHDCPPolicy = (await vi.importActual("../../probers/HDCPPolicy")) - .default as typeof IProbeHDCPPolicy; - + compatEmeMock.default.requestMediaKeySystemAccess = mockRequestMediaKeySystemAcces; await probeHDCPPolicy({ hdcp: "1.1" }).then(([res]: [unknown]) => { expect(res).toEqual(ProberStatus.Supported); expect(mockCreateMediaKeys).toHaveBeenCalledTimes(1); @@ -102,14 +87,8 @@ describe("MediaCapabilitiesProber probers - HDCPPolicy", () => { createMediaKeys: mockCreateMediaKeys, }); }); - vi.doMock("../../../../../compat/eme", () => ({ - default: { - requestMediaKeySystemAccess: mockRequestMediaKeySystemAcces, - }, - })); + compatEmeMock.default.requestMediaKeySystemAccess = mockRequestMediaKeySystemAcces; - const probeHDCPPolicy = (await vi.importActual("../../probers/HDCPPolicy")) - .default as typeof IProbeHDCPPolicy; await probeHDCPPolicy({ hdcp: "1.1" }).then(([res]: [unknown]) => { expect(res).toEqual(ProberStatus.NotSupported); expect(mockCreateMediaKeys).toHaveBeenCalledTimes(1); diff --git a/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/decodingInfos.test.ts b/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/decodingInfos.test.ts index 1cc0718b1f..08bcbec552 100644 --- a/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/decodingInfos.test.ts +++ b/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/decodingInfos.test.ts @@ -1,11 +1,10 @@ import { describe, beforeEach, afterEach, it, expect, vi } from "vitest"; -import isNullOrUndefined from "../../../../../utils/is_null_or_undefined"; +import globalScope from "../../../../../utils/global_scope"; import probeDecodingInfos from "../../probers/decodingInfo"; import type { IMediaConfiguration } from "../../types"; import { ProberStatus } from "../../types"; -const origDecodingInfo = navigator.mediaCapabilities; -const origMediaCapabilities = navigator.mediaCapabilities; +const oldNavigator = globalScope.navigator; /** * Stub decodingInfo API to resolve. @@ -25,31 +24,34 @@ function stubDecodingInfo(isSupported: boolean, mustReject?: boolean) { const mockMediaCapabilities = { decodingInfo: decodingInfoStub, - }; + } as unknown as MediaCapabilities; - // @ts-expect-error: `navigator.mediaCapabilities` is read-only normally, for - // now, we're going through JSDom through so that's OK. - navigator.mediaCapabilities = mockMediaCapabilities; + Object.defineProperty(navigator, "mediaCapabilities", { + get() { + return mockMediaCapabilities; + }, + }); return decodingInfoStub; } -/** - * Reset decodingInfo to native implementation. - */ -function resetDecodingInfos(): void { - // @ts-expect-error: `navigator.mediaCapabilities` is read-only normally, for - // now, we're going through JSDom through so that's OK. - navigator.mediaCapabilities = origDecodingInfo; -} - describe("MediaCapabilitiesProber probers - decodingInfo", () => { beforeEach(() => { vi.resetModules(); + + // Ugly trick to authorize the resetting of the `navigator` property: + // 1. We redefine what window.navigator points to so it can be modified. + // We don't care about its value here. + // 2. We're now able to remove it from `window`. + // 3. We now redefine it as an empty object. + Object.defineProperty(globalScope, "navigator", {}); + // @ts-expect-error: part of the aforementioned trick + delete globalScope.navigator; + // @ts-expect-error: part of the aforementioned trick + globalScope.navigator = {}; }); + afterEach(() => { - // @ts-expect-error: `navigator.mediaCapabilities` is read-only normally, for - // now, we're going through JSDom through so that's OK. - navigator.mediaCapabilities = origMediaCapabilities; + globalScope.navigator = oldNavigator; }); it("should throw if no video and audio config", () => { @@ -59,18 +61,13 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { }; expect.assertions(2); - return probeDecodingInfos(configuration) - .then(() => { - resetDecodingInfos(); - }) - .catch(({ message }: { message: string }) => { - expect(message).toEqual( - "MediaCapabilitiesProber >>> API_CALL: " + - "Not enough arguments for calling mediaCapabilites.", - ); - expect(decodingInfoStub).not.toHaveBeenCalled(); - resetDecodingInfos(); - }); + return probeDecodingInfos(configuration).catch(({ message }: { message: string }) => { + expect(message).toEqual( + "MediaCapabilitiesProber >>> API_CALL: " + + "Not enough arguments for calling mediaCapabilites.", + ); + expect(decodingInfoStub).not.toHaveBeenCalled(); + }); }); it("should throw if incomplete video config", () => { @@ -83,18 +80,13 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { }; expect.assertions(2); - return probeDecodingInfos(configuration) - .then(() => { - resetDecodingInfos(); - }) - .catch(({ message }: { message: string }) => { - expect(message).toEqual( - "MediaCapabilitiesProber >>> API_CALL: " + - "Not enough arguments for calling mediaCapabilites.", - ); - expect(decodingInfoStub).not.toHaveBeenCalled(); - resetDecodingInfos(); - }); + return probeDecodingInfos(configuration).catch(({ message }: { message: string }) => { + expect(message).toEqual( + "MediaCapabilitiesProber >>> API_CALL: " + + "Not enough arguments for calling mediaCapabilites.", + ); + expect(decodingInfoStub).not.toHaveBeenCalled(); + }); }); it("should throw if incomplete audio config", () => { @@ -107,18 +99,13 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { }; expect.assertions(2); - return probeDecodingInfos(configuration) - .then(() => { - resetDecodingInfos(); - }) - .catch(({ message }: { message: string }) => { - expect(message).toEqual( - "MediaCapabilitiesProber >>> API_CALL: " + - "Not enough arguments for calling mediaCapabilites.", - ); - expect(decodingInfoStub).not.toHaveBeenCalled(); - resetDecodingInfos(); - }); + return probeDecodingInfos(configuration).catch(({ message }: { message: string }) => { + expect(message).toEqual( + "MediaCapabilitiesProber >>> API_CALL: " + + "Not enough arguments for calling mediaCapabilites.", + ); + expect(decodingInfoStub).not.toHaveBeenCalled(); + }); }); it("should throw if no type in config", () => { @@ -129,18 +116,13 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { }, }; expect.assertions(2); - return probeDecodingInfos(configuration) - .then(() => { - resetDecodingInfos(); - }) - .catch(({ message }: { message: string }) => { - expect(message).toEqual( - "MediaCapabilitiesProber >>> API_CALL: " + - "Not enough arguments for calling mediaCapabilites.", - ); - expect(decodingInfoStub).not.toHaveBeenCalled(); - resetDecodingInfos(); - }); + return probeDecodingInfos(configuration).catch(({ message }: { message: string }) => { + expect(message).toEqual( + "MediaCapabilitiesProber >>> API_CALL: " + + "Not enough arguments for calling mediaCapabilites.", + ); + expect(decodingInfoStub).not.toHaveBeenCalled(); + }); }); it("should throw if empty config", () => { @@ -148,24 +130,16 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { const configuration = {}; expect.assertions(2); - return probeDecodingInfos(configuration) - .then(() => { - resetDecodingInfos(); - }) - .catch(({ message }: { message: string }) => { - expect(message).toEqual( - "MediaCapabilitiesProber >>> API_CALL: " + - "Not enough arguments for calling mediaCapabilites.", - ); - expect(decodingInfoStub).not.toHaveBeenCalled(); - resetDecodingInfos(); - }); + return probeDecodingInfos(configuration).catch(({ message }: { message: string }) => { + expect(message).toEqual( + "MediaCapabilitiesProber >>> API_CALL: " + + "Not enough arguments for calling mediaCapabilites.", + ); + expect(decodingInfoStub).not.toHaveBeenCalled(); + }); }); it("should throw if API mediaCapabilities not available", () => { - // @ts-expect-error: `navigator.mediaCapabilities` is read-only normally, for - // now, we're going through JSDom through so that's OK. - delete navigator.mediaCapabilities; // eslint-disable-next-line @typescript-eslint/no-floating-promises expect(probeDecodingInfos({})).rejects.toThrowError( "MediaCapabilitiesProber >>> API_CALL: MediaCapabilities API not available", @@ -173,15 +147,12 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { }); it("should throw if API decodingInfo not available", () => { - if (!isNullOrUndefined(navigator.mediaCapabilities)) { - // @ts-expect-error: `navigator.mediaCapabilities` is read-only normally, for - // now, we're going through JSDom through so that's OK. - delete navigator.mediaCapabilities.decodingInfo; - } else { - // @ts-expect-error: `navigator.mediaCapabilities` is read-only normally, for - // now, we're going through JSDom through so that's OK. - navigator.mediaCapabilities = {}; - } + Object.defineProperty(navigator, "mediaCapabilities", { + get() { + return {}; + }, + }); + // eslint-disable-next-line @typescript-eslint/no-floating-promises expect(probeDecodingInfos({})).rejects.toThrowError( "MediaCapabilitiesProber >>> API_CALL: Decoding Info not available", @@ -202,15 +173,10 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { }; expect.assertions(2); - return probeDecodingInfos(configuration) - .then(([res]) => { - expect(res).toBe(ProberStatus.Supported); - expect(decodingInfoStub).toHaveBeenCalledTimes(1); - resetDecodingInfos(); - }) - .catch(() => { - resetDecodingInfos(); - }); + return probeDecodingInfos(configuration).then(([res]) => { + expect(res).toBe(ProberStatus.Supported); + expect(decodingInfoStub).toHaveBeenCalledTimes(1); + }); }); it("should resolve with `Supported` if decodingInfo supports (audio only)", () => { @@ -226,15 +192,10 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { }; expect.assertions(2); - return probeDecodingInfos(configuration) - .then(([res]) => { - expect(res).toBe(ProberStatus.Supported); - expect(decodingInfoStub).toHaveBeenCalledTimes(1); - resetDecodingInfos(); - }) - .catch(() => { - resetDecodingInfos(); - }); + return probeDecodingInfos(configuration).then(([res]) => { + expect(res).toBe(ProberStatus.Supported); + expect(decodingInfoStub).toHaveBeenCalledTimes(1); + }); }); it("should resolve with `Supported` if decodingInfo supports video + audio", () => { @@ -256,15 +217,10 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { }, }; expect.assertions(2); - return probeDecodingInfos(configuration) - .then(([res]) => { - expect(res).toBe(ProberStatus.Supported); - expect(decodingInfoStub).toHaveBeenCalledTimes(1); - resetDecodingInfos(); - }) - .catch(() => { - resetDecodingInfos(); - }); + return probeDecodingInfos(configuration).then(([res]) => { + expect(res).toBe(ProberStatus.Supported); + expect(decodingInfoStub).toHaveBeenCalledTimes(1); + }); }); it("should return `NotSupported` if no decodingInfo support (video only)", () => { @@ -280,15 +236,10 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { }, }; expect.assertions(2); - return probeDecodingInfos(configuration) - .then(([res]) => { - expect(res).toBe(ProberStatus.NotSupported); - expect(decodingInfoStub).toHaveBeenCalledTimes(1); - resetDecodingInfos(); - }) - .catch(() => { - resetDecodingInfos(); - }); + return probeDecodingInfos(configuration).then(([res]) => { + expect(res).toBe(ProberStatus.NotSupported); + expect(decodingInfoStub).toHaveBeenCalledTimes(1); + }); }); it("should return `NotSupported` if no decodingInfo support (audio only)", () => { @@ -303,15 +254,10 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { }, }; expect.assertions(2); - return probeDecodingInfos(configuration) - .then(([res]) => { - expect(res).toBe(ProberStatus.NotSupported); - expect(decodingInfoStub).toHaveBeenCalledTimes(1); - resetDecodingInfos(); - }) - .catch(() => { - resetDecodingInfos(); - }); + return probeDecodingInfos(configuration).then(([res]) => { + expect(res).toBe(ProberStatus.NotSupported); + expect(decodingInfoStub).toHaveBeenCalledTimes(1); + }); }); it("should return `NotSupported` if no decodingInfo support", () => { @@ -333,15 +279,10 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { }, }; expect.assertions(2); - return probeDecodingInfos(configuration) - .then(([res]) => { - expect(res).toBe(ProberStatus.NotSupported); - expect(decodingInfoStub).toHaveBeenCalledTimes(1); - resetDecodingInfos(); - }) - .catch(() => { - resetDecodingInfos(); - }); + return probeDecodingInfos(configuration).then(([res]) => { + expect(res).toBe(ProberStatus.NotSupported); + expect(decodingInfoStub).toHaveBeenCalledTimes(1); + }); }); it("should resolve with `NotSupported` if decodingInfo throws", () => { @@ -363,14 +304,9 @@ describe("MediaCapabilitiesProber probers - decodingInfo", () => { }, }; expect.assertions(2); - return probeDecodingInfos(configuration) - .then(([res]) => { - expect(res).toBe(ProberStatus.NotSupported); - expect(decodingInfoStub).toHaveBeenCalledTimes(1); - resetDecodingInfos(); - }) - .catch(() => { - resetDecodingInfos(); - }); + return probeDecodingInfos(configuration).then(([res]) => { + expect(res).toBe(ProberStatus.NotSupported); + expect(decodingInfoStub).toHaveBeenCalledTimes(1); + }); }); }); diff --git a/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/defaultCodecFinder.test.ts b/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/defaultCodecFinder.test.ts index 3a3b0012eb..ff6d33406b 100644 --- a/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/defaultCodecFinder.test.ts +++ b/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/defaultCodecFinder.test.ts @@ -1,15 +1,30 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type { - findDefaultVideoCodec as IFindDefaultVideoCodec, - findDefaultAudioCodec as IFindDefaultAudioCodec, +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import { + findDefaultVideoCodec, + findDefaultAudioCodec, } from "../../probers/defaultCodecsFinder"; +const mocks = vi.hoisted(() => { + return { + default: { + MediaSource_: {} as unknown, + }, + }; +}); + +vi.mock("../../../../../compat/browser_compatibility_types", () => { + return mocks; +}); + describe("MediaCapabilitiesProber probers - findDefaultVideoCodec", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + mocks.default.MediaSource_ = {}; + }); - it("should find default video codec", async () => { + it("should find default video codec", () => { const mockIsTypeSupported = vi.fn((codec: string) => { return ( codec === 'video/mp4;codecs="avc1.4d401e"' || @@ -17,53 +32,34 @@ describe("MediaCapabilitiesProber probers - findDefaultVideoCodec", () => { codec === 'video/webm;codecs="vp8"' ); }); - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: mockIsTypeSupported, - }, - })); - const findDefaultVideoCodec = ( - await vi.importActual("../../probers/defaultCodecsFinder") - ).findDefaultVideoCodec as typeof IFindDefaultVideoCodec; + + mocks.default.MediaSource_ = { + isTypeSupported: mockIsTypeSupported, + }; expect(findDefaultVideoCodec()).toBe('video/mp4;codecs="avc1.4d401e"'); expect(mockIsTypeSupported).toHaveBeenCalledTimes(1); }); - it("should not find default video codec", async () => { + it("should not find default video codec", () => { const mockIsTypeSupported = vi.fn(() => false); - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: mockIsTypeSupported, - }, - })); - const findDefaultVideoCodec = ( - await vi.importActual("../../probers/defaultCodecsFinder") - ).findDefaultVideoCodec as typeof IFindDefaultVideoCodec; + mocks.default.MediaSource_ = { + isTypeSupported: mockIsTypeSupported, + }; expect(() => { findDefaultVideoCodec(); }).toThrowError("No default video codec found."); expect(mockIsTypeSupported).toHaveBeenCalledTimes(4); }); - it("should throw because no MediaSource", async () => { - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: null, - })); - const findDefaultVideoCodec = ( - await vi.importActual("../../probers/defaultCodecsFinder") - ).findDefaultVideoCodec as typeof IFindDefaultVideoCodec; + it("should throw because no MediaSource", () => { + mocks.default.MediaSource_ = null; expect(() => { findDefaultVideoCodec(); }).toThrowError("Cannot check video codec support: No API available."); }); - it("should throw because no isTypeSupported", async () => { - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: {}, - })); - const findDefaultVideoCodec = ( - await vi.importActual("../../probers/defaultCodecsFinder") - ).findDefaultVideoCodec as typeof IFindDefaultVideoCodec; + it("should throw because no isTypeSupported", () => { + mocks.default.MediaSource_ = {}; expect(() => { findDefaultVideoCodec(); }).toThrowError("Cannot check video codec support: No API available."); @@ -75,59 +71,39 @@ describe("MediaCapabilitiesProber probers - findDefaultAudioCodec", () => { vi.resetModules(); }); - it("should find default audio codec", async () => { + it("should find default audio codec", () => { const mockIsTypeSupported = vi.fn((codec: string) => { return ( codec === 'audio/mp4;codecs="mp4a.40.2"' || codec === "audio/webm;codecs=opus" ); }); - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: mockIsTypeSupported, - }, - })); - const findDefaultAudioCodec = ( - await vi.importActual("../../probers/defaultCodecsFinder") - ).findDefaultAudioCodec as typeof IFindDefaultAudioCodec; + mocks.default.MediaSource_ = { + isTypeSupported: mockIsTypeSupported, + }; expect(findDefaultAudioCodec()).toBe('audio/mp4;codecs="mp4a.40.2"'); expect(mockIsTypeSupported).toHaveBeenCalledTimes(1); }); - it("should not find default audio codec", async () => { + it("should not find default audio codec", () => { const mockIsTypeSupported = vi.fn(() => false); - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: mockIsTypeSupported, - }, - })); - const findDefaultAudioCodec = ( - await vi.importActual("../../probers/defaultCodecsFinder") - ).findDefaultAudioCodec as typeof IFindDefaultAudioCodec; + mocks.default.MediaSource_ = { + isTypeSupported: mockIsTypeSupported, + }; expect(() => { findDefaultAudioCodec(); }).toThrowError("No default audio codec found."); expect(mockIsTypeSupported).toHaveBeenCalledTimes(2); }); - it("should throw because no MediaSource", async () => { - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: null, - })); - const findDefaultAudioCodec = ( - await vi.importActual("../../probers/defaultCodecsFinder") - ).findDefaultAudioCodec as typeof IFindDefaultAudioCodec; + it("should throw because no MediaSource", () => { + mocks.default.MediaSource_ = null; expect(() => { findDefaultAudioCodec(); }).toThrowError("Cannot check audio codec support: No API available."); }); - it("should throw because no isTypeSupported", async () => { - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: {}, - })); - const findDefaultAudioCodec = ( - await vi.importActual("../../probers/defaultCodecsFinder") - ).findDefaultAudioCodec as typeof IFindDefaultAudioCodec; + it("should throw because no isTypeSupported", () => { + mocks.default.MediaSource_ = {}; expect(() => { findDefaultAudioCodec(); }).toThrow("Cannot check audio codec support: No API available."); diff --git a/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/mediaContentType.test.ts b/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/mediaContentType.test.ts index 895e5f0021..b9025800b6 100644 --- a/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/mediaContentType.test.ts +++ b/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/mediaContentType.test.ts @@ -1,35 +1,40 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IProbeMediaContentType from "../../probers/mediaContentType"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import probeMediaContentType from "../../probers/mediaContentType"; import { ProberStatus } from "../../types"; import type { IMediaConfiguration } from "../../types"; +const mocks = vi.hoisted(() => { + return { + default: { + MediaSource_: {} as unknown, + }, + }; +}); + +vi.mock("../../../../../compat/browser_compatibility_types", () => { + return mocks; +}); + describe("MediaCapabilitiesProber - probers probeMediaContentType", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + mocks.default.MediaSource_ = {}; + }); - it("should throw if no compatible MediaSource API", async () => { - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: null, - })); - const probeMediaContentType = ( - await vi.importActual("../../probers/mediaContentType") - ).default as typeof IProbeMediaContentType; + it("should throw if no compatible MediaSource API", () => { + mocks.default.MediaSource_ = null; // eslint-disable-next-line @typescript-eslint/no-floating-promises expect(probeMediaContentType({})).rejects.toThrowError( "MediaCapabilitiesProber >>> API_CALL: " + "MediaSource API not available", ); }); - it("should throw if no compatible isTypeSupported API", async () => { - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: false, - }, - })); - const probeMediaContentType = ( - await vi.importActual("../../probers/mediaContentType") - ).default as typeof IProbeMediaContentType; + it("should throw if no compatible isTypeSupported API", () => { + mocks.default.MediaSource_ = { + isTypeSupported: false, + }; // eslint-disable-next-line @typescript-eslint/no-floating-promises expect(probeMediaContentType({})).rejects.toThrowError( "MediaCapabilitiesProber >>> API_CALL: " + "isTypeSupported not available", @@ -38,17 +43,12 @@ describe("MediaCapabilitiesProber - probers probeMediaContentType", () => { it("should throw if no specified contentType in config", async () => { const mockIsTypeSupported = vi.fn(() => true); - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: mockIsTypeSupported, - }, - })); + mocks.default.MediaSource_ = { + isTypeSupported: mockIsTypeSupported, + }; const config: IMediaConfiguration = { type: "media-source", }; - const probeMediaContentType = ( - await vi.importActual("../../probers/mediaContentType") - ).default as typeof IProbeMediaContentType; expect.assertions(1); await probeMediaContentType(config).catch(({ message }: { message: string }) => { @@ -61,20 +61,15 @@ describe("MediaCapabilitiesProber - probers probeMediaContentType", () => { it("should resolve with `Supported` when video contentType is supported", async () => { const mockIsTypeSupported = vi.fn(() => true); - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: mockIsTypeSupported, - }, - })); + mocks.default.MediaSource_ = { + isTypeSupported: mockIsTypeSupported, + }; const config: IMediaConfiguration = { type: "media-source", video: { contentType: "video/mp5", }, }; - const probeMediaContentType = ( - await vi.importActual("../../probers/mediaContentType") - ).default as typeof IProbeMediaContentType; expect.assertions(2); await probeMediaContentType(config) @@ -89,20 +84,15 @@ describe("MediaCapabilitiesProber - probers probeMediaContentType", () => { it("should resolve with `Supported` when audio contentType is supported", async () => { const mockIsTypeSupported = vi.fn(() => true); - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: mockIsTypeSupported, - }, - })); + mocks.default.MediaSource_ = { + isTypeSupported: mockIsTypeSupported, + }; const config: IMediaConfiguration = { type: "media-source", audio: { contentType: "audio/wma", }, }; - const probeMediaContentType = ( - await vi.importActual("../../probers/mediaContentType") - ).default as typeof IProbeMediaContentType; expect.assertions(2); await probeMediaContentType(config) @@ -117,11 +107,9 @@ describe("MediaCapabilitiesProber - probers probeMediaContentType", () => { it("should resolve with `Supported` when both contentTypes are supported", async () => { const mockIsTypeSupported = vi.fn(() => true); - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: mockIsTypeSupported, - }, - })); + mocks.default.MediaSource_ = { + isTypeSupported: mockIsTypeSupported, + }; const config: IMediaConfiguration = { type: "media-source", audio: { @@ -131,9 +119,6 @@ describe("MediaCapabilitiesProber - probers probeMediaContentType", () => { contentType: "video/mp5", }, }; - const probeMediaContentType = ( - await vi.importActual("../../probers/mediaContentType") - ).default as typeof IProbeMediaContentType; expect.assertions(2); await probeMediaContentType(config) @@ -148,20 +133,15 @@ describe("MediaCapabilitiesProber - probers probeMediaContentType", () => { it("should return `NotSupported` when audio contentType is not supported", async () => { const mockIsTypeSupported = vi.fn(() => false); - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: mockIsTypeSupported, - }, - })); + mocks.default.MediaSource_ = { + isTypeSupported: mockIsTypeSupported, + }; const config: IMediaConfiguration = { type: "media-source", audio: { contentType: "audio/wma", }, }; - const probeMediaContentType = ( - await vi.importActual("../../probers/mediaContentType") - ).default as typeof IProbeMediaContentType; expect.assertions(2); await probeMediaContentType(config) @@ -176,20 +156,15 @@ describe("MediaCapabilitiesProber - probers probeMediaContentType", () => { it("should return `NotSupported` when video contentType is not supported", async () => { const mockIsTypeSupported = vi.fn(() => false); - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: mockIsTypeSupported, - }, - })); + mocks.default.MediaSource_ = { + isTypeSupported: mockIsTypeSupported, + }; const config: IMediaConfiguration = { type: "media-source", video: { contentType: "video/mp5", }, }; - const probeMediaContentType = ( - await vi.importActual("../../probers/mediaContentType") - ).default as typeof IProbeMediaContentType; expect.assertions(2); await probeMediaContentType(config) @@ -204,11 +179,9 @@ describe("MediaCapabilitiesProber - probers probeMediaContentType", () => { it("should resolve with `NotSupported` when contentTypes are not supported", async () => { const mockIsTypeSupported = vi.fn(() => false); - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: mockIsTypeSupported, - }, - })); + mocks.default.MediaSource_ = { + isTypeSupported: mockIsTypeSupported, + }; const config: IMediaConfiguration = { type: "media-source", video: { @@ -218,9 +191,6 @@ describe("MediaCapabilitiesProber - probers probeMediaContentType", () => { contentType: "audio/wma", }, }; - const probeMediaContentType = ( - await vi.importActual("../../probers/mediaContentType") - ).default as typeof IProbeMediaContentType; expect.assertions(2); await probeMediaContentType(config) @@ -237,11 +207,9 @@ describe("MediaCapabilitiesProber - probers probeMediaContentType", () => { const mockIsTypeSupported = vi.fn((type: string) => { return type === "video/mp5"; }); - vi.doMock("../../../../../compat/browser_compatibility_types", () => ({ - MediaSource_: { - isTypeSupported: mockIsTypeSupported, - }, - })); + mocks.default.MediaSource_ = { + isTypeSupported: mockIsTypeSupported, + }; const config: IMediaConfiguration = { type: "media-source", video: { @@ -251,9 +219,6 @@ describe("MediaCapabilitiesProber - probers probeMediaContentType", () => { contentType: "audio/wma", }, }; - const probeMediaContentType = ( - await vi.importActual("../../probers/mediaContentType") - ).default as typeof IProbeMediaContentType; expect.assertions(2); await probeMediaContentType(config) diff --git a/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/mediaDisplayInfos.test.ts b/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/mediaDisplayInfos.test.ts index e730f32097..c1c9729a57 100644 --- a/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/mediaDisplayInfos.test.ts +++ b/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/mediaDisplayInfos.test.ts @@ -1,19 +1,16 @@ import { describe, it, expect, vi } from "vitest"; import globalScope from "../../../../../utils/global_scope"; -import type IProbeMediaDisplayInfos from "../../probers/mediaDisplayInfos"; +import probeMediaDisplayInfos from "../../probers/mediaDisplayInfos"; import { ProberStatus } from "../../types"; describe("MediaCapabilitiesProber probers probeMediaDisplayInfos", () => { - it("should throw if matchMedia is undefined", async () => { + it("should throw if matchMedia is undefined", () => { // eslint-disable-next-line @typescript-eslint/unbound-method const origMatchMedia = globalScope.matchMedia; ( globalScope as { matchMedia: typeof globalScope.matchMedia | undefined } ).matchMedia = undefined; - const probeMediaDisplayInfos = ( - await vi.importActual("../../probers/mediaDisplayInfos") - ).default as typeof IProbeMediaDisplayInfos; // eslint-disable-next-line @typescript-eslint/no-floating-promises expect(probeMediaDisplayInfos({})).rejects.toThrowError( "MediaCapabilitiesProber >>> API_CALL: matchMedia not available", @@ -32,10 +29,6 @@ describe("MediaCapabilitiesProber probers probeMediaDisplayInfos", () => { display: {}, }; - const probeMediaDisplayInfos = ( - await vi.importActual("../../probers/mediaDisplayInfos") - ).default as typeof IProbeMediaDisplayInfos; - expect.assertions(1); return probeMediaDisplayInfos(config) .then(() => { @@ -61,10 +54,6 @@ describe("MediaCapabilitiesProber probers probeMediaDisplayInfos", () => { globalScope.matchMedia = mockMatchMedia as unknown as typeof globalScope.matchMedia; const config = {}; - const probeMediaDisplayInfos = ( - await vi.importActual("../../probers/mediaDisplayInfos") - ).default as typeof IProbeMediaDisplayInfos; - expect.assertions(1); return probeMediaDisplayInfos(config) .then(() => { @@ -96,10 +85,6 @@ describe("MediaCapabilitiesProber probers probeMediaDisplayInfos", () => { }, }; - const probeMediaDisplayInfos = ( - await vi.importActual("../../probers/mediaDisplayInfos") - ).default as typeof IProbeMediaDisplayInfos; - expect.assertions(2); return probeMediaDisplayInfos(config) .then(() => { @@ -132,10 +117,6 @@ describe("MediaCapabilitiesProber probers probeMediaDisplayInfos", () => { }, }; - const probeMediaDisplayInfos = ( - await vi.importActual("../../probers/mediaDisplayInfos") - ).default as typeof IProbeMediaDisplayInfos; - expect.assertions(2); return probeMediaDisplayInfos(config) .then(([res]) => { @@ -165,10 +146,6 @@ describe("MediaCapabilitiesProber probers probeMediaDisplayInfos", () => { }, }; - const probeMediaDisplayInfos = ( - await vi.importActual("../../probers/mediaDisplayInfos") - ).default as typeof IProbeMediaDisplayInfos; - expect.assertions(2); return probeMediaDisplayInfos(config) .then(([res]) => { diff --git a/src/experimental/tools/mediaCapabilitiesProber/probers/defaultCodecsFinder.ts b/src/experimental/tools/mediaCapabilitiesProber/probers/defaultCodecsFinder.ts index 69dac72480..1aca2fd0fe 100644 --- a/src/experimental/tools/mediaCapabilitiesProber/probers/defaultCodecsFinder.ts +++ b/src/experimental/tools/mediaCapabilitiesProber/probers/defaultCodecsFinder.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { MediaSource_ } from "../../../../compat/browser_compatibility_types"; +import BROWSER_GLOBALS from "../../../../compat/browser_compatibility_types"; import isNullOrUndefined from "../../../../utils/is_null_or_undefined"; /** @@ -30,6 +30,7 @@ export function findDefaultVideoCodec(): string { 'video/mp4;codecs="hvc1.1.6.L93.B0"', 'video/webm;codecs="vp8"', ]; + const { MediaSource_ } = BROWSER_GLOBALS; if ( isNullOrUndefined(MediaSource_) || typeof MediaSource_.isTypeSupported !== "function" @@ -52,6 +53,7 @@ export function findDefaultVideoCodec(): string { */ export function findDefaultAudioCodec(): string { const audioCodecs = ['audio/mp4;codecs="mp4a.40.2"', "audio/webm;codecs=opus"]; + const { MediaSource_ } = BROWSER_GLOBALS; if ( isNullOrUndefined(MediaSource_) || typeof MediaSource_.isTypeSupported !== "function" diff --git a/src/experimental/tools/mediaCapabilitiesProber/probers/mediaContentType.ts b/src/experimental/tools/mediaCapabilitiesProber/probers/mediaContentType.ts index e0719df820..e35a077b0e 100644 --- a/src/experimental/tools/mediaCapabilitiesProber/probers/mediaContentType.ts +++ b/src/experimental/tools/mediaCapabilitiesProber/probers/mediaContentType.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { MediaSource_ } from "../../../../compat/browser_compatibility_types"; +import BROWSER_GLOBALS from "../../../../compat/browser_compatibility_types"; import isNullOrUndefined from "../../../../utils/is_null_or_undefined"; import type { IMediaConfiguration } from "../types"; import { ProberStatus } from "../types"; @@ -27,6 +27,7 @@ export default function probeContentType( config: IMediaConfiguration, ): Promise<[ProberStatus]> { return new Promise((resolve) => { + const { MediaSource_ } = BROWSER_GLOBALS; if (isNullOrUndefined(MediaSource_)) { throw new Error( "MediaCapabilitiesProber >>> API_CALL: " + "MediaSource API not available", diff --git a/src/features/__tests__/add_features.test.ts b/src/features/__tests__/add_features.test.ts index a8670a7797..701bbae000 100644 --- a/src/features/__tests__/add_features.test.ts +++ b/src/features/__tests__/add_features.test.ts @@ -1,31 +1,23 @@ import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IAddFeatures from "../add_features"; +import addFeatures from "../add_features"; import type { IFeature } from "../types"; +vi.mock("../features_object", () => { + return { + default: { a: 412 }, + }; +}); + describe("Features - addFeatures", () => { beforeEach(() => { vi.resetModules(); }); - it("should do nothing if an empty array is given", async () => { - const feat = {}; - vi.doMock("../features_object", () => ({ - default: feat, - })); - const addFeatures = (await vi.importActual("../add_features")) - .default as typeof IAddFeatures; - + it("should do nothing if an empty array is given", () => { expect(() => addFeatures([])).not.toThrow(); }); - it("should throw if something different than a function is given", async () => { - const feat = {}; - vi.doMock("../features_object", () => ({ - default: feat, - })); - const addFeatures = (await vi.importActual("../add_features")) - .default as typeof IAddFeatures; - + it("should throw if something different than a function is given", () => { expect(() => addFeatures([5 as unknown as IFeature])).toThrow( new Error("Unrecognized feature"), ); @@ -39,20 +31,13 @@ describe("Features - addFeatures", () => { ).toThrow(new Error("Unrecognized feature")); }); - it("should call the given functions with the features object in argument", async () => { - const feat = { a: 412 }; - vi.doMock("../features_object", () => ({ - default: feat, - })); - const addFeatures = (await vi.importActual("../add_features")) - .default as typeof IAddFeatures; - + it("should call the given functions with the features object in argument", () => { const fakeFeat1 = vi.fn(); const fakeFeat2 = vi.fn(); addFeatures([fakeFeat1, fakeFeat2]); expect(fakeFeat1).toHaveBeenCalledTimes(1); - expect(fakeFeat1).toHaveBeenCalledWith(feat); + expect(fakeFeat1).toHaveBeenCalledWith({ a: 412 }); expect(fakeFeat2).toHaveBeenCalledTimes(1); - expect(fakeFeat2).toHaveBeenCalledWith(feat); + expect(fakeFeat2).toHaveBeenCalledWith({ a: 412 }); }); }); diff --git a/src/main_thread/api/__tests__/option_utils.test.ts b/src/main_thread/api/__tests__/option_utils.test.ts index af8cf20323..13f4649a3f 100644 --- a/src/main_thread/api/__tests__/option_utils.test.ts +++ b/src/main_thread/api/__tests__/option_utils.test.ts @@ -1,43 +1,36 @@ -import type { MockInstance } from "vitest"; -import { describe, beforeEach, afterEach, it, expect, vi } from "vitest"; +import { describe, afterEach, it, expect, vi } from "vitest"; import config from "../../../config"; +import log from "../../../log"; import type { IAudioTrackSwitchingMode, IKeySystemOption, ILoadVideoOptions, IStartAtOption, } from "../../../public_types"; -import type { - parseConstructorOptions as IParseConstructorOptions, - parseLoadVideoOptions as IParseLoadVideoOptions, - checkReloadOptions as ICheckReloadOptions, +import { + parseConstructorOptions, + parseLoadVideoOptions, + checkReloadOptions, } from "../option_utils"; -let warnOnceMock: MockInstance; -let logWarnMock: MockInstance; +const mocks = vi.hoisted(() => { + return { + warnOnce: vi.fn(), + }; +}); +vi.mock("../../../utils/languages"); +vi.mock("../../../utils/warn_once", () => { + return { default: mocks.warnOnce }; +}); +const logWarn = vi.spyOn(log, "warn").mockImplementation(() => { + /* noop */ +}); describe("API - parseConstructorOptions", () => { - let parseConstructorOptions: typeof IParseConstructorOptions; - beforeEach(async () => { - warnOnceMock = vi.fn(); - logWarnMock = vi.fn(); - vi.doMock("../../../log", () => { - return { - default: { - warn: logWarnMock, - }, - }; - }); - vi.doMock("../../../utils/languages"); - vi.doMock("../../../utils/warn_once", () => { - return { default: warnOnceMock }; - }); - parseConstructorOptions = (await vi.importActual("../option_utils")) - .parseConstructorOptions as typeof IParseConstructorOptions; - }); - afterEach(() => { vi.resetModules(); + logWarn.mockClear(); + mocks.warnOnce.mockReset(); }); const videoElement = document.createElement("video"); @@ -255,27 +248,10 @@ describe("API - parseConstructorOptions", () => { }); describe("API - parseLoadVideoOptions", () => { - let parseLoadVideoOptions: typeof IParseLoadVideoOptions; - beforeEach(async () => { - warnOnceMock = vi.fn(); - logWarnMock = vi.fn(); - vi.doMock("../../../log", () => { - return { - default: { - warn: logWarnMock, - }, - }; - }); - vi.doMock("../../../utils/languages"); - vi.doMock("../../../utils/warn_once", () => { - return { default: warnOnceMock }; - }); - parseLoadVideoOptions = (await vi.importActual("../option_utils")) - .parseLoadVideoOptions as typeof IParseLoadVideoOptions; - }); - afterEach(() => { vi.resetModules(); + logWarn.mockClear(); + mocks.warnOnce.mockReset(); }); const defaultLoadVideoOptions = { @@ -679,7 +655,7 @@ describe("API - parseLoadVideoOptions", () => { }); it("should set an 'undefined' defaultAudioTrackSwitchingMode mode when the parameter is invalid or not specified", () => { - logWarnMock.mockReturnValue(undefined); + logWarn.mockReturnValue(undefined); expect( parseLoadVideoOptions({ defaultAudioTrackSwitchingMode: "foo-bar" as unknown as IAudioTrackSwitchingMode, @@ -692,16 +668,16 @@ describe("API - parseLoadVideoOptions", () => { transport: "bar", defaultAudioTrackSwitchingMode: undefined, }); - expect(logWarnMock).toHaveBeenCalledTimes(1); - expect(logWarnMock).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "The `defaultAudioTrackSwitchingMode` loadVideo option must match one of " + `the following strategy name: - \`seamless\` - \`direct\` - \`reload\``, ); - logWarnMock.mockReset(); - logWarnMock.mockReturnValue(undefined); + logWarn.mockClear(); + logWarn.mockReturnValue(undefined); expect( parseLoadVideoOptions({ @@ -714,7 +690,7 @@ describe("API - parseLoadVideoOptions", () => { transport: "bar", defaultAudioTrackSwitchingMode: undefined, }); - expect(logWarnMock).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should authorize setting a valid onCodecSwitch option", () => { @@ -746,7 +722,7 @@ describe("API - parseLoadVideoOptions", () => { }); it("should set a 'continue' onCodecSwitch when the parameter is invalid or not specified", () => { - logWarnMock.mockReturnValue(undefined); + logWarn.mockReturnValue(undefined); expect( parseLoadVideoOptions({ onCodecSwitch: "foo-bar" as unknown as "continue", @@ -759,16 +735,16 @@ describe("API - parseLoadVideoOptions", () => { transport: "bar", onCodecSwitch: "continue", }); - expect(logWarnMock).toHaveBeenCalledTimes(1); - expect(logWarnMock).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "The `onCodecSwitch` loadVideo option must match one " + `of the following string: - \`continue\` - \`reload\` If badly set, continue will be used as default`, ); - logWarnMock.mockReset(); - logWarnMock.mockReturnValue(undefined); + logWarn.mockClear(); + logWarn.mockReturnValue(undefined); expect( parseLoadVideoOptions({ @@ -781,7 +757,7 @@ If badly set, continue will be used as default`, transport: "bar", onCodecSwitch: "continue", }); - expect(logWarnMock).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should authorize setting a valid enableFastSwitching option", () => { @@ -1040,7 +1016,7 @@ If badly set, continue will be used as default`, }); it("should warn when setting a textTrackElement with a `native` textTrackMode", () => { - logWarnMock.mockReturnValue(undefined); + logWarn.mockReturnValue(undefined); const textTrackElement = document.createElement("div"); parseLoadVideoOptions({ @@ -1048,7 +1024,7 @@ If badly set, continue will be used as default`, url: "foo", transport: "bar", }); - expect(logWarnMock).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); expect( parseLoadVideoOptions({ @@ -1064,8 +1040,8 @@ If badly set, continue will be used as default`, textTrackMode: "native", }); - expect(logWarnMock).toHaveBeenCalledTimes(1); - expect(logWarnMock).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "API: You have set a textTrackElement " + 'without being in an "html" textTrackMode. It will be ignored.', ); @@ -1073,11 +1049,6 @@ If badly set, continue will be used as default`, }); describe("API - checkReloadOptions", () => { - let checkReloadOptions: typeof ICheckReloadOptions; - beforeEach(async () => { - checkReloadOptions = (await vi.importActual("../option_utils")) - .checkReloadOptions as typeof ICheckReloadOptions; - }); it("Should valid undefined options", () => { const options = undefined; expect(() => checkReloadOptions(options)).not.toThrow(); diff --git a/src/main_thread/api/__tests__/public_api.test.ts b/src/main_thread/api/__tests__/public_api.test.ts index 3024f1d017..db0bf310c3 100644 --- a/src/main_thread/api/__tests__/public_api.test.ts +++ b/src/main_thread/api/__tests__/public_api.test.ts @@ -1,5 +1,5 @@ import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IPublicAPI from "../public_api"; +import PublicAPI from "../public_api"; describe("API - Public API", () => { beforeEach(() => { @@ -8,17 +8,13 @@ describe("API - Public API", () => { describe("static properties", () => { describe("ErrorTypes", () => { - it("should expose static ErrorTypes property", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should expose static ErrorTypes property", () => { expect(typeof PublicAPI.ErrorTypes).toBe("object"); }); }); describe("ErrorCodes", () => { - it("should expose static ErrorCodes property", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should expose static ErrorCodes property", () => { expect(typeof PublicAPI.ErrorTypes).toBe("object"); }); }); @@ -26,45 +22,35 @@ describe("API - Public API", () => { describe("public methods", () => { describe("getError", () => { - it("should have no error by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should have no error by default", () => { const player = new PublicAPI(); expect(player.getError()).toBe(null); }); }); describe("getPlayerState", () => { - it('should return "STOPPED" in getPlayerState by default', async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it('should return "STOPPED" in getPlayerState by default', () => { const player = new PublicAPI(); expect(player.getPlayerState()).toBe("STOPPED"); }); }); describe("isLive", () => { - it("should return false in isLive by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return false in isLive by default", () => { const player = new PublicAPI(); expect(player.isLive()).toBe(false); }); }); describe("getContentUrls", () => { - it("should return undefined in getContentUrls by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return undefined in getContentUrls by default", () => { const player = new PublicAPI(); expect(player.getContentUrls()).toBe(undefined); }); }); describe("getMediaDuration", () => { - it("should return the video element initial duration in getMediaDuration by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return the video element initial duration in getMediaDuration by default", () => { const player = new PublicAPI(); // ! HAHA ! NaN is not === to NaN @@ -77,99 +63,77 @@ describe("API - Public API", () => { }); describe("getCurrentBufferGap", () => { - it("should return 0 in getCurrentBufferGap by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return 0 in getCurrentBufferGap by default", () => { const player = new PublicAPI(); expect(player.getCurrentBufferGap()).toBe(0); }); }); describe("getWallClockTime", () => { - it("should return 0 in getWallClockTime by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return 0 in getWallClockTime by default", () => { const player = new PublicAPI(); expect(player.getWallClockTime()).toBe(0); }); }); describe("getPosition", () => { - it("should return 0 in getPosition by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return 0 in getPosition by default", () => { const player = new PublicAPI(); expect(player.getPosition()).toBe(0); }); }); describe("getPlaybackRate", () => { - it("should return 1 in getPlaybackRate by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return 1 in getPlaybackRate by default", () => { const player = new PublicAPI(); expect(player.getPlaybackRate()).toBe(1); }); }); describe("getVolume", () => { - it("should return 1 in getVolume by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return 1 in getVolume by default", () => { const player = new PublicAPI(); expect(player.getVolume()).toBe(1); }); }); describe("getVideoRepresentation", () => { - it("should return undefined in getVideoRepresentation by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return undefined in getVideoRepresentation by default", () => { const player = new PublicAPI(); expect(player.getVideoRepresentation()).toBe(undefined); }); }); describe("getAudioRepresentation", () => { - it("should return undefined in getAudioRepresentation by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return undefined in getAudioRepresentation by default", () => { const player = new PublicAPI(); expect(player.getAudioRepresentation()).toBe(undefined); }); }); describe("getWantedBufferAhead", () => { - it("should return 30 in getWantedBufferAhead by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return 30 in getWantedBufferAhead by default", () => { const player = new PublicAPI(); expect(player.getWantedBufferAhead()).toBe(30); }); }); describe("getMaxBufferBehind", () => { - it("should return Infinity in getMaxBufferBehind by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return Infinity in getMaxBufferBehind by default", () => { const player = new PublicAPI(); expect(player.getMaxBufferBehind()).toBe(Infinity); }); }); describe("getMaxBufferAhead", () => { - it("should return Infinity in getMaxBufferAhead by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return Infinity in getMaxBufferAhead by default", () => { const player = new PublicAPI(); expect(player.getMaxBufferAhead()).toBe(Infinity); }); }); describe("getPlaybackRate/setPlaybackRate", () => { - it("should allow to change the playback rate through setPlaybackRate", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should allow to change the playback rate through setPlaybackRate", () => { const player = new PublicAPI(); player.setPlaybackRate(4); expect(player.getPlaybackRate()).toBe(4); @@ -192,9 +156,7 @@ describe("API - Public API", () => { }); describe("seekTo", () => { - it("should throw in seekTo by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should throw in seekTo by default", () => { const player = new PublicAPI(); expect(() => player.seekTo(10)).toThrow(); expect(() => player.seekTo(54)).toThrow(); @@ -205,16 +167,12 @@ describe("API - Public API", () => { }); describe("getVolume/setVolume", () => { - it("should throw in setVolume by default if no volume has been given", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should throw in setVolume by default if no volume has been given", () => { const player = new PublicAPI(); expect(() => player.setVolume(5)).toThrow(); }); - it("should set the volume in setVolume by default if a volume has been given", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should set the volume in setVolume by default if a volume has been given", () => { const player = new PublicAPI(); const videoElement = player.getVideoElement(); if (videoElement === null) { @@ -232,9 +190,7 @@ describe("API - Public API", () => { }); describe("mute/unMute/isMute", () => { - it("should keep the volume yet mute the media element in mute by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should keep the volume yet mute the media element in mute by default", () => { const player = new PublicAPI(); const videoElement = player.getVideoElement(); if (videoElement === null) { @@ -257,9 +213,7 @@ describe("API - Public API", () => { expect(videoElement.muted).toBe(false); }); - it("should unmute without changing the volume in unMute by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should unmute without changing the volume in unMute by default", () => { const player = new PublicAPI(); // back to a "normal" state. player.unMute(); @@ -290,16 +244,12 @@ describe("API - Public API", () => { expect(videoElement.muted).toBe(false); }); - it("should return false in isMute by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return false in isMute by default", () => { const player = new PublicAPI(); expect(player.isMute()).toBe(false); }); - it("should not return true in isMute if just the volume is equal to 0", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should not return true in isMute if just the volume is equal to 0", () => { const player = new PublicAPI(); expect(player.isMute()).toBe(false); @@ -310,9 +260,7 @@ describe("API - Public API", () => { }); describe("getMaxBufferBehind/setMaxBufferBehind", () => { - it("should update the max buffer behind through setMaxBufferBehind by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should update the max buffer behind through setMaxBufferBehind by default", () => { const player = new PublicAPI(); player.setMaxBufferBehind(50); expect(player.getMaxBufferBehind()).toBe(50); @@ -323,9 +271,7 @@ describe("API - Public API", () => { }); describe("getMaxBufferAhead/setMaxBufferAhead", () => { - it("should update the max buffer behind through setMaxBufferAhead by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should update the max buffer behind through setMaxBufferAhead by default", () => { const player = new PublicAPI(); player.setMaxBufferAhead(50); expect(player.getMaxBufferAhead()).toBe(50); @@ -336,9 +282,7 @@ describe("API - Public API", () => { }); describe("getWantedBufferAhead/setWantedBufferAhead", () => { - it("should update the buffer goal through setWantedBufferAhead by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should update the buffer goal through setWantedBufferAhead by default", () => { const player = new PublicAPI(); player.setWantedBufferAhead(50); expect(player.getWantedBufferAhead()).toBe(50); @@ -349,63 +293,49 @@ describe("API - Public API", () => { }); describe("getAvailableAudioTracks", () => { - it("should return an empty array through getAvailableAudioTracks by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return an empty array through getAvailableAudioTracks by default", () => { const player = new PublicAPI(); expect(player.getAvailableAudioTracks()).toEqual([]); }); }); describe("getAvailableTextTracks", () => { - it("should return an empty array through getAvailableTextTracks by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return an empty array through getAvailableTextTracks by default", () => { const player = new PublicAPI(); expect(player.getAvailableTextTracks()).toEqual([]); }); }); describe("getAvailableVideoTracks", () => { - it("should return an empty array through getAvailableVideoTracks by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return an empty array through getAvailableVideoTracks by default", () => { const player = new PublicAPI(); expect(player.getAvailableVideoTracks()).toEqual([]); }); }); describe("getAudioTrack", () => { - it("should return undefined through getAudioTrack by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return undefined through getAudioTrack by default", () => { const player = new PublicAPI(); expect(player.getAudioTrack()).toBe(undefined); }); }); describe("getTextTrack", () => { - it("should return undefined through getTextTrack by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return undefined through getTextTrack by default", () => { const player = new PublicAPI(); expect(player.getTextTrack()).toBe(undefined); }); }); describe("getVideoTrack", () => { - it("should return undefined through getVideoTrack by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return undefined through getVideoTrack by default", () => { const player = new PublicAPI(); expect(player.getVideoTrack()).toBe(undefined); }); }); describe("setAudioTrack", () => { - it("should throw in setAudioTrack by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should throw in setAudioTrack by default", () => { const player = new PublicAPI(); expect(() => player.setAudioTrack("a")).toThrow(); expect(() => player.setAudioTrack("test")).toThrow(); @@ -413,9 +343,7 @@ describe("API - Public API", () => { }); describe("setTextTrack", () => { - it("should throw in setTextTrack by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should throw in setTextTrack by default", () => { const player = new PublicAPI(); expect(() => player.setTextTrack("a")).toThrow(); expect(() => player.setTextTrack("test")).toThrow(); @@ -423,9 +351,7 @@ describe("API - Public API", () => { }); describe("setVideoTrack", () => { - it("should throw in setVideoTrack by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should throw in setVideoTrack by default", () => { const player = new PublicAPI(); expect(() => player.setVideoTrack("a")).toThrow(); expect(() => player.setVideoTrack("test")).toThrow(); @@ -433,9 +359,7 @@ describe("API - Public API", () => { }); describe("disableTextTrack", () => { - it("should disable text tracks in disableTextTrack by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should disable text tracks in disableTextTrack by default", () => { const player = new PublicAPI(); player.disableTextTrack(); expect(player.getTextTrack()).toBe(undefined); @@ -443,27 +367,21 @@ describe("API - Public API", () => { }); describe("getMinimumPosition", () => { - it("should return null in getMinimumPosition by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return null in getMinimumPosition by default", () => { const player = new PublicAPI(); expect(player.getMinimumPosition()).toBe(null); }); }); describe("getMaximumPosition", () => { - it("should return null in getMaximumPosition by default", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should return null in getMaximumPosition by default", () => { const player = new PublicAPI(); expect(player.getMinimumPosition()).toBe(null); }); }); describe("Player instantiation", () => { - it("should log a warning if creating two players attached to the same video element", async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + it("should log a warning if creating two players attached to the same video element", () => { const warn = vi.spyOn(console, "warn").mockImplementation(vi.fn()); const videoElement = document.createElement("video"); const player1 = new PublicAPI({ videoElement }); @@ -490,9 +408,7 @@ describe("API - Public API", () => { }); it(`should not log a warning if creating a player attached to - the same video element after the previous one was disposed`, async () => { - const PublicAPI = (await vi.importActual("../public_api")) - .default as typeof IPublicAPI; + the same video element after the previous one was disposed`, () => { const warn = vi.spyOn(console, "warn").mockImplementation(vi.fn()); const videoElement = document.createElement("video"); const player1 = new PublicAPI({ videoElement }); diff --git a/src/main_thread/decrypt/__tests__/__global__/find_key_system.test.ts b/src/main_thread/decrypt/__tests__/__global__/find_key_system.test.ts index aca5a9ea67..9f9dd9f576 100644 --- a/src/main_thread/decrypt/__tests__/__global__/find_key_system.test.ts +++ b/src/main_thread/decrypt/__tests__/__global__/find_key_system.test.ts @@ -1,42 +1,65 @@ -import type { MockInstance } from "vitest"; import { describe, beforeEach, it, expect, vi } from "vitest"; -import * as compat from "../../../../compat/can_rely_on_request_media_key_system_access"; -import eme from "../../../../compat/eme"; import { testKeySystem } from "../../find_key_system"; +const mocks = vi.hoisted(() => { + return { + requestMediaKeySystemAccess: vi.fn(), + canRelyOnRequestMediaKeySystemAccess: vi.fn(), + }; +}); + +vi.mock("../../../../compat/can_rely_on_request_media_key_system_access", () => { + return { + canRelyOnRequestMediaKeySystemAccess: mocks.canRelyOnRequestMediaKeySystemAccess, + }; +}); +vi.mock("../../../../compat/eme", () => ({ + default: { + onEncrypted: vi.fn(), + requestMediaKeySystemAccess: mocks.requestMediaKeySystemAccess, + setMediaKeys: vi.fn(), + }, + getInitData: vi.fn(), + generateKeyRequest: vi.fn(), + closeSession: vi.fn(), + loadSession: vi.fn(), +})); + describe("find_key_systems - ", () => { - let requestMediaKeySystemAccessMock: MockInstance; - let canRelyOnEMEMock: MockInstance; const keySystem = "com.microsoft.playready.recommendation"; beforeEach(() => { vi.resetModules(); vi.restoreAllMocks(); - requestMediaKeySystemAccessMock = vi.spyOn(eme, "requestMediaKeySystemAccess"); - canRelyOnEMEMock = vi.spyOn(compat, "canRelyOnRequestMediaKeySystemAccess"); + mocks.canRelyOnRequestMediaKeySystemAccess.mockReset(); + mocks.requestMediaKeySystemAccess.mockReset(); }); it("should resolve if the keySystem is supported", async () => { /* mock implementation of requestMediaKeySystemAccess that support the keySystem */ - requestMediaKeySystemAccessMock.mockImplementation(() => ({ + mocks.requestMediaKeySystemAccess.mockImplementation(() => ({ createMediaKeys: () => ({ createSession: () => ({ - // eslint-disable-next-line @typescript-eslint/no-empty-function - generateRequest: () => {}, + generateRequest: () => { + /* noop */ + }, + close: () => { + return Promise.resolve(); + }, }), }), })); await expect(testKeySystem(keySystem, [])).resolves.toBeTruthy(); - expect(requestMediaKeySystemAccessMock).toHaveBeenCalledTimes(1); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(1); }); it("should reject if the keySystem is not supported", async () => { /* mock implementation of requestMediaKeySystemAccess that does not support the keySystem */ - requestMediaKeySystemAccessMock.mockImplementation(() => { + mocks.requestMediaKeySystemAccess.mockImplementation(() => { throw new Error(); }); await expect(testKeySystem(keySystem, [])).rejects.toThrow(); - expect(requestMediaKeySystemAccessMock).toHaveBeenCalledTimes(1); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(1); }); it("should reject if the keySystem seems to be supported but the EME workflow fail", async () => { @@ -44,8 +67,8 @@ describe("find_key_systems - ", () => { but that is failing when performing the usual EME workflow of creating mediaKeys, creating a session and generating a request. */ - canRelyOnEMEMock.mockImplementation(() => false); - requestMediaKeySystemAccessMock.mockImplementation(() => ({ + mocks.canRelyOnRequestMediaKeySystemAccess.mockImplementation(() => false); + mocks.requestMediaKeySystemAccess.mockImplementation(() => ({ createMediaKeys: () => ({ createSession: () => ({ generateRequest: () => { @@ -55,6 +78,6 @@ describe("find_key_systems - ", () => { }), })); await expect(testKeySystem(keySystem, [])).rejects.toThrow(); - expect(requestMediaKeySystemAccessMock).toHaveBeenCalledTimes(1); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(1); }); }); diff --git a/src/main_thread/decrypt/__tests__/__global__/get_license.test.ts b/src/main_thread/decrypt/__tests__/__global__/get_license.test.ts index 216e74ae1b..a32982a40c 100644 --- a/src/main_thread/decrypt/__tests__/__global__/get_license.test.ts +++ b/src/main_thread/decrypt/__tests__/__global__/get_license.test.ts @@ -1,8 +1,8 @@ import { describe, afterEach, it, expect, vi } from "vitest"; import type { IKeySystemOption, IPlayerError } from "../../../../public_types"; import { concat } from "../../../../utils/byte_parsing"; -import type IContentDecryptor from "../../content_decryptor"; -import type { ContentDecryptorState as IContentDecryptorState } from "../../types"; +import ContentDecryptor from "../../content_decryptor"; +import { ContentDecryptorState } from "../../types"; import { formatFakeChallengeFromInitData, MediaKeySessionImpl, @@ -10,13 +10,46 @@ import { mockCompat, } from "./utils"; -/** Default video element used in our tests. */ -const videoElt = document.createElement("video"); +const mocks = vi.hoisted(() => { + return { + shouldRenewMediaKeySystemAccess: vi.fn(() => false), + canReuseMediaKeys: vi.fn(() => true), + onEncrypted: vi.fn(), + requestMediaKeySystemAccess: vi.fn(), + setMediaKeys: vi.fn(), + getInitData: vi.fn(), + generateKeyRequest: vi.fn(), + }; +}); +vi.mock("../../../../compat/should_renew_media_key_system_access", () => ({ + default: mocks.shouldRenewMediaKeySystemAccess, +})); +vi.mock("../../../../compat/can_reuse_media_keys", () => ({ + default: mocks.canReuseMediaKeys, +})); +vi.mock("../../../../compat/eme", () => ({ + default: { + onEncrypted: mocks.onEncrypted, + requestMediaKeySystemAccess: mocks.requestMediaKeySystemAccess, + setMediaKeys: mocks.setMediaKeys, + }, + getInitData: mocks.getInitData, + generateKeyRequest: mocks.generateKeyRequest, + closeSession: vi.fn(), + loadSession: vi.fn(), +})); describe("decrypt - global tests - getLicense", () => { afterEach(() => { vi.resetModules(); vi.restoreAllMocks(); + mocks.shouldRenewMediaKeySystemAccess.mockReset(); + mocks.canReuseMediaKeys.mockReset(); + mocks.onEncrypted.mockReset(); + mocks.requestMediaKeySystemAccess.mockReset(); + mocks.setMediaKeys.mockReset(); + mocks.getInitData.mockReset(); + mocks.generateKeyRequest.mockReset(); }); it("should update the session after getLicense resolves with a license", async () => { @@ -334,11 +367,8 @@ async function checkGetLicense({ } return Promise.reject(new Error("AAAA")); }); - mockCompat(); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; + const videoElt = document.createElement("video"); + mockCompat(mocks); return new Promise((res, rej) => { // == vars == /** Default keySystems configuration used in our tests. */ diff --git a/src/main_thread/decrypt/__tests__/__global__/init_data.test.ts b/src/main_thread/decrypt/__tests__/__global__/init_data.test.ts index 027b4e87ba..6b2a9cd122 100644 --- a/src/main_thread/decrypt/__tests__/__global__/init_data.test.ts +++ b/src/main_thread/decrypt/__tests__/__global__/init_data.test.ts @@ -1,6 +1,6 @@ import { describe, afterEach, it, expect, vi } from "vitest"; -import type IContentDecryptor from "../../content_decryptor"; -import type { ContentDecryptorState as IContentDecryptorState } from "../../types"; +import ContentDecryptor from "../../content_decryptor"; +import { ContentDecryptorState } from "../../types"; import { formatFakeChallengeFromInitData, MediaKeySessionImpl, @@ -8,6 +8,35 @@ import { mockCompat, } from "./utils"; +const mocks = vi.hoisted(() => { + return { + shouldRenewMediaKeySystemAccess: vi.fn(() => false), + canReuseMediaKeys: vi.fn(() => true), + onEncrypted: vi.fn(), + requestMediaKeySystemAccess: vi.fn(), + setMediaKeys: vi.fn(), + getInitData: vi.fn(), + generateKeyRequest: vi.fn(), + }; +}); +vi.mock("../../../../compat/should_renew_media_key_system_access", () => ({ + default: mocks.shouldRenewMediaKeySystemAccess, +})); +vi.mock("../../../../compat/can_reuse_media_keys", () => ({ + default: mocks.canReuseMediaKeys, +})); +vi.mock("../../../../compat/eme", () => ({ + default: { + onEncrypted: mocks.onEncrypted, + requestMediaKeySystemAccess: mocks.requestMediaKeySystemAccess, + setMediaKeys: mocks.setMediaKeys, + }, + getInitData: mocks.getInitData, + generateKeyRequest: mocks.generateKeyRequest, + closeSession: vi.fn(), + loadSession: vi.fn(), +})); + describe("decrypt - global tests - init data", () => { /** Default video element used in our tests. */ const videoElt = document.createElement("video"); @@ -24,19 +53,21 @@ describe("decrypt - global tests - init data", () => { afterEach(() => { vi.resetAllMocks(); vi.resetModules(); + mocks.shouldRenewMediaKeySystemAccess.mockReset(); + mocks.canReuseMediaKeys.mockReset(); + mocks.onEncrypted.mockReset(); + mocks.requestMediaKeySystemAccess.mockReset(); + mocks.setMediaKeys.mockReset(); + mocks.getInitData.mockReset(); + mocks.generateKeyRequest.mockReset(); }); - it("should create a session and generate a request when init data is sent through the arguments", async () => { - // == mocks == - const { mockGenerateKeyRequest } = mockCompat(); + it("should create a session and generate a request when init data is sent through the arguments", () => { + mockCompat(mocks); const mediaKeySession = new MediaKeySessionImpl(); const mockCreateSession = vi .spyOn(MediaKeysImpl.prototype, "createSession") .mockReturnValue(mediaKeySession); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { // == vars == const initData = new Uint8Array([54, 55, 75]); @@ -45,7 +76,7 @@ describe("decrypt - global tests - init data", () => { const contentDecryptor = new ContentDecryptor(videoElt, ksConfig); contentDecryptor.addEventListener( "stateChange", - (newState: IContentDecryptorState) => { + (newState: ContentDecryptorState) => { if (newState !== ContentDecryptorState.WaitingForAttachment) { rej(new Error(`Unexpected state: ${newState}`)); } @@ -61,8 +92,8 @@ describe("decrypt - global tests - init data", () => { try { expect(mockCreateSession).toHaveBeenCalledTimes(1); expect(mockCreateSession).toHaveBeenCalledWith("temporary"); - expect(mockGenerateKeyRequest).toHaveBeenCalledTimes(1); - expect(mockGenerateKeyRequest).toHaveBeenCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenCalledTimes(1); + expect(mocks.generateKeyRequest).toHaveBeenCalledWith( mediaKeySession, "cenc", initData, @@ -82,17 +113,12 @@ describe("decrypt - global tests - init data", () => { }); }); - it("should ignore init data already sent through the argument", async () => { - // == mocks == - const { mockGenerateKeyRequest } = mockCompat(); + it("should ignore init data already sent through the argument", () => { + mockCompat(mocks); const mediaKeySession = new MediaKeySessionImpl(); const mockCreateSession = vi .spyOn(MediaKeysImpl.prototype, "createSession") .mockReturnValue(mediaKeySession); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { // == vars == const initData = new Uint8Array([54, 55, 75]); @@ -101,7 +127,7 @@ describe("decrypt - global tests - init data", () => { const contentDecryptor = new ContentDecryptor(videoElt, ksConfig); contentDecryptor.addEventListener( "stateChange", - (newState: IContentDecryptorState) => { + (newState: ContentDecryptorState) => { if (newState !== ContentDecryptorState.WaitingForAttachment) { rej(new Error(`Unexpected state: ${newState}`)); } @@ -127,8 +153,8 @@ describe("decrypt - global tests - init data", () => { try { expect(mockCreateSession).toHaveBeenCalledTimes(1); expect(mockCreateSession).toHaveBeenCalledWith("temporary"); - expect(mockGenerateKeyRequest).toHaveBeenCalledTimes(1); - expect(mockGenerateKeyRequest).toHaveBeenCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenCalledTimes(1); + expect(mocks.generateKeyRequest).toHaveBeenCalledWith( mediaKeySession, "cenc", initData, @@ -148,9 +174,8 @@ describe("decrypt - global tests - init data", () => { }); }); - it("should create multiple sessions for multiple sent init data when unknown", async () => { - // == mocks == - const { mockGenerateKeyRequest } = mockCompat(); + it("should create multiple sessions for multiple sent init data when unknown", () => { + mockCompat(mocks); const mediaKeySessions = [ new MediaKeySessionImpl(), new MediaKeySessionImpl(), @@ -161,10 +186,6 @@ describe("decrypt - global tests - init data", () => { .spyOn(MediaKeysImpl.prototype, "createSession") .mockImplementation(() => mediaKeySessions[createSessionCallIdx++]); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { // == vars == const initDatas = [ @@ -177,7 +198,7 @@ describe("decrypt - global tests - init data", () => { const contentDecryptor = new ContentDecryptor(videoElt, ksConfig); contentDecryptor.addEventListener( "stateChange", - (newState: IContentDecryptorState) => { + (newState: ContentDecryptorState) => { if (newState !== ContentDecryptorState.WaitingForAttachment) { rej(new Error(`Unexpected state: ${newState}`)); } @@ -215,20 +236,20 @@ describe("decrypt - global tests - init data", () => { expect(mockCreateSession).toHaveBeenNthCalledWith(1, "temporary"); expect(mockCreateSession).toHaveBeenNthCalledWith(2, "temporary"); expect(mockCreateSession).toHaveBeenNthCalledWith(3, "temporary"); - expect(mockGenerateKeyRequest).toHaveBeenCalledTimes(3); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenCalledTimes(3); + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 1, mediaKeySessions[0], "cenc", initDatas[0], ); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 2, mediaKeySessions[1], "cenc", initDatas[1], ); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 3, mediaKeySessions[2], "cenc", @@ -260,19 +281,14 @@ describe("decrypt - global tests - init data", () => { }); }); - it("should create multiple sessions for multiple sent init data types", async () => { - // == mocks == - const { mockGenerateKeyRequest } = mockCompat(); + it("should create multiple sessions for multiple sent init data types", () => { + mockCompat(mocks); const mediaKeySessions = [new MediaKeySessionImpl(), new MediaKeySessionImpl()]; let createSessionCallIdx = 0; const mockCreateSession = vi .spyOn(MediaKeysImpl.prototype, "createSession") .mockImplementation(() => mediaKeySessions[createSessionCallIdx++]); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { // == vars == const initData = new Uint8Array([54, 55, 75]); @@ -281,7 +297,7 @@ describe("decrypt - global tests - init data", () => { const contentDecryptor = new ContentDecryptor(videoElt, ksConfig); contentDecryptor.addEventListener( "stateChange", - (newState: IContentDecryptorState) => { + (newState: ContentDecryptorState) => { if (newState !== ContentDecryptorState.WaitingForAttachment) { rej(new Error(`Unexpected state: ${newState}`)); } @@ -302,14 +318,14 @@ describe("decrypt - global tests - init data", () => { expect(mockCreateSession).toHaveBeenCalledTimes(2); expect(mockCreateSession).toHaveBeenNthCalledWith(1, "temporary"); expect(mockCreateSession).toHaveBeenNthCalledWith(2, "temporary"); - expect(mockGenerateKeyRequest).toHaveBeenCalledTimes(2); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenCalledTimes(2); + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 1, mediaKeySessions[0], "cenc", initData, ); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 2, mediaKeySessions[1], "cenc2", @@ -336,18 +352,13 @@ describe("decrypt - global tests - init data", () => { }); }); - it("should create a session and generate a request when init data is received from the browser", async () => { - // == mocks == - const { mockGenerateKeyRequest, eventTriggers, mockGetInitData } = mockCompat(); + it("should create a session and generate a request when init data is received from the browser", () => { + const { eventTriggers } = mockCompat(mocks); const mediaKeySession = new MediaKeySessionImpl(); const mockCreateSession = vi .spyOn(MediaKeysImpl.prototype, "createSession") .mockReturnValue(mediaKeySession); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { // == vars == const initData = new Uint8Array([54, 55, 75]); @@ -356,7 +367,7 @@ describe("decrypt - global tests - init data", () => { const contentDecryptor = new ContentDecryptor(videoElt, ksConfig); contentDecryptor.addEventListener( "stateChange", - (newState: IContentDecryptorState) => { + (newState: ContentDecryptorState) => { if (newState !== ContentDecryptorState.WaitingForAttachment) { rej(new Error(`Unexpected state: ${newState}`)); } @@ -371,12 +382,12 @@ describe("decrypt - global tests - init data", () => { eventTriggers.triggerEncrypted(videoElt, initDataEvent); setTimeout(() => { try { - expect(mockGetInitData).toHaveBeenCalledTimes(1); - expect(mockGetInitData).toHaveBeenCalledWith(initDataEvent); + expect(mocks.getInitData).toHaveBeenCalledTimes(1); + expect(mocks.getInitData).toHaveBeenCalledWith(initDataEvent); expect(mockCreateSession).toHaveBeenCalledTimes(1); expect(mockCreateSession).toHaveBeenCalledWith("temporary"); - expect(mockGenerateKeyRequest).toHaveBeenCalledTimes(1); - expect(mockGenerateKeyRequest).toHaveBeenCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenCalledTimes(1); + expect(mocks.generateKeyRequest).toHaveBeenCalledWith( mediaKeySession, "cenc", initData, @@ -396,18 +407,13 @@ describe("decrypt - global tests - init data", () => { }); }); - it("should ignore init data already received through the browser", async () => { - // == mocks == - const { mockGenerateKeyRequest, eventTriggers, mockGetInitData } = mockCompat(); + it("should ignore init data already received through the browser", () => { + const { eventTriggers } = mockCompat(mocks); const mediaKeySession = new MediaKeySessionImpl(); const mockCreateSession = vi .spyOn(MediaKeysImpl.prototype, "createSession") .mockReturnValue(mediaKeySession); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { // == vars == const initData = new Uint8Array([54, 55, 75]); @@ -416,7 +422,7 @@ describe("decrypt - global tests - init data", () => { const contentDecryptor = new ContentDecryptor(videoElt, ksConfig); contentDecryptor.addEventListener( "stateChange", - (newState: IContentDecryptorState) => { + (newState: ContentDecryptorState) => { if (newState !== ContentDecryptorState.WaitingForAttachment) { rej(new Error(`Unexpected state: ${newState}`)); } @@ -435,14 +441,14 @@ describe("decrypt - global tests - init data", () => { }, 5); setTimeout(() => { try { - expect(mockGetInitData).toHaveBeenCalledTimes(3); - expect(mockGetInitData).toHaveBeenNthCalledWith(1, initDataEvent); - expect(mockGetInitData).toHaveBeenNthCalledWith(2, initDataEvent); - expect(mockGetInitData).toHaveBeenNthCalledWith(3, initDataEvent); + expect(mocks.getInitData).toHaveBeenCalledTimes(3); + expect(mocks.getInitData).toHaveBeenNthCalledWith(1, initDataEvent); + expect(mocks.getInitData).toHaveBeenNthCalledWith(2, initDataEvent); + expect(mocks.getInitData).toHaveBeenNthCalledWith(3, initDataEvent); expect(mockCreateSession).toHaveBeenCalledTimes(1); expect(mockCreateSession).toHaveBeenCalledWith("temporary"); - expect(mockGenerateKeyRequest).toHaveBeenCalledTimes(1); - expect(mockGenerateKeyRequest).toHaveBeenCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenCalledTimes(1); + expect(mocks.generateKeyRequest).toHaveBeenCalledWith( mediaKeySession, "cenc", initData, @@ -462,9 +468,8 @@ describe("decrypt - global tests - init data", () => { }); }); - it("should create multiple sessions for multiple received init data when unknown", async () => { - // == mocks == - const { mockGenerateKeyRequest, eventTriggers, mockGetInitData } = mockCompat(); + it("should create multiple sessions for multiple received init data when unknown", () => { + const { eventTriggers } = mockCompat(mocks); const mediaKeySessions = [ new MediaKeySessionImpl(), new MediaKeySessionImpl(), @@ -475,10 +480,6 @@ describe("decrypt - global tests - init data", () => { .spyOn(MediaKeysImpl.prototype, "createSession") .mockImplementation(() => mediaKeySessions[createSessionCallIdx++]); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { // == vars == const initDatas = [ @@ -498,7 +499,7 @@ describe("decrypt - global tests - init data", () => { const contentDecryptor = new ContentDecryptor(videoElt, ksConfig); contentDecryptor.addEventListener( "stateChange", - (newState: IContentDecryptorState) => { + (newState: ContentDecryptorState) => { if (newState !== ContentDecryptorState.WaitingForAttachment) { rej(new Error(`Unexpected state: ${newState}`)); } @@ -517,30 +518,30 @@ describe("decrypt - global tests - init data", () => { }, 5); setTimeout(() => { try { - expect(mockGetInitData).toHaveBeenCalledTimes(5); - expect(mockGetInitData).toHaveBeenNthCalledWith(1, initDataEvents[0]); - expect(mockGetInitData).toHaveBeenNthCalledWith(2, initDataEvents[1]); - expect(mockGetInitData).toHaveBeenNthCalledWith(3, initDataEvents[0]); - expect(mockGetInitData).toHaveBeenNthCalledWith(4, initDataEvents[2]); - expect(mockGetInitData).toHaveBeenNthCalledWith(5, initDataEvents[1]); + expect(mocks.getInitData).toHaveBeenCalledTimes(5); + expect(mocks.getInitData).toHaveBeenNthCalledWith(1, initDataEvents[0]); + expect(mocks.getInitData).toHaveBeenNthCalledWith(2, initDataEvents[1]); + expect(mocks.getInitData).toHaveBeenNthCalledWith(3, initDataEvents[0]); + expect(mocks.getInitData).toHaveBeenNthCalledWith(4, initDataEvents[2]); + expect(mocks.getInitData).toHaveBeenNthCalledWith(5, initDataEvents[1]); expect(mockCreateSession).toHaveBeenCalledTimes(3); expect(mockCreateSession).toHaveBeenNthCalledWith(1, "temporary"); expect(mockCreateSession).toHaveBeenNthCalledWith(2, "temporary"); expect(mockCreateSession).toHaveBeenNthCalledWith(3, "temporary"); - expect(mockGenerateKeyRequest).toHaveBeenCalledTimes(3); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenCalledTimes(3); + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 1, mediaKeySessions[0], "cenc", initDatas[0], ); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 2, mediaKeySessions[1], "cenc", initDatas[1], ); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 3, mediaKeySessions[2], "cenc", @@ -572,19 +573,14 @@ describe("decrypt - global tests - init data", () => { }); }); - it("should create multiple sessions for multiple received init data types", async () => { - // == mocks == - const { mockGenerateKeyRequest, eventTriggers, mockGetInitData } = mockCompat(); + it("should create multiple sessions for multiple received init data types", () => { + const { eventTriggers } = mockCompat(mocks); const mediaKeySessions = [new MediaKeySessionImpl(), new MediaKeySessionImpl()]; let createSessionCallIdx = 0; const mockCreateSession = vi .spyOn(MediaKeysImpl.prototype, "createSession") .mockImplementation(() => mediaKeySessions[createSessionCallIdx++]); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { // == vars == const initData = new Uint8Array([54, 55, 75]); @@ -598,7 +594,7 @@ describe("decrypt - global tests - init data", () => { const contentDecryptor = new ContentDecryptor(videoElt, ksConfig); contentDecryptor.addEventListener( "stateChange", - (newState: IContentDecryptorState) => { + (newState: ContentDecryptorState) => { if (newState !== ContentDecryptorState.WaitingForAttachment) { rej(new Error(`Unexpected state: ${newState}`)); } @@ -610,20 +606,20 @@ describe("decrypt - global tests - init data", () => { eventTriggers.triggerEncrypted(videoElt, initDataEvents[1]); setTimeout(() => { try { - expect(mockGetInitData).toHaveBeenCalledTimes(2); - expect(mockGetInitData).toHaveBeenNthCalledWith(1, initDataEvents[0]); - expect(mockGetInitData).toHaveBeenNthCalledWith(2, initDataEvents[1]); + expect(mocks.getInitData).toHaveBeenCalledTimes(2); + expect(mocks.getInitData).toHaveBeenNthCalledWith(1, initDataEvents[0]); + expect(mocks.getInitData).toHaveBeenNthCalledWith(2, initDataEvents[1]); expect(mockCreateSession).toHaveBeenCalledTimes(2); expect(mockCreateSession).toHaveBeenNthCalledWith(1, "temporary"); expect(mockCreateSession).toHaveBeenNthCalledWith(2, "temporary"); - expect(mockGenerateKeyRequest).toHaveBeenCalledTimes(2); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenCalledTimes(2); + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 1, mediaKeySessions[0], "cenc", initData, ); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 2, mediaKeySessions[1], "cenc2", @@ -650,9 +646,8 @@ describe("decrypt - global tests - init data", () => { }); }); - it("should consider sent event through arguments and received events through the browser the same way", async () => { - // == mocks == - const { mockGenerateKeyRequest, eventTriggers, mockGetInitData } = mockCompat(); + it("should consider sent event through arguments and received events through the browser the same way", () => { + const { eventTriggers } = mockCompat(mocks); const mediaKeySessions = [ new MediaKeySessionImpl(), new MediaKeySessionImpl(), @@ -663,10 +658,6 @@ describe("decrypt - global tests - init data", () => { .spyOn(MediaKeysImpl.prototype, "createSession") .mockImplementation(() => mediaKeySessions[createSessionCallIdx++]); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { // == vars == const initDatas = [ @@ -686,7 +677,7 @@ describe("decrypt - global tests - init data", () => { const contentDecryptor = new ContentDecryptor(videoElt, ksConfig); contentDecryptor.addEventListener( "stateChange", - (newState: IContentDecryptorState) => { + (newState: ContentDecryptorState) => { if (newState !== ContentDecryptorState.WaitingForAttachment) { rej(new Error(`Unexpected state: ${newState}`)); } @@ -704,29 +695,29 @@ describe("decrypt - global tests - init data", () => { }); setTimeout(() => { try { - expect(mockGetInitData).toHaveBeenCalledTimes(4); - expect(mockGetInitData).toHaveBeenNthCalledWith(1, initDataEvents[0]); - expect(mockGetInitData).toHaveBeenNthCalledWith(2, initDataEvents[1]); - expect(mockGetInitData).toHaveBeenNthCalledWith(3, initDataEvents[0]); - expect(mockGetInitData).toHaveBeenNthCalledWith(4, initDataEvents[2]); + expect(mocks.getInitData).toHaveBeenCalledTimes(4); + expect(mocks.getInitData).toHaveBeenNthCalledWith(1, initDataEvents[0]); + expect(mocks.getInitData).toHaveBeenNthCalledWith(2, initDataEvents[1]); + expect(mocks.getInitData).toHaveBeenNthCalledWith(3, initDataEvents[0]); + expect(mocks.getInitData).toHaveBeenNthCalledWith(4, initDataEvents[2]); expect(mockCreateSession).toHaveBeenCalledTimes(3); expect(mockCreateSession).toHaveBeenNthCalledWith(1, "temporary"); expect(mockCreateSession).toHaveBeenNthCalledWith(2, "temporary"); expect(mockCreateSession).toHaveBeenNthCalledWith(3, "temporary"); - expect(mockGenerateKeyRequest).toHaveBeenCalledTimes(3); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenCalledTimes(3); + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 1, mediaKeySessions[0], "cenc", initDatas[0], ); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 2, mediaKeySessions[1], "cenc", initDatas[1], ); - expect(mockGenerateKeyRequest).toHaveBeenNthCalledWith( + expect(mocks.generateKeyRequest).toHaveBeenNthCalledWith( 3, mediaKeySessions[2], "cenc", diff --git a/src/main_thread/decrypt/__tests__/__global__/media_key_system_access.test.ts b/src/main_thread/decrypt/__tests__/__global__/media_key_system_access.test.ts index 6821016fc4..71a83c8b65 100644 --- a/src/main_thread/decrypt/__tests__/__global__/media_key_system_access.test.ts +++ b/src/main_thread/decrypt/__tests__/__global__/media_key_system_access.test.ts @@ -1,7 +1,7 @@ import { describe, beforeEach, afterEach, it, expect, vi } from "vitest"; import type { ICustomMediaKeySystemAccess } from "../../../../compat/eme"; import type { IKeySystemOption } from "../../../../public_types"; -import type IContentDecryptor from "../../content_decryptor"; +import ContentDecryptor from "../../content_decryptor"; import { defaultKSConfig, defaultPRRecommendationKSConfig, @@ -10,6 +10,40 @@ import { testContentDecryptorError, } from "./utils"; +const mocks = vi.hoisted(() => { + return { + // Used to implement every functions that should never be called. + neverCalled: vi.fn(), + shouldRenewMediaKeySystemAccess: vi.fn(() => false), + canReuseMediaKeys: vi.fn(() => true), + onEncrypted: vi.fn(), + requestMediaKeySystemAccess: vi.fn(), + setMediaKeys: vi.fn(), + getInitData: vi.fn(), + generateKeyRequest: vi.fn(), + }; +}); +vi.mock("../../../../compat/should_renew_media_key_system_access", () => ({ + default: mocks.shouldRenewMediaKeySystemAccess, +})); +vi.mock("../../../../compat/can_reuse_media_keys", () => ({ + default: mocks.canReuseMediaKeys, +})); +vi.mock("../../../../compat/eme", () => ({ + default: { + onEncrypted: mocks.onEncrypted, + requestMediaKeySystemAccess: mocks.requestMediaKeySystemAccess, + setMediaKeys: mocks.setMediaKeys, + }, + getInitData: mocks.getInitData, + generateKeyRequest: mocks.generateKeyRequest, + closeSession: vi.fn(), + loadSession: vi.fn(), +})); +vi.mock("../../set_server_certificate", () => ({ + default: mocks.neverCalled, +})); + function requestMediaKeySystemAccessNoMediaKeys( keySystem: string, config: MediaKeySystemConfiguration[], @@ -60,8 +94,6 @@ async function checkIncompatibleKeySystemsErrorMessage( keySystemsConfigs: IKeySystemOption[], ): Promise { const mediaElement = document.createElement("video"); - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; const error = await testContentDecryptorError( ContentDecryptor, @@ -76,44 +108,41 @@ async function checkIncompatibleKeySystemsErrorMessage( } describe("decrypt - global tests - media key system access", () => { - // Used to implement every functions that should never be called. - const neverCalledFn = vi.fn(); - beforeEach(() => { vi.resetModules(); vi.restoreAllMocks(); - vi.doMock("../../set_server_certificate", () => ({ - default: neverCalledFn, - })); }); afterEach(() => { - expect(neverCalledFn).not.toHaveBeenCalled(); + expect(mocks.neverCalled).not.toHaveBeenCalled(); + mocks.shouldRenewMediaKeySystemAccess.mockReset(); + mocks.canReuseMediaKeys.mockReset(); + mocks.onEncrypted.mockReset(); + mocks.requestMediaKeySystemAccess.mockReset(); + mocks.setMediaKeys.mockReset(); + mocks.getInitData.mockReset(); + mocks.generateKeyRequest.mockReset(); }); it("should throw if an empty keySystemsConfigs is given", async () => { - mockCompat(); + mockCompat(mocks); await checkIncompatibleKeySystemsErrorMessage([]); }); it("should throw if given a single incompatible keySystemsConfigs", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); - const getLicenseFn = neverCalledFn; + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); + const getLicenseFn = mocks.neverCalled; await checkIncompatibleKeySystemsErrorMessage([ { type: "foo", getLicense: getLicenseFn }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "foo", removeCapabiltiesFromConfig(defaultKSConfig), @@ -121,45 +150,41 @@ describe("decrypt - global tests - media key system access", () => { }); it("should throw if given multiple incompatible keySystemsConfigs", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); const config = [ - { type: "foo", getLicense: neverCalledFn }, - { type: "bar", getLicense: neverCalledFn }, - { type: "baz", getLicense: neverCalledFn }, + { type: "foo", getLicense: mocks.neverCalled }, + { type: "bar", getLicense: mocks.neverCalled }, + { type: "baz", getLicense: mocks.neverCalled }, ]; await checkIncompatibleKeySystemsErrorMessage(config); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(6); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(6); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "foo", removeCapabiltiesFromConfig(defaultKSConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 3, "bar", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 4, "bar", removeCapabiltiesFromConfig(defaultKSConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 5, "baz", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 6, "baz", removeCapabiltiesFromConfig(defaultKSConfig), @@ -167,22 +192,18 @@ describe("decrypt - global tests - media key system access", () => { }); it("should throw if given a single incompatible keySystemsConfigs", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ - { type: "foo", getLicense: neverCalledFn }, + { type: "foo", getLicense: mocks.neverCalled }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "foo", removeCapabiltiesFromConfig(defaultKSConfig), @@ -190,26 +211,22 @@ describe("decrypt - global tests - media key system access", () => { }); it('should set persistentState value if persistentState is set to "required"', async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ - { type: "foo", getLicense: neverCalledFn, persistentState: "required" }, + { type: "foo", getLicense: mocks.neverCalled, persistentState: "required" }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); const expectedConfig: MediaKeySystemConfiguration[] = defaultKSConfig.map((conf) => { return { ...conf, persistentState: "required" }; }); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", expectedConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "foo", removeCapabiltiesFromConfig(expectedConfig), @@ -217,30 +234,26 @@ describe("decrypt - global tests - media key system access", () => { }); it('should set persistentState value if persistentState is set to "not-allowed"', async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ { type: "foo", - getLicense: neverCalledFn, + getLicense: mocks.neverCalled, persistentState: "not-allowed", }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); const expectedConfig: MediaKeySystemConfiguration[] = defaultKSConfig.map((conf) => { return { ...conf, persistentState: "not-allowed" }; }); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", expectedConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "foo", removeCapabiltiesFromConfig(expectedConfig), @@ -248,26 +261,22 @@ describe("decrypt - global tests - media key system access", () => { }); it('should set persistentState value if persistentState is set to "optional"', async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ - { type: "foo", getLicense: neverCalledFn, persistentState: "optional" }, + { type: "foo", getLicense: mocks.neverCalled, persistentState: "optional" }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); const expectedConfig: MediaKeySystemConfiguration[] = defaultKSConfig.map((conf) => { return { ...conf, persistentState: "optional" }; }); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", expectedConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "foo", removeCapabiltiesFromConfig(expectedConfig), @@ -275,30 +284,26 @@ describe("decrypt - global tests - media key system access", () => { }); it('should set distinctiveIdentifier value if distinctiveIdentifier is set to "required"', async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ { type: "foo", - getLicense: neverCalledFn, + getLicense: mocks.neverCalled, distinctiveIdentifier: "required", }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); const expectedConfig: MediaKeySystemConfiguration[] = defaultKSConfig.map((conf) => { return { ...conf, distinctiveIdentifier: "required" }; }); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", expectedConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "foo", removeCapabiltiesFromConfig(expectedConfig), @@ -306,30 +311,26 @@ describe("decrypt - global tests - media key system access", () => { }); it('should set distinctiveIdentifier value if distinctiveIdentifier is set to "not-allowed"', async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ { type: "foo", - getLicense: neverCalledFn, + getLicense: mocks.neverCalled, distinctiveIdentifier: "not-allowed", }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); const expectedConfig: MediaKeySystemConfiguration[] = defaultKSConfig.map((conf) => { return { ...conf, distinctiveIdentifier: "not-allowed" }; }); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", expectedConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "foo", removeCapabiltiesFromConfig(expectedConfig), @@ -337,30 +338,26 @@ describe("decrypt - global tests - media key system access", () => { }); it('should set distinctiveIdentifier value if distinctiveIdentifier is set to "optional"', async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ { type: "foo", - getLicense: neverCalledFn, + getLicense: mocks.neverCalled, distinctiveIdentifier: "optional", }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); const expectedConfig: MediaKeySystemConfiguration[] = defaultKSConfig.map((conf) => { return { ...conf, distinctiveIdentifier: "optional" }; }); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", expectedConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "foo", removeCapabiltiesFromConfig(expectedConfig), @@ -368,12 +365,8 @@ describe("decrypt - global tests - media key system access", () => { }); it("should want persistent sessions if persistentLicenseConfig is set", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); const persistentLicenseConfig = { save() { throw new Error("Should not save."); @@ -383,9 +376,9 @@ describe("decrypt - global tests - media key system access", () => { }, }; await checkIncompatibleKeySystemsErrorMessage([ - { type: "foo", getLicense: neverCalledFn, persistentLicenseConfig }, + { type: "foo", getLicense: mocks.neverCalled, persistentLicenseConfig }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); const expectedConfig: MediaKeySystemConfiguration[] = defaultKSConfig.map((conf) => { return { @@ -394,12 +387,12 @@ describe("decrypt - global tests - media key system access", () => { sessionTypes: ["temporary", "persistent-license"], }; }); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", expectedConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "foo", removeCapabiltiesFromConfig(expectedConfig), @@ -407,22 +400,18 @@ describe("decrypt - global tests - media key system access", () => { }); it("should do nothing if persistentLicenseConfig is set to null", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ - { type: "foo", getLicense: neverCalledFn }, + { type: "foo", getLicense: mocks.neverCalled }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "foo", removeCapabiltiesFromConfig(defaultKSConfig), @@ -430,25 +419,21 @@ describe("decrypt - global tests - media key system access", () => { }); it("should do nothing if persistentLicenseConfig is set to undefined", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ { type: "foo", - getLicense: neverCalledFn, + getLicense: mocks.neverCalled, }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "foo", removeCapabiltiesFromConfig(defaultKSConfig), @@ -456,32 +441,28 @@ describe("decrypt - global tests - media key system access", () => { }); it("should translate a `clearkey` keySystem", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ - { type: "clearkey", getLicense: neverCalledFn }, + { type: "clearkey", getLicense: mocks.neverCalled }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(4); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(4); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "webkit-org.w3.clearkey", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "webkit-org.w3.clearkey", removeCapabiltiesFromConfig(defaultKSConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 3, "org.w3.clearkey", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 4, "org.w3.clearkey", removeCapabiltiesFromConfig(defaultKSConfig), @@ -489,22 +470,18 @@ describe("decrypt - global tests - media key system access", () => { }); it("should translate a `widevine` keySystem", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ - { type: "widevine", getLicense: neverCalledFn }, + { type: "widevine", getLicense: mocks.neverCalled }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "com.widevine.alpha", defaultWidevineConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "com.widevine.alpha", removeCapabiltiesFromConfig(defaultWidevineConfig), @@ -512,52 +489,48 @@ describe("decrypt - global tests - media key system access", () => { }); it("should translate a `playready` keySystem", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ - { type: "playready", getLicense: neverCalledFn }, + { type: "playready", getLicense: mocks.neverCalled }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(8); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(8); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "com.microsoft.playready.recommendation", defaultPRRecommendationKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "com.microsoft.playready.recommendation", removeCapabiltiesFromConfig(defaultPRRecommendationKSConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 3, "com.microsoft.playready", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 4, "com.microsoft.playready", removeCapabiltiesFromConfig(defaultKSConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 5, "com.chromecast.playready", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 6, "com.chromecast.playready", removeCapabiltiesFromConfig(defaultKSConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 7, "com.youtube.playready", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 8, "com.youtube.playready", removeCapabiltiesFromConfig(defaultKSConfig), @@ -565,84 +538,76 @@ describe("decrypt - global tests - media key system access", () => { }); it("should translate a `fairplay` keySystem", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ - { type: "fairplay", getLicense: neverCalledFn }, + { type: "fairplay", getLicense: mocks.neverCalled }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledWith( "com.apple.fps.1_0", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledWith( "com.apple.fps.1_0", removeCapabiltiesFromConfig(defaultKSConfig), ); }); it("should translate a multiple keySystems at the same time", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ - { type: "playready", getLicense: neverCalledFn }, - { type: "clearkey", getLicense: neverCalledFn }, + { type: "playready", getLicense: mocks.neverCalled }, + { type: "clearkey", getLicense: mocks.neverCalled }, ]); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(12); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(12); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "com.microsoft.playready.recommendation", defaultPRRecommendationKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "com.microsoft.playready.recommendation", removeCapabiltiesFromConfig(defaultPRRecommendationKSConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 3, "com.microsoft.playready", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 4, "com.microsoft.playready", removeCapabiltiesFromConfig(defaultKSConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 5, "com.chromecast.playready", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 6, "com.chromecast.playready", removeCapabiltiesFromConfig(defaultKSConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 9, "webkit-org.w3.clearkey", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 10, "webkit-org.w3.clearkey", removeCapabiltiesFromConfig(defaultKSConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 11, "org.w3.clearkey", defaultKSConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 12, "org.w3.clearkey", removeCapabiltiesFromConfig(defaultKSConfig), @@ -650,12 +615,8 @@ describe("decrypt - global tests - media key system access", () => { }); it("should translate a multiple keySystems at the same time with different configs", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ { type: "playready", @@ -667,12 +628,12 @@ describe("decrypt - global tests - media key system access", () => { return []; }, }, - getLicense: neverCalledFn, + getLicense: mocks.neverCalled, }, { type: "clearkey", distinctiveIdentifier: "required", - getLicense: neverCalledFn, + getLicense: mocks.neverCalled, }, ]); const expectedPRRecommendationPersistentConfig: MediaKeySystemConfiguration[] = @@ -697,63 +658,63 @@ describe("decrypt - global tests - media key system access", () => { return { ...conf, distinctiveIdentifier: "required" }; }, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(12); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(12); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "com.microsoft.playready.recommendation", expectedPRRecommendationPersistentConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "com.microsoft.playready.recommendation", removeCapabiltiesFromConfig(expectedPRRecommendationPersistentConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 3, "com.microsoft.playready", expectedPersistentConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 4, "com.microsoft.playready", removeCapabiltiesFromConfig(expectedPersistentConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 5, "com.chromecast.playready", expectedPersistentConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 6, "com.chromecast.playready", removeCapabiltiesFromConfig(expectedPersistentConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 7, "com.youtube.playready", expectedPersistentConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 8, "com.youtube.playready", removeCapabiltiesFromConfig(expectedPersistentConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 9, "webkit-org.w3.clearkey", expectedIdentifierConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 10, "webkit-org.w3.clearkey", removeCapabiltiesFromConfig(expectedIdentifierConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 11, "org.w3.clearkey", expectedIdentifierConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 12, "org.w3.clearkey", removeCapabiltiesFromConfig(expectedIdentifierConfig), @@ -761,12 +722,8 @@ describe("decrypt - global tests - media key system access", () => { }); it("should set widevine robustnesses for a `com.widevine.alpha` keySystem", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ { type: "com.widevine.alpha", @@ -778,7 +735,7 @@ describe("decrypt - global tests - media key system access", () => { return []; }, }, - getLicense: neverCalledFn, + getLicense: mocks.neverCalled, }, ]); const expectedPersistentConfig: MediaKeySystemConfiguration[] = @@ -789,13 +746,13 @@ describe("decrypt - global tests - media key system access", () => { sessionTypes: ["temporary", "persistent-license"], }; }); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "com.widevine.alpha", expectedPersistentConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "com.widevine.alpha", removeCapabiltiesFromConfig(expectedPersistentConfig), @@ -803,12 +760,8 @@ describe("decrypt - global tests - media key system access", () => { }); it("should set playready robustnesses for a `playready` keySystem", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ { type: "playready", @@ -820,12 +773,12 @@ describe("decrypt - global tests - media key system access", () => { return []; }, }, - getLicense: neverCalledFn, + getLicense: mocks.neverCalled, }, { type: "clearkey", distinctiveIdentifier: "required", - getLicense: neverCalledFn, + getLicense: mocks.neverCalled, }, ]); const expectedPersistentConfig: MediaKeySystemConfiguration[] = defaultKSConfig.map( @@ -850,63 +803,63 @@ describe("decrypt - global tests - media key system access", () => { return { ...conf, distinctiveIdentifier: "required" }; }, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(12); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(12); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "com.microsoft.playready.recommendation", expectedRecoPersistentConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "com.microsoft.playready.recommendation", removeCapabiltiesFromConfig(expectedRecoPersistentConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 3, "com.microsoft.playready", expectedPersistentConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 4, "com.microsoft.playready", removeCapabiltiesFromConfig(expectedPersistentConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 5, "com.chromecast.playready", expectedPersistentConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 6, "com.chromecast.playready", removeCapabiltiesFromConfig(expectedPersistentConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 7, "com.youtube.playready", expectedPersistentConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 8, "com.youtube.playready", removeCapabiltiesFromConfig(expectedPersistentConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 9, "webkit-org.w3.clearkey", expectedIdentifierConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 10, "webkit-org.w3.clearkey", removeCapabiltiesFromConfig(expectedIdentifierConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 11, "org.w3.clearkey", expectedIdentifierConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 12, "org.w3.clearkey", removeCapabiltiesFromConfig(expectedIdentifierConfig), @@ -914,12 +867,8 @@ describe("decrypt - global tests - media key system access", () => { }); it("should set playready robustnesses for a `com.microsoft.playready.recommendation` keySystem", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation(() => Promise.reject("nope")); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation(() => Promise.reject("nope")); await checkIncompatibleKeySystemsErrorMessage([ { type: "com.microsoft.playready.recommendation", @@ -931,7 +880,7 @@ describe("decrypt - global tests - media key system access", () => { return []; }, }, - getLicense: neverCalledFn, + getLicense: mocks.neverCalled, }, ]); const expectedRecoPersistentConfig: MediaKeySystemConfiguration[] = @@ -942,13 +891,13 @@ describe("decrypt - global tests - media key system access", () => { sessionTypes: ["temporary", "persistent-license"], }; }); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(2); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(2); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "com.microsoft.playready.recommendation", expectedRecoPersistentConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "com.microsoft.playready.recommendation", removeCapabiltiesFromConfig(expectedRecoPersistentConfig), @@ -956,18 +905,14 @@ describe("decrypt - global tests - media key system access", () => { }); it("should successfully create a MediaKeySystemAccess if given the right configuration", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation((keyType: string, conf: MediaKeySystemConfiguration[]) => { + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation( + (keyType: string, conf: MediaKeySystemConfiguration[]) => { return requestMediaKeySystemAccessNoMediaKeys(keyType, conf); - }); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; + }, + ); return new Promise((res, rej) => { - const config = [{ type: "com.widevine.alpha", getLicense: neverCalledFn }]; + const config = [{ type: "com.widevine.alpha", getLicense: mocks.neverCalled }]; const mediaElement = document.createElement("video"); const contentDecryptor = new ContentDecryptor(mediaElement, config); @@ -975,8 +920,8 @@ describe("decrypt - global tests - media key system access", () => { rej(error); }); setTimeout(() => { - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(1); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(1); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledWith( "com.widevine.alpha", defaultWidevineConfig, ); @@ -986,23 +931,19 @@ describe("decrypt - global tests - media key system access", () => { }); it("should successfully create a MediaKeySystemAccess if given multiple configurations where one works", async () => { - const mockRequestMediaKeySystemAccess = vi - .fn() - .mockImplementation((keyType: string, conf: MediaKeySystemConfiguration[]) => { + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation( + (keyType: string, conf: MediaKeySystemConfiguration[]) => { if (keyType === "some-other-working-key-system") { return requestMediaKeySystemAccessNoMediaKeys(keyType, conf); } return Promise.reject("nope"); - }); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; + }, + ); return new Promise((res, rej) => { const config = [ - { type: "com.widevine.alpha", getLicense: neverCalledFn }, - { type: "some-other-working-key-system", getLicense: neverCalledFn }, + { type: "com.widevine.alpha", getLicense: mocks.neverCalled }, + { type: "some-other-working-key-system", getLicense: mocks.neverCalled }, ]; const mediaElement = document.createElement("video"); @@ -1011,18 +952,18 @@ describe("decrypt - global tests - media key system access", () => { rej(error); }); setTimeout(() => { - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(3); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(3); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "com.widevine.alpha", defaultWidevineConfig, ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 2, "com.widevine.alpha", removeCapabiltiesFromConfig(defaultWidevineConfig), ); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 3, "some-other-working-key-system", defaultKSConfig, @@ -1033,27 +974,23 @@ describe("decrypt - global tests - media key system access", () => { }); it("should not continue to check if the ContentDecryptor is disposed from", async () => { - let contentDecryptor: IContentDecryptor | null = null; + mockCompat(mocks); + let contentDecryptor: ContentDecryptor | null = null; let rmksHasBeenCalled = false; - const mockRequestMediaKeySystemAccess = vi.fn().mockImplementation(() => { + mocks.requestMediaKeySystemAccess.mockImplementation(() => { return Promise.resolve().then(() => { rmksHasBeenCalled = true; contentDecryptor?.dispose(); return Promise.reject("nope"); }); }); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { const mediaElement = document.createElement("video"); const config = [ - { type: "foo", getLicense: neverCalledFn }, - { type: "bar", getLicense: neverCalledFn }, - { type: "baz", getLicense: neverCalledFn }, + { type: "foo", getLicense: mocks.neverCalled }, + { type: "bar", getLicense: mocks.neverCalled }, + { type: "baz", getLicense: mocks.neverCalled }, ]; contentDecryptor = new ContentDecryptor(mediaElement, config); contentDecryptor.addEventListener("error", (error) => { @@ -1061,8 +998,8 @@ describe("decrypt - global tests - media key system access", () => { }); setTimeout(() => { expect(rmksHasBeenCalled).toEqual(true); - expect(mockRequestMediaKeySystemAccess).toHaveBeenCalledTimes(1); - expect(mockRequestMediaKeySystemAccess).toHaveBeenNthCalledWith( + expect(mocks.requestMediaKeySystemAccess).toHaveBeenCalledTimes(1); + expect(mocks.requestMediaKeySystemAccess).toHaveBeenNthCalledWith( 1, "foo", defaultKSConfig, @@ -1073,20 +1010,16 @@ describe("decrypt - global tests - media key system access", () => { }); it("should trigger error even if requestMediaKeySystemAccess throws", async () => { + mockCompat(mocks); let rmksHasBeenCalled = false; - const mockRequestMediaKeySystemAccess = vi.fn().mockImplementation(() => { + mocks.requestMediaKeySystemAccess.mockImplementation(() => { rmksHasBeenCalled = true; throw new Error("nope"); }); - mockCompat({ - requestMediaKeySystemAccess: mockRequestMediaKeySystemAccess, - }); - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { const mediaElement = document.createElement("video"); - const config = [{ type: "foo", getLicense: neverCalledFn }]; + const config = [{ type: "foo", getLicense: mocks.neverCalled }]; const contentDecryptor = new ContentDecryptor(mediaElement, config); contentDecryptor.addEventListener("error", () => { expect(rmksHasBeenCalled).toEqual(true); diff --git a/src/main_thread/decrypt/__tests__/__global__/media_keys.test.ts b/src/main_thread/decrypt/__tests__/__global__/media_keys.test.ts index e2c1f838e3..fede712a96 100644 --- a/src/main_thread/decrypt/__tests__/__global__/media_keys.test.ts +++ b/src/main_thread/decrypt/__tests__/__global__/media_keys.test.ts @@ -1,7 +1,7 @@ import { describe, beforeEach, afterEach, it, expect, vi } from "vitest"; import type { IKeySystemOption } from "../../../../public_types"; -import type IContentDecryptor from "../../content_decryptor"; -import type { ContentDecryptorState as IContentDecryptorState } from "../../types"; +import ContentDecryptor from "../../content_decryptor"; +import { ContentDecryptorState } from "../../types"; import { MediaKeysImpl, MediaKeySystemAccessImpl, @@ -9,36 +9,70 @@ import { testContentDecryptorError, } from "./utils"; -describe("decrypt - global tests - media key system access", () => { - /** Used to implement every functions that should never be called. */ - const neverCalledFn = vi.fn(); +const mocks = vi.hoisted(() => { + return { + // Used to implement every functions that should never be called. + neverCalled: vi.fn(), + shouldRenewMediaKeySystemAccess: vi.fn(() => false), + canReuseMediaKeys: vi.fn(() => true), + onEncrypted: vi.fn(), + requestMediaKeySystemAccess: vi.fn(), + setMediaKeys: vi.fn(), + getInitData: vi.fn(), + generateKeyRequest: vi.fn(), + }; +}); +vi.mock("../../../../compat/should_renew_media_key_system_access", () => ({ + default: mocks.shouldRenewMediaKeySystemAccess, +})); +vi.mock("../../../../compat/can_reuse_media_keys", () => ({ + default: mocks.canReuseMediaKeys, +})); +vi.mock("../../../../compat/eme", () => ({ + default: { + onEncrypted: mocks.onEncrypted, + requestMediaKeySystemAccess: mocks.requestMediaKeySystemAccess, + setMediaKeys: mocks.setMediaKeys, + }, + getInitData: mocks.getInitData, + generateKeyRequest: mocks.generateKeyRequest, + closeSession: vi.fn(), + loadSession: vi.fn(), +})); +vi.mock("../../set_server_certificate", () => ({ + default: mocks.neverCalled, +})); +describe("decrypt - global tests - media key system access", () => { /** Default video element used in our tests. */ const videoElt = document.createElement("video"); /** Default keySystems configuration used in our tests. */ const ksConfig: IKeySystemOption[] = [ - { type: "com.widevine.alpha", getLicense: neverCalledFn }, + { type: "com.widevine.alpha", getLicense: mocks.neverCalled }, ]; beforeEach(() => { vi.resetModules(); vi.restoreAllMocks(); - vi.doMock("../../set_server_certificate", () => ({ - default: neverCalledFn, - })); }); afterEach(() => { - expect(neverCalledFn).not.toHaveBeenCalled(); + expect(mocks.neverCalled).not.toHaveBeenCalled(); + mocks.shouldRenewMediaKeySystemAccess.mockReset(); + mocks.canReuseMediaKeys.mockReset(); + mocks.onEncrypted.mockReset(); + mocks.requestMediaKeySystemAccess.mockReset(); + mocks.setMediaKeys.mockReset(); + mocks.getInitData.mockReset(); + mocks.generateKeyRequest.mockReset(); }); it("should throw if createMediaKeys throws", async () => { - // == mocks == function requestMediaKeySystemAccessBadMediaKeys( keySystem: string, conf: MediaKeySystemConfiguration[], - ) { + ): Promise { return Promise.resolve({ keySystem, getConfiguration() { @@ -49,13 +83,12 @@ describe("decrypt - global tests - media key system access", () => { }, }); } - mockCompat({ - requestMediaKeySystemAccess: vi.fn(requestMediaKeySystemAccessBadMediaKeys), - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation( + requestMediaKeySystemAccessBadMediaKeys, + ); // == test == - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; const error = await testContentDecryptorError(ContentDecryptor, videoElt, ksConfig); expect(error).toBeInstanceOf(Error); expect(error.message).toEqual("CREATE_MEDIA_KEYS_ERROR: No non no"); @@ -66,7 +99,6 @@ describe("decrypt - global tests - media key system access", () => { }); it("should throw if createMediaKeys rejects", async () => { - // == mocks == function requestMediaKeySystemAccessRejMediaKeys( keySystem: string, conf: MediaKeySystemConfiguration[], @@ -77,13 +109,12 @@ describe("decrypt - global tests - media key system access", () => { createMediaKeys: () => Promise.reject(new Error("No non no")), }); } - mockCompat({ - requestMediaKeySystemAccess: vi.fn(requestMediaKeySystemAccessRejMediaKeys), - }); + mockCompat(mocks); + mocks.requestMediaKeySystemAccess.mockImplementation( + requestMediaKeySystemAccessRejMediaKeys, + ); // == test == - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; const error = await testContentDecryptorError(ContentDecryptor, videoElt, ksConfig); expect(error).toBeInstanceOf(Error); expect(error.message).toEqual("CREATE_MEDIA_KEYS_ERROR: No non no"); @@ -94,15 +125,11 @@ describe("decrypt - global tests - media key system access", () => { }); it("should go into the WaitingForAttachment state if createMediaKeys resolves", async () => { - mockCompat(); + mockCompat(mocks); const mockCreateMediaKeys = vi.spyOn( MediaKeySystemAccessImpl.prototype, "createMediaKeys", ); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { const contentDecryptor = new ContentDecryptor(videoElt, ksConfig); let receivedStateChange = 0; @@ -131,15 +158,11 @@ describe("decrypt - global tests - media key system access", () => { }); it("should not call createMediaKeys again if previous one is compatible", async () => { - mockCompat(); + mockCompat(mocks); const mockCreateMediaKeys = vi.spyOn( MediaKeySystemAccessImpl.prototype, "createMediaKeys", ); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { const contentDecryptor1 = new ContentDecryptor(videoElt, ksConfig); let receivedStateChange1 = 0; @@ -196,17 +219,12 @@ describe("decrypt - global tests - media key system access", () => { }); it("should call createMediaKeys again if the platform needs re-creation of the MediaKeys", async () => { - mockCompat({ - canReuseMediaKeys: vi.fn(() => false), - }); + mockCompat(mocks); + mocks.canReuseMediaKeys.mockImplementation(() => false); const mockCreateMediaKeys = vi.spyOn( MediaKeySystemAccessImpl.prototype, "createMediaKeys", ); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { const contentDecryptor1 = new ContentDecryptor(videoElt, ksConfig); let receivedStateChange1 = 0; @@ -263,17 +281,12 @@ describe("decrypt - global tests - media key system access", () => { }); it("should not call createMediaKeys again if the platform needs MediaKeySystemAccess renewal", async () => { - mockCompat({ - shouldRenewMediaKeySystemAccess: vi.fn(() => true), - }); + mockCompat(mocks); + mocks.shouldRenewMediaKeySystemAccess.mockImplementation(() => true); const mockCreateMediaKeys = vi.spyOn( MediaKeySystemAccessImpl.prototype, "createMediaKeys", ); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; return new Promise((res, rej) => { const contentDecryptor1 = new ContentDecryptor(videoElt, ksConfig); @@ -331,16 +344,13 @@ describe("decrypt - global tests - media key system access", () => { }); it("should not create any session if no encrypted event was received", async () => { - // == mocks == - const mockSetMediaKeys = vi.fn(() => Promise.resolve()); - mockCompat({ setMediaKeys: mockSetMediaKeys }); + mockCompat(mocks); + mocks.setMediaKeys.mockImplementation(() => { + /* noop */ + }); const mockCreateSession = vi.spyOn(MediaKeysImpl.prototype, "createSession"); // == test == - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; const contentDecryptor = new ContentDecryptor(videoElt, ksConfig); return new Promise((res) => { contentDecryptor.addEventListener("stateChange", (newState) => { @@ -348,8 +358,11 @@ describe("decrypt - global tests - media key system access", () => { contentDecryptor.removeEventListener("stateChange"); contentDecryptor.attach(); setTimeout(() => { - expect(mockSetMediaKeys).toHaveBeenCalledTimes(1); - expect(mockSetMediaKeys).toHaveBeenCalledWith(videoElt, new MediaKeysImpl()); + expect(mocks.setMediaKeys).toHaveBeenCalledTimes(1); + expect(mocks.setMediaKeys).toHaveBeenCalledWith( + videoElt, + new MediaKeysImpl(), + ); expect(mockCreateSession).not.toHaveBeenCalled(); res(); }, 5); diff --git a/src/main_thread/decrypt/__tests__/__global__/server_certificate.test.ts b/src/main_thread/decrypt/__tests__/__global__/server_certificate.test.ts index 62dd11e928..07d466a8ed 100644 --- a/src/main_thread/decrypt/__tests__/__global__/server_certificate.test.ts +++ b/src/main_thread/decrypt/__tests__/__global__/server_certificate.test.ts @@ -1,9 +1,38 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; import type { IKeySystemOption } from "../../../../public_types"; -import type IContentDecryptor from "../../content_decryptor"; -import type { ContentDecryptorState as IContentDecryptorState } from "../../types"; +import ContentDecryptor from "../../content_decryptor"; +import { ContentDecryptorState } from "../../types"; import { MediaKeysImpl, MediaKeySystemAccessImpl, mockCompat } from "./utils"; +const mocks = vi.hoisted(() => { + return { + shouldRenewMediaKeySystemAccess: vi.fn(() => false), + canReuseMediaKeys: vi.fn(() => true), + onEncrypted: vi.fn(), + requestMediaKeySystemAccess: vi.fn(), + setMediaKeys: vi.fn(), + getInitData: vi.fn(), + generateKeyRequest: vi.fn(), + }; +}); +vi.mock("../../../../compat/should_renew_media_key_system_access", () => ({ + default: mocks.shouldRenewMediaKeySystemAccess, +})); +vi.mock("../../../../compat/can_reuse_media_keys", () => ({ + default: mocks.canReuseMediaKeys, +})); +vi.mock("../../../../compat/eme", () => ({ + default: { + onEncrypted: mocks.onEncrypted, + requestMediaKeySystemAccess: mocks.requestMediaKeySystemAccess, + setMediaKeys: mocks.setMediaKeys, + }, + getInitData: mocks.getInitData, + generateKeyRequest: mocks.generateKeyRequest, + closeSession: vi.fn(), + loadSession: vi.fn(), +})); + describe("decrypt - global tests - server certificate", () => { const mockGetLicense = vi.fn(() => { return new Promise(() => { @@ -11,9 +40,6 @@ describe("decrypt - global tests - server certificate", () => { }); }); - /** Default video element used in our tests. */ - const videoElt = document.createElement("video"); - const serverCertificate = new Uint8Array([1, 2, 3]); /** Default keySystems configuration used in our tests. */ @@ -30,9 +56,20 @@ describe("decrypt - global tests - server certificate", () => { vi.restoreAllMocks(); }); - it("should set the serverCertificate only after the MediaKeys is attached", async () => { - const { mockSetMediaKeys } = mockCompat(); - mockSetMediaKeys.mockImplementation(() => { + afterEach(() => { + mocks.shouldRenewMediaKeySystemAccess.mockReset(); + mocks.canReuseMediaKeys.mockReset(); + mocks.onEncrypted.mockReset(); + mocks.requestMediaKeySystemAccess.mockReset(); + mocks.setMediaKeys.mockReset(); + mocks.getInitData.mockReset(); + mocks.generateKeyRequest.mockReset(); + }); + + it("should set the serverCertificate only after the MediaKeys is attached", () => { + const videoElt = document.createElement("video"); + mockCompat(mocks); + mocks.setMediaKeys.mockImplementation(() => { expect(mockCreateSession).not.toHaveBeenCalled(); expect(mockSetServerCertificate).not.toHaveBeenCalled(); return Promise.resolve(); @@ -41,15 +78,11 @@ describe("decrypt - global tests - server certificate", () => { const mockSetServerCertificate = vi .spyOn(MediaKeysImpl.prototype, "setServerCertificate") .mockImplementation((_serverCertificate: BufferSource) => { - expect(mockSetMediaKeys).toHaveBeenCalledTimes(1); + expect(mocks.setMediaKeys).toHaveBeenCalledTimes(1); expect(mockCreateSession).not.toHaveBeenCalled(); return Promise.resolve(true); }); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; const contentDecryptor = new ContentDecryptor(videoElt, ksConfigCert); return new Promise((res) => { @@ -57,16 +90,18 @@ describe("decrypt - global tests - server certificate", () => { if (state === ContentDecryptorState.WaitingForAttachment) { contentDecryptor.removeEventListener("stateChange"); setTimeout(() => { - expect(mockSetMediaKeys).not.toHaveBeenCalled(); + expect(mocks.setMediaKeys).not.toHaveBeenCalled(); expect(mockCreateSession).not.toHaveBeenCalled(); expect(mockSetServerCertificate).not.toHaveBeenCalled(); contentDecryptor.attach(); }, 5); setTimeout(() => { contentDecryptor.dispose(); - expect(mockSetMediaKeys).toHaveBeenCalledTimes(1); + expect(mocks.setMediaKeys).toHaveBeenCalledTimes(1); expect(mockSetServerCertificate).toHaveBeenCalledTimes(1); expect(mockCreateSession).not.toHaveBeenCalled(); + mockSetServerCertificate.mockRestore(); + mockCreateSession.mockRestore(); res(); }, 10); } @@ -74,9 +109,10 @@ describe("decrypt - global tests - server certificate", () => { }); }); - it("should not call serverCertificate multiple times on init data", async () => { - const { mockSetMediaKeys } = mockCompat(); - mockSetMediaKeys.mockImplementation(() => { + it("should not call serverCertificate multiple times on init data", () => { + const videoElt = document.createElement("video"); + mockCompat(mocks); + mocks.setMediaKeys.mockImplementation(() => { expect(mockCreateSession).not.toHaveBeenCalled(); expect(mockSetServerCertificate).not.toHaveBeenCalled(); return Promise.resolve(); @@ -85,22 +121,18 @@ describe("decrypt - global tests - server certificate", () => { const mockSetServerCertificate = vi .spyOn(MediaKeysImpl.prototype, "setServerCertificate") .mockImplementation((_serverCertificate: BufferSource) => { - expect(mockSetMediaKeys).toHaveBeenCalledTimes(1); + expect(mocks.setMediaKeys).toHaveBeenCalledTimes(1); expect(mockCreateSession).not.toHaveBeenCalled(); return Promise.resolve(true); }); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; const contentDecryptor = new ContentDecryptor(videoElt, ksConfigCert); contentDecryptor.addEventListener("stateChange", (state) => { if (state === ContentDecryptorState.WaitingForAttachment) { contentDecryptor.removeEventListener("stateChange"); setTimeout(() => { - expect(mockSetMediaKeys).not.toHaveBeenCalled(); + expect(mocks.setMediaKeys).not.toHaveBeenCalled(); expect(mockCreateSession).not.toHaveBeenCalled(); expect(mockSetServerCertificate).not.toHaveBeenCalled(); const initData = new Uint8Array([54, 55, 75]); @@ -115,7 +147,7 @@ describe("decrypt - global tests - server certificate", () => { return new Promise((res) => { setTimeout(() => { contentDecryptor.dispose(); - expect(mockSetMediaKeys).toHaveBeenCalledTimes(1); + expect(mocks.setMediaKeys).toHaveBeenCalledTimes(1); expect(mockSetServerCertificate).toHaveBeenCalledTimes(1); expect(mockCreateSession).toHaveBeenCalledTimes(1); res(); @@ -123,8 +155,9 @@ describe("decrypt - global tests - server certificate", () => { }); }); - it("should emit warning if serverCertificate call rejects but still continue", async () => { - const { mockSetMediaKeys } = mockCompat(); + it("should emit warning if serverCertificate call rejects but still continue", () => { + const videoElt = document.createElement("video"); + mockCompat(mocks); const mockCreateSession = vi.spyOn(MediaKeysImpl.prototype, "createSession"); const mockSetServerCertificate = vi .spyOn(MediaKeysImpl.prototype, "setServerCertificate") @@ -132,10 +165,6 @@ describe("decrypt - global tests - server certificate", () => { throw new Error("some error"); }); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; const contentDecryptor = new ContentDecryptor(videoElt, ksConfigCert); contentDecryptor.addEventListener("stateChange", (state) => { @@ -154,7 +183,7 @@ describe("decrypt - global tests - server certificate", () => { return new Promise((res) => { setTimeout(() => { contentDecryptor.dispose(); - expect(mockSetMediaKeys).toHaveBeenCalledTimes(1); + expect(mocks.setMediaKeys).toHaveBeenCalledTimes(1); expect(mockSetServerCertificate).toHaveBeenCalledTimes(1); expect(mockCreateSession).not.toHaveBeenCalled(); expect(warningsReceived).toEqual(1); @@ -163,8 +192,9 @@ describe("decrypt - global tests - server certificate", () => { }); }); - it("should emit warning if serverCertificate call throws but still continue", async () => { - const { mockSetMediaKeys } = mockCompat(); + it("should emit warning if serverCertificate call throws but still continue", () => { + const videoElt = document.createElement("video"); + mockCompat(mocks); const mockCreateSession = vi.spyOn(MediaKeysImpl.prototype, "createSession"); const mockSetServerCertificate = vi .spyOn(MediaKeysImpl.prototype, "setServerCertificate") @@ -172,10 +202,6 @@ describe("decrypt - global tests - server certificate", () => { return Promise.reject(new Error("some error")); }); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; const contentDecryptor = new ContentDecryptor(videoElt, ksConfigCert); contentDecryptor.addEventListener("stateChange", (state) => { @@ -194,7 +220,7 @@ describe("decrypt - global tests - server certificate", () => { return new Promise((res) => { setTimeout(() => { contentDecryptor.dispose(); - expect(mockSetMediaKeys).toHaveBeenCalledTimes(1); + expect(mocks.setMediaKeys).toHaveBeenCalledTimes(1); expect(mockSetServerCertificate).toHaveBeenCalledTimes(1); expect(mockCreateSession).not.toHaveBeenCalled(); expect(warningsReceived).toEqual(1); @@ -203,8 +229,9 @@ describe("decrypt - global tests - server certificate", () => { }); }); - it("should just continue if setServerCertificate is undefined", async () => { - const { mockSetMediaKeys } = mockCompat(); + it("should just continue if setServerCertificate is undefined", () => { + const videoElt = document.createElement("video"); + mockCompat(mocks); vi.spyOn(MediaKeySystemAccessImpl.prototype, "createMediaKeys").mockImplementation( () => { const mediaKeys = new MediaKeysImpl(); @@ -213,7 +240,7 @@ describe("decrypt - global tests - server certificate", () => { return Promise.resolve(mediaKeys); }, ); - mockSetMediaKeys.mockImplementation(() => { + mocks.setMediaKeys.mockImplementation(() => { expect(mockCreateSession).not.toHaveBeenCalled(); expect(mockSetServerCertificate).not.toHaveBeenCalled(); return Promise.resolve(); @@ -223,17 +250,13 @@ describe("decrypt - global tests - server certificate", () => { MediaKeysImpl.prototype, "setServerCertificate", ); - const ContentDecryptorState = (await vi.importActual("../../types")) - .ContentDecryptorState as typeof IContentDecryptorState; - const ContentDecryptor = (await vi.importActual("../../content_decryptor")) - .default as typeof IContentDecryptor; const contentDecryptor = new ContentDecryptor(videoElt, ksConfigCert); contentDecryptor.addEventListener("stateChange", (state) => { if (state === ContentDecryptorState.WaitingForAttachment) { contentDecryptor.removeEventListener("stateChange"); setTimeout(() => { - expect(mockSetMediaKeys).not.toHaveBeenCalled(); + expect(mocks.setMediaKeys).not.toHaveBeenCalled(); expect(mockCreateSession).not.toHaveBeenCalled(); expect(mockSetServerCertificate).not.toHaveBeenCalled(); const initData = new Uint8Array([54, 55, 75]); @@ -249,7 +272,7 @@ describe("decrypt - global tests - server certificate", () => { return new Promise((res) => { setTimeout(() => { contentDecryptor.dispose(); - expect(mockSetMediaKeys).toHaveBeenCalledTimes(1); + expect(mocks.setMediaKeys).toHaveBeenCalledTimes(1); expect(mockSetServerCertificate).not.toHaveBeenCalled(); expect(mockCreateSession).toHaveBeenCalledTimes(1); res(); diff --git a/src/main_thread/decrypt/__tests__/__global__/utils.ts b/src/main_thread/decrypt/__tests__/__global__/utils.ts index 8d060a61ad..7788ed0138 100644 --- a/src/main_thread/decrypt/__tests__/__global__/utils.ts +++ b/src/main_thread/decrypt/__tests__/__global__/utils.ts @@ -1,7 +1,7 @@ -import type { MockInstance } from "vitest"; +import type { Mock, MockInstance } from "vitest"; import { vi } from "vitest"; import type { IMediaElement } from "../../../../compat/browser_compatibility_types"; -import type { IEmeApiImplementation, IEncryptedEventData } from "../../../../compat/eme"; +import type { IEncryptedEventData } from "../../../../compat/eme"; import type { IKeySystemOption } from "../../../../public_types"; import { base64ToBytes, bytesToBase64 } from "../../../../utils/base64"; import EventEmitter from "../../../../utils/event_emitter"; @@ -272,37 +272,35 @@ class MockedDecryptorEventEmitter extends EventEmitter<{ /** * Mock functions coming from the compat directory. */ -export function mockCompat( - presets: { - canReuseMediaKeys?: MockInstance; - shouldRenewMediaKeySystemAccess?: MockInstance; - onEncrypted?: MockInstance; - requestMediaKeySystemAccess?: MockInstance; - setMediaKeys?: MockInstance; - } = {}, -) { +export function mockCompat(mocks: { + canReuseMediaKeys: Mock; + shouldRenewMediaKeySystemAccess: Mock; + onEncrypted: Mock; + requestMediaKeySystemAccess: Mock; + setMediaKeys: Mock; + getInitData: Mock; + generateKeyRequest: Mock; +}) { const ee = new MockedDecryptorEventEmitter(); - const onEncrypted = - presets.onEncrypted ?? - vi - .fn() - .mockImplementation( - (elt: IMediaElement, fn: (x: unknown) => void, signal: CancellationSignal) => { - elt.addEventListener("encrypted", fn); - signal.register(() => { - elt.removeEventListener("encrypted", fn); - }); - ee.addEventListener( - "encrypted", - (evt) => { - if (evt.elt === elt) { - fn(evt.value); - } - }, - signal, - ); - }, - ); + const onEncrypted = ( + elt: IMediaElement, + fn: (x: unknown) => void, + signal: CancellationSignal, + ) => { + elt.addEventListener("encrypted", fn); + signal.register(() => { + elt.removeEventListener("encrypted", fn); + }); + ee.addEventListener( + "encrypted", + (evt) => { + if (evt.elt === elt) { + fn(evt.value); + } + }, + signal, + ); + }; const mockEvents: Record = { onKeyMessage: vi .fn() @@ -366,59 +364,25 @@ export function mockCompat( ), }; - const mockRmksa = - presets.requestMediaKeySystemAccess ?? - vi.fn().mockImplementation(requestMediaKeySystemAccessImpl); - const mockSetMediaKeys = - presets.setMediaKeys ?? vi.fn().mockImplementation(() => Promise.resolve()); - const mockGenerateKeyRequest = vi - .fn() - .mockImplementation( - ( - mks: MediaKeySessionImpl, - initializationDataType: string, - initializationData: BufferSource, - ) => { - return mks.generateRequest(initializationDataType, initializationData); - }, - ); - - const mockGetInitData = vi - .fn() - .mockImplementation((encryptedEvent: IEncryptedEventData) => { - return encryptedEvent; - }); - - if (presets.shouldRenewMediaKeySystemAccess === undefined) { - vi.doMock("../../../../compat/should_renew_media_key_system_access", () => ({ - default: vi.fn().mockImplementation(() => false), - })); - } else { - vi.doMock("../../../../compat/should_renew_media_key_system_access", () => ({ - default: presets.shouldRenewMediaKeySystemAccess, - })); - } - if (presets.canReuseMediaKeys === undefined) { - vi.doMock("../../../../compat/can_reuse_media_keys", () => ({ - default: vi.fn().mockImplementation(() => true), - })); - } else { - vi.doMock("../../../../compat/can_reuse_media_keys", () => ({ - default: presets.canReuseMediaKeys, - })); - } + const mockRmksa = requestMediaKeySystemAccessImpl; + const mockSetMediaKeys = () => Promise.resolve(); + const mockGenerateKeyRequest = ( + mks: MediaKeySessionImpl, + initializationDataType: string, + initializationData: BufferSource, + ) => { + return mks.generateRequest(initializationDataType, initializationData); + }; - const emeImplementation = { - onEncrypted, - requestMediaKeySystemAccess: mockRmksa, - setMediaKeys: mockSetMediaKeys, - } as unknown as IEmeApiImplementation; + const mockGetInitData = (encryptedEvent: IEncryptedEventData) => { + return encryptedEvent; + }; - vi.doMock("../../../../compat/eme", () => ({ - default: emeImplementation, - getInitData: mockGetInitData, - generateKeyRequest: mockGenerateKeyRequest, - })); + mocks.onEncrypted.mockImplementation(onEncrypted); + mocks.requestMediaKeySystemAccess.mockImplementation(mockRmksa); + mocks.setMediaKeys.mockImplementation(mockSetMediaKeys); + mocks.getInitData.mockImplementation(mockGetInitData); + mocks.generateKeyRequest.mockImplementation(mockGenerateKeyRequest); return { mockEvents, @@ -436,10 +400,6 @@ export function mockCompat( ee.triggerKeyStatusesChange(session, value); }, }, - mockRequestMediaKeySystemAccess: mockRmksa, - mockGetInitData, - mockSetMediaKeys, - mockGenerateKeyRequest, }; } diff --git a/src/main_thread/decrypt/__tests__/find_key_system.test.ts b/src/main_thread/decrypt/__tests__/find_key_system.test.ts index 565d3135bc..3c09bfe901 100644 --- a/src/main_thread/decrypt/__tests__/find_key_system.test.ts +++ b/src/main_thread/decrypt/__tests__/find_key_system.test.ts @@ -1,4 +1,3 @@ -import type { MockInstance } from "vitest"; import { describe, beforeEach, it, expect, vi } from "vitest"; import eme from "../../../compat/eme"; import type { IKeySystemOption } from "../../../public_types"; @@ -7,13 +6,28 @@ import getMediaKeySystemAccess from "../find_key_system"; import LoadedSessionsStore from "../utils/loaded_sessions_store"; import mediaKeysAttacher from "../utils/media_keys_attacher"; -describe("find_key_systems - ", () => { - let requestMediaKeySystemAccessMock: MockInstance; +const mocks = vi.hoisted(() => { + return { + requestMediaKeySystemAccess: vi.fn(), + }; +}); +vi.mock("../../../compat/eme", () => ({ + default: { + onEncrypted: vi.fn(), + requestMediaKeySystemAccess: mocks.requestMediaKeySystemAccess, + setMediaKeys: vi.fn(() => Promise.resolve()), + }, + getInitData: vi.fn(), + generateKeyRequest: vi.fn(), + closeSession: vi.fn(), + loadSession: vi.fn(), +})); +describe("find_key_systems - ", () => { beforeEach(() => { vi.resetModules(); vi.restoreAllMocks(); - requestMediaKeySystemAccessMock = vi.spyOn(eme, "requestMediaKeySystemAccess"); + mocks.requestMediaKeySystemAccess.mockReset(); }); const baseEmeConfiguration: MediaKeySystemConfiguration = { @@ -148,12 +162,13 @@ describe("find_key_systems - ", () => { }; it("should create a media key the first time and then reuse the previous one if it's the same configuration", async () => { - requestMediaKeySystemAccessMock.mockImplementation(() => { + mocks.requestMediaKeySystemAccess.mockImplementation(() => { return { createMediaKeys: () => ({ createSession: () => ({ - // eslint-disable-next-line @typescript-eslint/no-empty-function - generateRequest: () => {}, + generateRequest: () => { + /* noop */ + }, }), }), getConfiguration: () => { @@ -198,18 +213,19 @@ describe("find_key_systems - ", () => { }); it("should create a media key the first time and then create another one if the previous is not compatible.", async () => { - requestMediaKeySystemAccessMock.mockImplementation(() => { - return { + mocks.requestMediaKeySystemAccess.mockImplementation(() => { + return Promise.resolve({ createMediaKeys: () => ({ createSession: () => ({ - // eslint-disable-next-line @typescript-eslint/no-empty-function - generateRequest: () => {}, + generateRequest: () => { + /* noop */ + }, }), }), getConfiguration: () => { return baseEmeConfiguration; }, - }; + }); }); const mediaElement = document.createElement("video"); const keySystemOptionsA: IKeySystemOption[] = [ @@ -256,18 +272,19 @@ describe("find_key_systems - ", () => { }); it("should create a media key the first time and then reuse the previous one if it's a different configuration but it's a compatible configuration.", async () => { - requestMediaKeySystemAccessMock.mockImplementation(() => { - return { + mocks.requestMediaKeySystemAccess.mockImplementation(() => { + return Promise.resolve({ createMediaKeys: () => ({ createSession: () => ({ - // eslint-disable-next-line @typescript-eslint/no-empty-function - generateRequest: () => {}, + generateRequest: () => { + /* noop */ + }, }), }), getConfiguration: () => { return baseEmeConfiguration; }, - }; + }); }); const mediaElement = document.createElement("video"); const keySystemOptionsA: IKeySystemOption[] = [ diff --git a/src/main_thread/decrypt/utils/__tests__/clean_old_stored_persistent_info.test.ts b/src/main_thread/decrypt/utils/__tests__/clean_old_stored_persistent_info.test.ts index b7d7934bef..72c3fe06aa 100644 --- a/src/main_thread/decrypt/utils/__tests__/clean_old_stored_persistent_info.test.ts +++ b/src/main_thread/decrypt/utils/__tests__/clean_old_stored_persistent_info.test.ts @@ -1,7 +1,12 @@ -import { describe, it, expect, vi } from "vitest"; -import type ICleanOldStoredPersistentInfo from "../clean_old_stored_persistent_info"; +import { describe, it, expect, vi, afterEach } from "vitest"; +import log from "../../../../log"; +import cleanOldStoredPersistentInfo from "../clean_old_stored_persistent_info"; import type PersistentSessionsStore from "../persistent_sessions_store"; +const logInfo = vi.spyOn(log, "info").mockImplementation(() => { + /* noop */ +}); + function createPersistentSessionsStore(): PersistentSessionsStore { return { getLength(): number { @@ -31,21 +36,15 @@ const emptyPersistentSessionsStore = { * @param {Object} persistentSessionsStore * @param {number} limit */ -async function checkNothingHappen( +function checkNothingHappen( persistentSessionsStore: PersistentSessionsStore, limit: number, ) { + logInfo.mockClear(); const mockDeleteLast = vi.spyOn(persistentSessionsStore, "deleteOldSessions"); - const mockLogInfo = vi.fn(); - vi.doMock("../../../../log", () => ({ - default: { info: mockLogInfo }, - })); - const cleanOldStoredPersistentInfo = ( - await vi.importActual("../clean_old_stored_persistent_info") - ).default as typeof ICleanOldStoredPersistentInfo; cleanOldStoredPersistentInfo(persistentSessionsStore, limit); expect(mockDeleteLast).not.toHaveBeenCalled(); - expect(mockLogInfo).not.toHaveBeenCalled(); + expect(logInfo).not.toHaveBeenCalled(); vi.resetModules(); } @@ -56,24 +55,18 @@ async function checkNothingHappen( * @param {number} limit * @param {number} numberToRemove */ -async function checkRemoved( +function checkRemoved( persistentSessionsStore: PersistentSessionsStore, limit: number, numberToRemove: number, ) { + logInfo.mockClear(); const mockDeleteLast = vi.spyOn(persistentSessionsStore, "deleteOldSessions"); - const mockLogInfo = vi.fn(); - vi.doMock("../../../../log", () => ({ - default: { info: mockLogInfo }, - })); - const cleanOldStoredPersistentInfo = ( - await vi.importActual("../clean_old_stored_persistent_info") - ).default as typeof ICleanOldStoredPersistentInfo; cleanOldStoredPersistentInfo(persistentSessionsStore, limit); expect(mockDeleteLast).toHaveBeenCalledTimes(1); expect(mockDeleteLast).toHaveBeenCalledWith(numberToRemove); - expect(mockLogInfo).toHaveBeenCalledTimes(1); - expect(mockLogInfo).toHaveBeenCalledWith( + expect(logInfo).toHaveBeenCalledTimes(1); + expect(logInfo).toHaveBeenCalledWith( "DRM: Too many stored persistent sessions," + " removing some.", persistentSessionsStore.getLength(), numberToRemove, @@ -82,44 +75,47 @@ async function checkRemoved( } describe("decrypt - cleanOldStoredPersistentInfo", () => { - it("should do nothing with a negative limit", async () => { - await checkNothingHappen(createPersistentSessionsStore(), -1); - await checkNothingHappen(createPersistentSessionsStore(), -20); - await checkNothingHappen(emptyPersistentSessionsStore, -20); + afterEach(() => { + logInfo.mockClear(); + }); + it("should do nothing with a negative limit", () => { + checkNothingHappen(createPersistentSessionsStore(), -1); + checkNothingHappen(createPersistentSessionsStore(), -20); + checkNothingHappen(emptyPersistentSessionsStore, -20); }); - it("should do nothing with a limit equal to NaN", async () => { - await checkNothingHappen(createPersistentSessionsStore(), NaN); - await checkNothingHappen(emptyPersistentSessionsStore, NaN); + it("should do nothing with a limit equal to NaN", () => { + checkNothingHappen(createPersistentSessionsStore(), NaN); + checkNothingHappen(emptyPersistentSessionsStore, NaN); }); - it("should do nothing with a limit equal to -infinity", async () => { - await checkNothingHappen(createPersistentSessionsStore(), -Infinity); - await checkNothingHappen(emptyPersistentSessionsStore, -Infinity); + it("should do nothing with a limit equal to -infinity", () => { + checkNothingHappen(createPersistentSessionsStore(), -Infinity); + checkNothingHappen(emptyPersistentSessionsStore, -Infinity); }); - it("should do nothing if the limit is superior to the current length", async () => { - await checkNothingHappen(createPersistentSessionsStore(), 4); - await checkNothingHappen(createPersistentSessionsStore(), 5); - await checkNothingHappen(createPersistentSessionsStore(), 6); - await checkNothingHappen(createPersistentSessionsStore(), +Infinity); - await checkNothingHappen(emptyPersistentSessionsStore, 1); - await checkNothingHappen(emptyPersistentSessionsStore, 2); - await checkNothingHappen(emptyPersistentSessionsStore, 1000); - await checkNothingHappen(emptyPersistentSessionsStore, +Infinity); + it("should do nothing if the limit is superior to the current length", () => { + checkNothingHappen(createPersistentSessionsStore(), 4); + checkNothingHappen(createPersistentSessionsStore(), 5); + checkNothingHappen(createPersistentSessionsStore(), 6); + checkNothingHappen(createPersistentSessionsStore(), +Infinity); + checkNothingHappen(emptyPersistentSessionsStore, 1); + checkNothingHappen(emptyPersistentSessionsStore, 2); + checkNothingHappen(emptyPersistentSessionsStore, 1000); + checkNothingHappen(emptyPersistentSessionsStore, +Infinity); }); - it("should do nothing if the limit is equal to the current length", async () => { - await checkNothingHappen(createPersistentSessionsStore(), 3); - await checkNothingHappen(emptyPersistentSessionsStore, 0); + it("should do nothing if the limit is equal to the current length", () => { + checkNothingHappen(createPersistentSessionsStore(), 3); + checkNothingHappen(emptyPersistentSessionsStore, 0); }); - it("should remove some if the limit is inferior to the current length", async () => { - await checkRemoved(createPersistentSessionsStore(), 1, 2); - await checkRemoved(createPersistentSessionsStore(), 2, 1); + it("should remove some if the limit is inferior to the current length", () => { + checkRemoved(createPersistentSessionsStore(), 1, 2); + checkRemoved(createPersistentSessionsStore(), 2, 1); }); - it("should remove all if the limit is equal to 0", async () => { - await checkRemoved(createPersistentSessionsStore(), 0, 3); + it("should remove all if the limit is equal to 0", () => { + checkRemoved(createPersistentSessionsStore(), 0, 3); }); }); diff --git a/src/main_thread/init/utils/__tests__/are_same_stream_events.test.ts b/src/main_thread/init/utils/__tests__/are_same_stream_events.test.ts index 20d52431e9..817688d1e5 100644 --- a/src/main_thread/init/utils/__tests__/are_same_stream_events.test.ts +++ b/src/main_thread/init/utils/__tests__/are_same_stream_events.test.ts @@ -1,49 +1,34 @@ -import { describe, it, expect, vi } from "vitest"; -import type IAreSameStreamEvents from "../stream_events_emitter/are_same_stream_events"; +import { describe, it, expect } from "vitest"; +import areSameStreamEvents from "../stream_events_emitter/are_same_stream_events"; describe("init - areSameStreamEvents", () => { - it("should consider two events to be the same with defined ends", async () => { + it("should consider two events to be the same with defined ends", () => { const evt1 = { start: 0, end: 10, id: "1" }; const evt2 = { start: 0, end: 10, id: "1" }; - const areSameStreamEvents = ( - await vi.importActual("../stream_events_emitter/are_same_stream_events.ts") - ).default as typeof IAreSameStreamEvents; const result = areSameStreamEvents(evt1, evt2); expect(result).toBe(true); }); - it("should consider two events to be the same with undefined ends", async () => { + it("should consider two events to be the same with undefined ends", () => { const evt1 = { start: 0, end: undefined, id: "1" }; const evt2 = { start: 0, end: undefined, id: "1" }; - const areSameStreamEvents = ( - await vi.importActual("../stream_events_emitter/are_same_stream_events.ts") - ).default as typeof IAreSameStreamEvents; const result = areSameStreamEvents(evt1, evt2); expect(result).toBe(true); }); - it("should consider two events not to be the same - different ids", async () => { + it("should consider two events not to be the same - different ids", () => { const evt1 = { start: 0, end: undefined, id: "1" }; const evt2 = { start: 0, end: undefined, id: "2" }; - const areSameStreamEvents = ( - await vi.importActual("../stream_events_emitter/are_same_stream_events.ts") - ).default as typeof IAreSameStreamEvents; const result = areSameStreamEvents(evt1, evt2); expect(result).toBe(false); }); - it("should consider two events not to be the same - different starts", async () => { + it("should consider two events not to be the same - different starts", () => { const evt1 = { start: 0, end: undefined, id: "1" }; const evt2 = { start: 10, end: undefined, id: "1" }; - const areSameStreamEvents = ( - await vi.importActual("../stream_events_emitter/are_same_stream_events.ts") - ).default as typeof IAreSameStreamEvents; const result = areSameStreamEvents(evt1, evt2); expect(result).toBe(false); }); - it("should consider two events not to be the same - different end", async () => { + it("should consider two events not to be the same - different end", () => { const evt1 = { start: 0, end: 10, id: "1" }; const evt2 = { start: 0, end: 30, id: "1" }; - const areSameStreamEvents = ( - await vi.importActual("../stream_events_emitter/are_same_stream_events.ts") - ).default as typeof IAreSameStreamEvents; const result = areSameStreamEvents(evt1, evt2); expect(result).toBe(false); }); diff --git a/src/main_thread/init/utils/__tests__/refresh_scheduled_events_list.test.ts b/src/main_thread/init/utils/__tests__/refresh_scheduled_events_list.test.ts index 9c6cdd5ad9..db48f0974a 100644 --- a/src/main_thread/init/utils/__tests__/refresh_scheduled_events_list.test.ts +++ b/src/main_thread/init/utils/__tests__/refresh_scheduled_events_list.test.ts @@ -1,14 +1,14 @@ -import { describe, it, expect, vi } from "vitest"; +import { describe, it, expect } from "vitest"; import type { IManifest } from "../../../../manifest"; import type { IStreamEventData } from "../../../../public_types"; -import type IRefreshScheduledEventsList from "../stream_events_emitter/refresh_scheduled_events_list"; +import refreshScheduledEventsList from "../stream_events_emitter/refresh_scheduled_events_list"; import type { INonFiniteStreamEventPayload, IStreamEventPayload, } from "../stream_events_emitter/types"; describe("init - refreshScheduledEventsList", () => { - it("should correctly refresh scheduled events", async () => { + it("should correctly refresh scheduled events", () => { function generateEventData(): IStreamEventData { return { type: "dash-event-stream", @@ -60,9 +60,6 @@ describe("init - refreshScheduledEventsList", () => { }, }, ]; - const refreshScheduledEventsList = ( - await vi.importActual("../stream_events_emitter/refresh_scheduled_events_list.ts") - ).default as typeof IRefreshScheduledEventsList; const scheduledEvents = refreshScheduledEventsList(oldScheduledEvents, manifest); expect(scheduledEvents).toEqual([ diff --git a/src/main_thread/init/utils/create_media_source.ts b/src/main_thread/init/utils/create_media_source.ts index 1baa39c876..6a5f2da3d9 100644 --- a/src/main_thread/init/utils/create_media_source.ts +++ b/src/main_thread/init/utils/create_media_source.ts @@ -14,10 +14,8 @@ * limitations under the License. */ -import { - isManagedMediaSource, - type IMediaElement, -} from "../../../compat/browser_compatibility_types"; +import type { IMediaElement } from "../../../compat/browser_compatibility_types"; +import BROWSER_GLOBALS from "../../../compat/browser_compatibility_types"; import clearElementSrc from "../../../compat/clear_element_src"; import log from "../../../log"; import MainMediaSourceInterface from "../../../mse/main_media_source_interface"; @@ -75,6 +73,7 @@ export function disableRemotePlaybackOnManagedMediaSource( mediaElement: IMediaElement, cancellationSignal: CancellationSignal, ) { + const { isManagedMediaSource } = BROWSER_GLOBALS; if (isManagedMediaSource && "disableRemotePlayback" in mediaElement) { const disableRemotePlaybackPreviousValue = mediaElement.disableRemotePlayback; cancellationSignal.register(() => { diff --git a/src/manifest/classes/__tests__/adaptation.test.ts b/src/manifest/classes/__tests__/adaptation.test.ts index 57c6feff37..6f94f0cff1 100644 --- a/src/manifest/classes/__tests__/adaptation.test.ts +++ b/src/manifest/classes/__tests__/adaptation.test.ts @@ -1,13 +1,27 @@ -import { describe, beforeEach, afterEach, it, expect, vi } from "vitest"; +import { describe, beforeEach, it, expect, vi } from "vitest"; import type { IParsedAdaptation, IParsedRepresentation } from "../../../parsers/manifest"; import type { IRepresentationContext, IRepresentationFilterRepresentation, } from "../../../public_types"; -import type IAdaptation from "../adaptation"; +import Adaptation from "../adaptation"; import CodecSupportCache from "../codec_support_cache"; import type { IRepresentationIndex } from "../representation_index"; +const mocks = vi.hoisted(() => { + return { + fakeRepresentation: vi.fn(), + normalize: vi.fn(), + }; +}); + +vi.mock("../representation", () => ({ + default: mocks.fakeRepresentation, +})); +vi.mock("../../../utils/languages", () => ({ + default: mocks.normalize, +})); + const minimalRepresentationIndex: IRepresentationIndex = { getInitSegment() { return null; @@ -58,7 +72,7 @@ const minimalRepresentationIndex: IRepresentationIndex = { /* noop */ }, }; -const mockDefaultRepresentationImpl = vi.fn((arg: IParsedRepresentation) => { +const mockDefaultRepresentationImpl = function (arg: IParsedRepresentation) { return { bitrate: arg.bitrate, id: arg.id, @@ -68,23 +82,18 @@ const mockDefaultRepresentationImpl = vi.fn((arg: IParsedRepresentation) => { }, index: arg.index, }; -}); +}; describe("Manifest - Adaptation", () => { beforeEach(() => { vi.resetModules(); - }); - afterEach(() => { - mockDefaultRepresentationImpl.mockClear(); + mocks.fakeRepresentation.mockReset(); + mocks.normalize.mockReset(); }); - it("should be able to create a minimal Adaptation", async () => { - vi.doMock("../representation", () => ({ - default: mockDefaultRepresentationImpl, - })); + it("should be able to create a minimal Adaptation", () => { + mocks.fakeRepresentation.mockImplementation(mockDefaultRepresentationImpl); - const Adaptation = (await vi.importActual("../adaptation")) - .default as typeof IAdaptation; const args: IParsedAdaptation = { id: "12", representations: [], type: "video" }; const codecSupportCache = new CodecSupportCache([]); const adaptation = new Adaptation(args, codecSupportCache); @@ -98,20 +107,13 @@ describe("Manifest - Adaptation", () => { expect(adaptation.manuallyAdded).toBe(false); expect(adaptation.getRepresentation("")).toBe(undefined); - expect(mockDefaultRepresentationImpl).not.toHaveBeenCalled(); + expect(mocks.fakeRepresentation).not.toHaveBeenCalled(); }); - it("should normalize a given language", async () => { - vi.doMock("../representation", () => ({ - default: mockDefaultRepresentationImpl, - })); - const mockNormalize = vi.fn((lang: string) => lang + "foo"); - vi.doMock("../../../utils/languages", () => ({ - default: mockNormalize, - })); - - const Adaptation = (await vi.importActual("../adaptation")) - .default as typeof IAdaptation; + it("should normalize a given language", () => { + mocks.fakeRepresentation.mockImplementation(mockDefaultRepresentationImpl); + mocks.normalize.mockImplementation((lang: string) => lang + "foo"); + const args1: IParsedAdaptation = { id: "12", representations: [], @@ -122,9 +124,9 @@ describe("Manifest - Adaptation", () => { const adaptation1 = new Adaptation(args1, codecSupportCache); expect(adaptation1.language).toBe("fr"); expect(adaptation1.normalizedLanguage).toBe("frfoo"); - expect(mockNormalize).toHaveBeenCalledTimes(1); - expect(mockNormalize).toHaveBeenCalledWith("fr"); - mockNormalize.mockClear(); + expect(mocks.normalize).toHaveBeenCalledTimes(1); + expect(mocks.normalize).toHaveBeenCalledWith("fr"); + mocks.normalize.mockClear(); const args2: IParsedAdaptation = { id: "12", @@ -135,36 +137,25 @@ describe("Manifest - Adaptation", () => { const adaptation2 = new Adaptation(args2, codecSupportCache); expect(adaptation2.language).toBe("toto"); expect(adaptation2.normalizedLanguage).toBe("totofoo"); - expect(mockNormalize).toHaveBeenCalledTimes(1); - expect(mockNormalize).toHaveBeenCalledWith("toto"); + expect(mocks.normalize).toHaveBeenCalledTimes(1); + expect(mocks.normalize).toHaveBeenCalledWith("toto"); }); - it("should not call normalize if no language is given", async () => { - vi.doMock("../representation", () => ({ - default: mockDefaultRepresentationImpl, - })); - const mockNormalize = vi.fn((lang: string) => lang + "foo"); - vi.doMock("../../../utils/languages", () => ({ - default: mockNormalize, - })); - - const Adaptation = (await vi.importActual("../adaptation")) - .default as typeof IAdaptation; + it("should not call normalize if no language is given", () => { + mocks.fakeRepresentation.mockImplementation(mockDefaultRepresentationImpl); + mocks.normalize.mockImplementation((lang: string) => lang + "foo"); + const args1: IParsedAdaptation = { id: "12", representations: [], type: "video" }; const codecSupportCache = new CodecSupportCache([]); const adaptation1 = new Adaptation(args1, codecSupportCache); expect(adaptation1.language).toBe(undefined); expect(adaptation1.normalizedLanguage).toBe(undefined); - expect(mockNormalize).not.toHaveBeenCalled(); + expect(mocks.normalize).not.toHaveBeenCalled(); }); - it("should create and sort the corresponding Representations", async () => { - vi.doMock("../representation", () => ({ - default: mockDefaultRepresentationImpl, - })); + it("should create and sort the corresponding Representations", () => { + mocks.fakeRepresentation.mockImplementation(mockDefaultRepresentationImpl); - const Adaptation = (await vi.importActual("../adaptation")) - .default as typeof IAdaptation; const rep1 = { bitrate: 10, id: "rep1", @@ -189,20 +180,20 @@ describe("Manifest - Adaptation", () => { const codecSupportCache = new CodecSupportCache([]); const adaptation = new Adaptation(args, codecSupportCache); const parsedRepresentations = adaptation.representations; - expect(mockDefaultRepresentationImpl).toHaveBeenCalledTimes(3); - expect(mockDefaultRepresentationImpl).toHaveBeenNthCalledWith( + expect(mocks.fakeRepresentation).toHaveBeenCalledTimes(3); + expect(mocks.fakeRepresentation).toHaveBeenNthCalledWith( 1, rep1, "text", codecSupportCache, ); - expect(mockDefaultRepresentationImpl).toHaveBeenNthCalledWith( + expect(mocks.fakeRepresentation).toHaveBeenNthCalledWith( 2, rep2, "text", codecSupportCache, ); - expect(mockDefaultRepresentationImpl).toHaveBeenNthCalledWith( + expect(mocks.fakeRepresentation).toHaveBeenNthCalledWith( 3, rep3, "text", @@ -217,8 +208,8 @@ describe("Manifest - Adaptation", () => { expect(adaptation.getRepresentation("rep2")?.bitrate).toEqual(30); }); - it("should execute the representationFilter if given", async () => { - const mockRepresentation = vi.fn((arg: IParsedRepresentation) => { + it("should execute the representationFilter if given", () => { + mocks.fakeRepresentation.mockImplementation((arg: IParsedRepresentation) => { return { bitrate: arg.bitrate, id: arg.id, @@ -230,12 +221,6 @@ describe("Manifest - Adaptation", () => { }; }); - vi.doMock("../representation", () => ({ - default: mockRepresentation, - })); - - const Adaptation = (await vi.importActual("../adaptation")) - .default as typeof IAdaptation; const rep1 = { bitrate: 10, id: "rep1", @@ -310,17 +295,9 @@ describe("Manifest - Adaptation", () => { expect(adaptation.getRepresentation("rep4")?.id).toEqual("rep4"); }); - it("should set an isDub value if one", async () => { - vi.doMock("../representation", () => ({ - default: mockDefaultRepresentationImpl, - })); - const mockNormalize = vi.fn((lang: string) => lang + "foo"); - vi.doMock("../../../utils/languages", () => ({ - default: mockNormalize, - })); - - const Adaptation = (await vi.importActual("../adaptation")) - .default as typeof IAdaptation; + it("should set an isDub value if one", () => { + mocks.fakeRepresentation.mockImplementation(mockDefaultRepresentationImpl); + mocks.normalize.mockImplementation((lang: string) => lang + "foo"); const args1: IParsedAdaptation = { id: "12", @@ -333,7 +310,7 @@ describe("Manifest - Adaptation", () => { expect(adaptation1.language).toBe(undefined); expect(adaptation1.normalizedLanguage).toBe(undefined); expect(adaptation1.isDub).toEqual(false); - expect(mockNormalize).not.toHaveBeenCalled(); + expect(mocks.normalize).not.toHaveBeenCalled(); const args2: IParsedAdaptation = { id: "12", @@ -345,20 +322,12 @@ describe("Manifest - Adaptation", () => { expect(adaptation2.language).toBe(undefined); expect(adaptation2.normalizedLanguage).toBe(undefined); expect(adaptation2.isDub).toEqual(true); - expect(mockNormalize).not.toHaveBeenCalled(); + expect(mocks.normalize).not.toHaveBeenCalled(); }); - it("should set an isClosedCaption value if one", async () => { - vi.doMock("../representation", () => ({ - default: mockDefaultRepresentationImpl, - })); - const mockNormalize = vi.fn((lang: string) => lang + "foo"); - vi.doMock("../../../utils/languages", () => ({ - default: mockNormalize, - })); - - const Adaptation = (await vi.importActual("../adaptation")) - .default as typeof IAdaptation; + it("should set an isClosedCaption value if one", () => { + mocks.fakeRepresentation.mockImplementation(mockDefaultRepresentationImpl); + mocks.normalize.mockImplementation((lang: string) => lang + "foo"); const args1: IParsedAdaptation = { id: "12", @@ -371,7 +340,7 @@ describe("Manifest - Adaptation", () => { expect(adaptation1.language).toBe(undefined); expect(adaptation1.normalizedLanguage).toBe(undefined); expect(adaptation1.isClosedCaption).toEqual(false); - expect(mockNormalize).not.toHaveBeenCalled(); + expect(mocks.normalize).not.toHaveBeenCalled(); const args2: IParsedAdaptation = { id: "12", @@ -383,21 +352,12 @@ describe("Manifest - Adaptation", () => { expect(adaptation2.language).toBe(undefined); expect(adaptation2.normalizedLanguage).toBe(undefined); expect(adaptation2.isClosedCaption).toEqual(true); - expect(mockNormalize).not.toHaveBeenCalled(); + expect(mocks.normalize).not.toHaveBeenCalled(); }); - it("should set an isAudioDescription value if one", async () => { - vi.doMock("../representation", () => ({ - default: mockDefaultRepresentationImpl, - })); - const mockNormalize = vi.fn((lang: string) => lang + "foo"); - - vi.doMock("../../../utils/languages", () => ({ - default: mockNormalize, - })); - - const Adaptation = (await vi.importActual("../adaptation")) - .default as typeof IAdaptation; + it("should set an isAudioDescription value if one", () => { + mocks.fakeRepresentation.mockImplementation(mockDefaultRepresentationImpl); + mocks.normalize.mockImplementation((lang: string) => lang + "foo"); const args1: IParsedAdaptation = { id: "12", @@ -410,7 +370,7 @@ describe("Manifest - Adaptation", () => { expect(adaptation1.language).toBe(undefined); expect(adaptation1.normalizedLanguage).toBe(undefined); expect(adaptation1.isAudioDescription).toEqual(false); - expect(mockNormalize).not.toHaveBeenCalled(); + expect(mocks.normalize).not.toHaveBeenCalled(); const args2: IParsedAdaptation = { id: "12", @@ -422,20 +382,12 @@ describe("Manifest - Adaptation", () => { expect(adaptation2.language).toBe(undefined); expect(adaptation2.normalizedLanguage).toBe(undefined); expect(adaptation2.isAudioDescription).toEqual(true); - expect(mockNormalize).not.toHaveBeenCalled(); + expect(mocks.normalize).not.toHaveBeenCalled(); }); - it("should set a manuallyAdded value if one", async () => { - vi.doMock("../representation", () => ({ - default: mockDefaultRepresentationImpl, - })); - const mockNormalize = vi.fn((lang: string) => lang + "foo"); - vi.doMock("../../../utils/languages", () => ({ - default: mockNormalize, - })); - - const Adaptation = (await vi.importActual("../adaptation")) - .default as typeof IAdaptation; + it("should set a manuallyAdded value if one", () => { + mocks.fakeRepresentation.mockImplementation(mockDefaultRepresentationImpl); + mocks.normalize.mockImplementation((lang: string) => lang + "foo"); const args1: IParsedAdaptation = { id: "12", representations: [], type: "video" }; const codecSupportCache = new CodecSupportCache([]); @@ -445,7 +397,7 @@ describe("Manifest - Adaptation", () => { expect(adaptation1.language).toBe(undefined); expect(adaptation1.normalizedLanguage).toBe(undefined); expect(adaptation1.manuallyAdded).toEqual(false); - expect(mockNormalize).not.toHaveBeenCalled(); + expect(mocks.normalize).not.toHaveBeenCalled(); const args2: IParsedAdaptation = { id: "12", representations: [], type: "video" }; const adaptation2 = new Adaptation(args2, codecSupportCache, { @@ -454,16 +406,12 @@ describe("Manifest - Adaptation", () => { expect(adaptation2.language).toBe(undefined); expect(adaptation2.normalizedLanguage).toBe(undefined); expect(adaptation2.manuallyAdded).toEqual(true); - expect(mockNormalize).not.toHaveBeenCalled(); + expect(mocks.normalize).not.toHaveBeenCalled(); }); - it("should return the first Representation with the given Id with `getRepresentation`", async () => { - vi.doMock("../representation", () => ({ - default: mockDefaultRepresentationImpl, - })); + it("should return the first Representation with the given Id with `getRepresentation`", () => { + mocks.fakeRepresentation.mockImplementation(mockDefaultRepresentationImpl); - const Adaptation = (await vi.importActual("../adaptation")) - .default as typeof IAdaptation; const rep1 = { bitrate: 10, id: "rep1", @@ -491,13 +439,9 @@ describe("Manifest - Adaptation", () => { expect(adaptation.getRepresentation("rep2")?.bitrate).toEqual(20); }); - it("should return undefined in `getRepresentation` if no representation is found with this Id", async () => { - vi.doMock("../representation", () => ({ - default: mockDefaultRepresentationImpl, - })); + it("should return undefined in `getRepresentation` if no representation is found with this Id", () => { + mocks.fakeRepresentation.mockImplementation(mockDefaultRepresentationImpl); - const Adaptation = (await vi.importActual("../adaptation")) - .default as typeof IAdaptation; const rep1 = { bitrate: 10, id: "rep1", diff --git a/src/manifest/classes/__tests__/manifest.test.ts b/src/manifest/classes/__tests__/manifest.test.ts index 9cd9b78778..72d835fa2a 100644 --- a/src/manifest/classes/__tests__/manifest.test.ts +++ b/src/manifest/classes/__tests__/manifest.test.ts @@ -8,9 +8,46 @@ import type { IPlayerError } from "../../../public_types"; import getMonotonicTimeStamp from "../../../utils/monotonic_timestamp"; import type IAdaptation from "../adaptation"; import CodecSupportCache from "../codec_support_cache"; -import type IManifest from "../manifest"; +import Manifest from "../manifest"; import type IPeriod from "../period"; +const mocks = vi.hoisted(() => { + const fakeGenerateNewId = vi.fn(() => "fakeId"); + const fakeIdGenerator = vi.fn(() => fakeGenerateNewId); + const fakePeriod = vi.fn(); + const fakeReplacePeriods = vi.fn(); + const fakeLogger = { + warn: vi.fn(() => undefined), + info: vi.fn(() => undefined), + }; + return { + fakeLogger, + fakeGenerateNewId, + fakeIdGenerator, + fakePeriod, + fakeReplacePeriods, + }; +}); + +vi.mock("../../../log", () => { + return { + default: mocks.fakeLogger, + }; +}); +vi.mock("../../../utils/id_generator", () => ({ + default: mocks.fakeIdGenerator, +})); +vi.mock("../period", () => ({ + default: mocks.fakePeriod, +})); +vi.mock("../update_periods", async () => { + const updatePeriods = (await vi.importActual("../update_periods")).updatePeriods; + return { + replacePeriods: mocks.fakeReplacePeriods, + updatePeriods, + }; +}); + function generateParsedPeriod( id: string, start: number, @@ -38,28 +75,19 @@ function generateParsedRepresentation(id: string): IParsedRepresentation { } describe("Manifest - Manifest", () => { - const fakeLogger = { - warn: vi.fn(() => undefined), - info: vi.fn(() => undefined), - }; - const fakeGenerateNewId = vi.fn(() => "fakeId"); - const fakeIdGenerator = vi.fn(() => fakeGenerateNewId); - beforeEach(() => { vi.resetModules(); - fakeLogger.warn.mockClear(); - fakeLogger.info.mockClear(); - vi.doMock("../../../log", () => ({ - default: fakeLogger, - })); - fakeGenerateNewId.mockClear(); - fakeIdGenerator.mockClear(); - vi.doMock("../../../utils/id_generator", () => ({ - default: fakeIdGenerator, - })); + mocks.fakeLogger.warn.mockReset(); + mocks.fakeLogger.info.mockReset(); + mocks.fakeGenerateNewId.mockReset(); + mocks.fakeIdGenerator.mockReset(); + mocks.fakePeriod.mockReset(); + mocks.fakeReplacePeriods.mockReset(); + mocks.fakeGenerateNewId.mockImplementation(() => "fakeId"); + mocks.fakeIdGenerator.mockImplementation(() => mocks.fakeGenerateNewId); }); - it("should create a normalized Manifest structure", async () => { + it("should create a normalized Manifest structure", () => { const simpleFakeManifest = { id: "man", transportType: "dash", @@ -80,7 +108,6 @@ describe("Manifest - Manifest", () => { periods: [], }; - const Manifest = (await vi.importActual("../manifest")).default as typeof IManifest; const warnings: IPlayerError[] = []; const manifest = new Manifest(simpleFakeManifest, {}, warnings); @@ -97,13 +124,12 @@ describe("Manifest - Manifest", () => { expect(manifest.suggestedPresentationDelay).toEqual(undefined); expect(manifest.uris).toEqual([]); - expect(fakeIdGenerator).toHaveBeenCalled(); - expect(fakeGenerateNewId).toHaveBeenCalledTimes(1); - expect(fakeLogger.info).not.toHaveBeenCalled(); - expect(fakeLogger.warn).not.toHaveBeenCalled(); + expect(mocks.fakeGenerateNewId).toHaveBeenCalledTimes(1); + expect(mocks.fakeLogger.info).not.toHaveBeenCalled(); + expect(mocks.fakeLogger.warn).not.toHaveBeenCalled(); }); - it("should create a Period for each manifest.periods given", async () => { + it("should create a Period for each manifest.periods given", () => { const period1 = generateParsedPeriod("0", 4, undefined); const period2 = generateParsedPeriod("1", 12, undefined); const simpleFakeManifest = { @@ -126,23 +152,19 @@ describe("Manifest - Manifest", () => { periods: [period1, period2], }; - const fakePeriod = vi.fn((period: IPeriod) => { + mocks.fakePeriod.mockImplementation((period: IPeriod) => { return { id: `foo${period.id}`, adaptations: period.adaptations }; }); - vi.doMock("../period", () => ({ - default: fakePeriod, - })); - const Manifest = (await vi.importActual("../manifest")).default as typeof IManifest; const manifest = new Manifest(simpleFakeManifest, {}, []); - expect(fakePeriod).toHaveBeenCalledTimes(2); - expect(fakePeriod).toHaveBeenCalledWith( + expect(mocks.fakePeriod).toHaveBeenCalledTimes(2); + expect(mocks.fakePeriod).toHaveBeenCalledWith( period1, [], new CodecSupportCache([]), undefined, ); - expect(fakePeriod).toHaveBeenCalledWith( + expect(mocks.fakePeriod).toHaveBeenCalledWith( period2, [], new CodecSupportCache([]), @@ -155,13 +177,12 @@ describe("Manifest - Manifest", () => { ]); expect(manifest.adaptations).toEqual(period1.adaptations); - expect(fakeIdGenerator).toHaveBeenCalled(); - expect(fakeGenerateNewId).toHaveBeenCalledTimes(1); - expect(fakeLogger.info).not.toHaveBeenCalled(); - expect(fakeLogger.warn).not.toHaveBeenCalled(); + expect(mocks.fakeGenerateNewId).toHaveBeenCalledTimes(1); + expect(mocks.fakeLogger.info).not.toHaveBeenCalled(); + expect(mocks.fakeLogger.warn).not.toHaveBeenCalled(); }); - it("should pass a `representationFilter` to the Period if given", async () => { + it("should pass a `representationFilter` to the Period if given", () => { const period1 = generateParsedPeriod("0", 4, undefined); const period2 = generateParsedPeriod("1", 12, undefined); const simpleFakeManifest = { @@ -188,37 +209,32 @@ describe("Manifest - Manifest", () => { return false; }; - const fakePeriod = vi.fn((period: IParsedPeriod): IPeriod => { + mocks.fakePeriod.mockImplementation((period: IParsedPeriod): IPeriod => { return { id: `foo${period.id}` } as IPeriod; }); - vi.doMock("../period", () => ({ - default: fakePeriod, - })); - const Manifest = (await vi.importActual("../manifest")).default as typeof IManifest; const manifest = new Manifest(simpleFakeManifest, { representationFilter }, []); expect(manifest).not.toBe(null); - expect(fakePeriod).toHaveBeenCalledTimes(2); - expect(fakePeriod).toHaveBeenCalledWith( + expect(mocks.fakePeriod).toHaveBeenCalledTimes(2); + expect(mocks.fakePeriod).toHaveBeenCalledWith( period1, [], new CodecSupportCache([]), representationFilter, ); - expect(fakePeriod).toHaveBeenCalledWith( + expect(mocks.fakePeriod).toHaveBeenCalledWith( period2, [], new CodecSupportCache([]), representationFilter, ); - expect(fakeIdGenerator).toHaveBeenCalled(); - expect(fakeGenerateNewId).toHaveBeenCalledTimes(1); - expect(fakeLogger.info).not.toHaveBeenCalled(); - expect(fakeLogger.warn).not.toHaveBeenCalled(); + expect(mocks.fakeGenerateNewId).toHaveBeenCalledTimes(1); + expect(mocks.fakeLogger.info).not.toHaveBeenCalled(); + expect(mocks.fakeLogger.warn).not.toHaveBeenCalled(); }); - it("should expose the adaptations of the first period if set", async () => { + it("should expose the adaptations of the first period if set", () => { const adapP1 = {}; const adapP2 = {}; const period1 = { id: "0", start: 4, adaptations: adapP1 }; @@ -243,23 +259,19 @@ describe("Manifest - Manifest", () => { periods: [period1, period2], }; - const fakePeriod = vi.fn((period: IParsedPeriod): IPeriod => { + mocks.fakePeriod.mockImplementation((period: IParsedPeriod): IPeriod => { return { ...period, id: `foo${period.id}` } as unknown as IPeriod; }); - vi.doMock("../period", () => ({ - default: fakePeriod, - })); - const Manifest = (await vi.importActual("../manifest")).default as typeof IManifest; const manifest = new Manifest(simpleFakeManifest, {}, []); - expect(fakePeriod).toHaveBeenCalledTimes(2); - expect(fakePeriod).toHaveBeenCalledWith( + expect(mocks.fakePeriod).toHaveBeenCalledTimes(2); + expect(mocks.fakePeriod).toHaveBeenCalledWith( period1, [], new CodecSupportCache([]), undefined, ); - expect(fakePeriod).toHaveBeenCalledWith( + expect(mocks.fakePeriod).toHaveBeenCalledWith( period2, [], new CodecSupportCache([]), @@ -272,13 +284,12 @@ describe("Manifest - Manifest", () => { ]); expect(manifest.adaptations).toBe(adapP1); - expect(fakeIdGenerator).toHaveBeenCalled(); - expect(fakeGenerateNewId).toHaveBeenCalledTimes(1); - expect(fakeLogger.info).not.toHaveBeenCalled(); - expect(fakeLogger.warn).not.toHaveBeenCalled(); + expect(mocks.fakeGenerateNewId).toHaveBeenCalledTimes(1); + expect(mocks.fakeLogger.info).not.toHaveBeenCalled(); + expect(mocks.fakeLogger.warn).not.toHaveBeenCalled(); }); - it("should push parsing errors if there are unsupported Adaptations", async () => { + it("should push parsing errors if there are unsupported Adaptations", () => { const period1 = generateParsedPeriod("0", 4, undefined); const period2 = generateParsedPeriod("1", 12, undefined); const simpleFakeManifest = { @@ -301,7 +312,7 @@ describe("Manifest - Manifest", () => { periods: [period1, period2], }; - const fakePeriod = vi.fn( + mocks.fakePeriod.mockImplementation( (period: IParsedPeriod, unsupportedAdaptations: IAdaptation[]): IPeriod => { unsupportedAdaptations.push({ type: "audio", @@ -314,10 +325,6 @@ describe("Manifest - Manifest", () => { return { ...period, id: `foo${period.id}` } as unknown as IPeriod; }, ); - vi.doMock("../period", () => ({ - default: fakePeriod, - })); - const Manifest = (await vi.importActual("../manifest")).default as typeof IManifest; const warnings: IPlayerError[] = []; new Manifest(simpleFakeManifest, {}, warnings); @@ -347,13 +354,12 @@ describe("Manifest - Manifest", () => { }, ]); - expect(fakeIdGenerator).toHaveBeenCalled(); - expect(fakeGenerateNewId).toHaveBeenCalledTimes(1); - expect(fakeLogger.info).not.toHaveBeenCalled(); - expect(fakeLogger.warn).not.toHaveBeenCalled(); + expect(mocks.fakeGenerateNewId).toHaveBeenCalledTimes(1); + expect(mocks.fakeLogger.info).not.toHaveBeenCalled(); + expect(mocks.fakeLogger.warn).not.toHaveBeenCalled(); }); - it("should correctly parse every manifest information given", async () => { + it("should correctly parse every manifest information given", () => { const oldPeriod1 = generateParsedPeriod("0", 4, undefined); const oldPeriod2 = generateParsedPeriod("1", 12, undefined); const time = getMonotonicTimeStamp(); @@ -381,7 +387,7 @@ describe("Manifest - Manifest", () => { uris: ["url1", "url2"], }; - const fakePeriod = vi.fn( + mocks.fakePeriod.mockImplementation( (period: IParsedPeriod, unsupportedAdaptations: IAdaptation[]): IPeriod => { unsupportedAdaptations.push({ id: period.adaptations.audio?.[0].id, @@ -391,10 +397,6 @@ describe("Manifest - Manifest", () => { return { ...period, id: `foo${period.id}` } as unknown as IPeriod; }, ); - vi.doMock("../period", () => ({ - default: fakePeriod, - })); - const Manifest = (await vi.importActual("../manifest")).default as typeof IManifest; const warnings: IPlayerError[] = []; const manifest = new Manifest(oldManifestArgs, {}, warnings); @@ -417,14 +419,13 @@ describe("Manifest - Manifest", () => { ]); expect(manifest.suggestedPresentationDelay).toEqual(99); expect(manifest.uris).toEqual(["url1", "url2"]); - expect(fakeIdGenerator).toHaveBeenCalled(); - expect(fakeGenerateNewId).toHaveBeenCalledTimes(1); - expect(fakeLogger.info).not.toHaveBeenCalled(); - expect(fakeLogger.warn).not.toHaveBeenCalled(); + expect(mocks.fakeGenerateNewId).toHaveBeenCalledTimes(1); + expect(mocks.fakeLogger.info).not.toHaveBeenCalled(); + expect(mocks.fakeLogger.warn).not.toHaveBeenCalled(); }); - it("should return all URLs given with `getContentUrls`", async () => { - const fakePeriod = vi.fn( + it("should return all URLs given with `getContentUrls`", () => { + mocks.fakePeriod.mockImplementation( (period: IParsedPeriod, unsupportedAdaptations: IAdaptation[]): IPeriod => { unsupportedAdaptations.push({ id: period.adaptations.audio?.[0].id, @@ -434,10 +435,6 @@ describe("Manifest - Manifest", () => { return { ...period, id: `foo${period.id}` } as unknown as IPeriod; }, ); - vi.doMock("../period", () => ({ - default: fakePeriod, - })); - const Manifest = (await vi.importActual("../manifest")).default as typeof IManifest; const oldPeriod1 = generateParsedPeriod("0", 4, undefined); const oldPeriod2 = generateParsedPeriod("1", 12, undefined); @@ -498,8 +495,8 @@ describe("Manifest - Manifest", () => { expect(manifest2.getUrls()).toEqual([]); }); - it("should replace with a new Manifest when calling `replace`", async () => { - const fakePeriod = vi.fn( + it("should replace with a new Manifest when calling `replace`", () => { + mocks.fakePeriod.mockImplementation( (period: IParsedPeriod, unsupportedAdaptations: IAdaptation[]): IPeriod => { unsupportedAdaptations.push({ id: period.adaptations.audio?.[0].id, @@ -514,14 +511,7 @@ describe("Manifest - Manifest", () => { addedPeriods: [], removedPeriods: [], }; - const fakeReplacePeriods = vi.fn(() => fakeReplacePeriodsRes); - vi.doMock("../period", () => ({ - default: fakePeriod, - })); - vi.doMock("../update_periods", () => ({ - replacePeriods: fakeReplacePeriods, - })); - + mocks.fakeReplacePeriods.mockImplementation(() => fakeReplacePeriodsRes); const oldPeriod1 = generateParsedPeriod("0", 4, undefined); const oldPeriod2 = generateParsedPeriod("1", 12, undefined); const oldManifestArgs = { @@ -548,12 +538,11 @@ describe("Manifest - Manifest", () => { uris: ["url1", "url2"], }; - const Manifest = (await vi.importActual("../manifest")).default as typeof IManifest; const manifest = new Manifest(oldManifestArgs, {}, []); const mockTrigger = vi .spyOn( - manifest as IManifest & { + manifest as Manifest & { trigger: (eventName: string, payload: unknown) => void; }, "trigger", @@ -591,20 +580,19 @@ describe("Manifest - Manifest", () => { }, periods: [newPeriod1, newPeriod2], uris: ["url3", "url4"], - } as unknown as IManifest; + } as unknown as Manifest; manifest.replace(newManifest); - expect(fakeReplacePeriods).toHaveBeenCalledTimes(1); - expect(fakeReplacePeriods).toHaveBeenCalledWith( + expect(mocks.fakeReplacePeriods).toHaveBeenCalledTimes(1); + expect(mocks.fakeReplacePeriods).toHaveBeenCalledWith( manifest.periods, newManifest.periods, ); expect(mockTrigger).toHaveBeenCalledTimes(1); expect(mockTrigger).toHaveBeenCalledWith("manifestUpdate", fakeReplacePeriodsRes); - expect(fakeIdGenerator).toHaveBeenCalled(); - expect(fakeGenerateNewId).toHaveBeenCalledTimes(1); - expect(fakeLogger.info).not.toHaveBeenCalled(); - expect(fakeLogger.warn).not.toHaveBeenCalled(); + expect(mocks.fakeGenerateNewId).toHaveBeenCalledTimes(1); + expect(mocks.fakeLogger.info).not.toHaveBeenCalled(); + expect(mocks.fakeLogger.warn).not.toHaveBeenCalled(); mockTrigger.mockRestore(); }); }); diff --git a/src/manifest/classes/__tests__/period.test.ts b/src/manifest/classes/__tests__/period.test.ts index 371cd9c19f..00a79abc82 100644 --- a/src/manifest/classes/__tests__/period.test.ts +++ b/src/manifest/classes/__tests__/period.test.ts @@ -2,15 +2,30 @@ import { describe, beforeEach, it, expect, vi } from "vitest"; import type { IParsedAdaptation, IParsedPeriod } from "../../../parsers/manifest"; import type Adaptation from "../adaptation"; import CodecSupportCache from "../codec_support_cache"; -import type IPeriod from "../period"; +import Period from "../period"; + +const mocks = vi.hoisted(() => { + const fakeAdaptation = vi.fn(); + const SUPPORTED_ADAPTATIONS_TYPE: string[] = []; + return { + fakeAdaptation, + SUPPORTED_ADAPTATIONS_TYPE, + }; +}); + +vi.mock("../adaptation", () => ({ + default: mocks.fakeAdaptation, +})); describe("Manifest - Period", () => { beforeEach(() => { + mocks.fakeAdaptation.mockClear(); + mocks.SUPPORTED_ADAPTATIONS_TYPE.length = 0; vi.resetModules(); }); - it("should throw if no adaptation is given", async () => { - const mockAdaptation = vi.fn((arg: IParsedAdaptation) => ({ + it("should throw if no adaptation is given", () => { + mocks.fakeAdaptation.mockImplementation((arg: IParsedAdaptation) => ({ ...arg, supportStatus: { hasSupportedCodec: undefined, @@ -18,14 +33,10 @@ describe("Manifest - Period", () => { isDecipherable: undefined, }, })); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const args = { id: "12", adaptations: {}, start: 0 }; - let period: IPeriod | null = null; + let period: Period | null = null; let errorReceived: unknown = null; const unsupportedAdaptations: Adaptation[] = []; try { @@ -47,11 +58,11 @@ describe("Manifest - Period", () => { expect((errorReceived as { code?: string }).code).toBe("MANIFEST_PARSE_ERROR"); expect(errorReceived.message).toContain("No supported audio and video tracks."); - expect(mockAdaptation).not.toHaveBeenCalled(); + expect(mocks.fakeAdaptation).not.toHaveBeenCalled(); }); - it("should throw if no audio nor video adaptation is given", async () => { - const mockAdaptation = vi.fn( + it("should throw if no audio nor video adaptation is given", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -62,12 +73,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text", "foo"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text", "foo"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const fooAda1 = { type: "foo", id: "54", @@ -84,7 +91,7 @@ describe("Manifest - Period", () => { adaptations: { foo }, start: 0, } as unknown as IParsedPeriod; - let period: IPeriod | null = null; + let period: Period | null = null; let errorReceived: unknown = null; const unsupportedAdaptations: Adaptation[] = []; const codecSupportCache = new CodecSupportCache([]); @@ -108,13 +115,23 @@ describe("Manifest - Period", () => { expect((errorReceived as { type?: string }).type).toBe("MEDIA_ERROR"); expect(errorReceived.message).toContain("No supported audio and video tracks."); - expect(mockAdaptation).toHaveBeenCalledTimes(2); - expect(mockAdaptation).toHaveBeenNthCalledWith(1, fooAda1, codecSupportCache, {}); - expect(mockAdaptation).toHaveBeenNthCalledWith(2, fooAda2, codecSupportCache, {}); + expect(mocks.fakeAdaptation).toHaveBeenCalledTimes(2); + expect(mocks.fakeAdaptation).toHaveBeenNthCalledWith( + 1, + fooAda1, + codecSupportCache, + {}, + ); + expect(mocks.fakeAdaptation).toHaveBeenNthCalledWith( + 2, + fooAda2, + codecSupportCache, + {}, + ); }); - it("should throw if only empty audio and/or video adaptations is given", async () => { - const mockAdaptation = vi.fn( + it("should throw if only empty audio and/or video adaptations is given", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -125,14 +142,10 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text", "foo"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text", "foo"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const args = { id: "12", adaptations: { video: [], audio: [] }, start: 0 }; - let period: IPeriod | null = null; + let period: Period | null = null; let errorReceived: unknown = null; const unsupportedAdaptations: Adaptation[] = []; try { @@ -156,11 +169,11 @@ describe("Manifest - Period", () => { expect((errorReceived as { type?: string }).type).toBe("MEDIA_ERROR"); expect(errorReceived.message).toContain("No supported audio and video tracks."); - expect(mockAdaptation).toHaveBeenCalledTimes(0); + expect(mocks.fakeAdaptation).toHaveBeenCalledTimes(0); }); - it("should throw if we are left with no audio representation", async () => { - const mockAdaptation = vi.fn( + it("should throw if we are left with no audio representation", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -171,12 +184,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text", "foo"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text", "foo"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -225,7 +234,7 @@ describe("Manifest - Period", () => { adaptations: { video, audio }, start: 0, } as unknown as IParsedPeriod; - let period: IPeriod | null = null; + let period: Period | null = null; let errorReceived: unknown = null; const unsupportedAdaptations: Adaptation[] = []; try { @@ -252,8 +261,8 @@ describe("Manifest - Period", () => { expect(errorReceived.message).toContain("No supported audio adaptations"); }); - it("should throw if no audio Adaptation is supported", async () => { - const mockAdaptation = vi.fn( + it("should throw if no audio Adaptation is supported", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -264,12 +273,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text", "foo"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text", "foo"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -325,7 +330,7 @@ describe("Manifest - Period", () => { adaptations: { video, audio }, start: 0, }; - let period: IPeriod | null = null; + let period: Period | null = null; let errorReceived: unknown = null; const unsupportedAdaptations: Adaptation[] = []; try { @@ -354,8 +359,8 @@ describe("Manifest - Period", () => { expect(errorReceived.message).toContain("No supported audio adaptations"); }); - it("should throw if we are left with no video representation", async () => { - const mockAdaptation = vi.fn( + it("should throw if we are left with no video representation", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -366,12 +371,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text", "foo"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text", "foo"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -423,7 +424,7 @@ describe("Manifest - Period", () => { audioAda2, ] as unknown as IParsedAdaptation[]; const args: IParsedPeriod = { id: "12", adaptations: { video, audio }, start: 0 }; - let period: IPeriod | null = null; + let period: Period | null = null; let errorReceived: unknown = null; const unsupportedAdaptations: Adaptation[] = []; try { @@ -450,8 +451,8 @@ describe("Manifest - Period", () => { expect(errorReceived.message).toContain("No supported video adaptation"); }); - it("should throw if no video adaptation is supported", async () => { - const mockAdaptation = vi.fn( + it("should throw if no video adaptation is supported", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -462,12 +463,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text", "foo"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text", "foo"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -516,7 +513,7 @@ describe("Manifest - Period", () => { }; const audio = [audioAda1, audioAda2] as unknown as IParsedAdaptation[]; const args = { id: "12", adaptations: { video, audio }, start: 0 }; - let period: IPeriod | null = null; + let period: Period | null = null; let errorReceived: unknown = null; const unsupportedAdaptations: Adaptation[] = []; try { @@ -543,8 +540,8 @@ describe("Manifest - Period", () => { expect(errorReceived.message).toContain("No supported video adaptation"); }); - it("should set a parsing error if an unsupported adaptation is given", async () => { - const mockAdaptation = vi.fn( + it("should set a parsing error if an unsupported adaptation is given", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -555,12 +552,7 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text", "foo"], - })); - - const Period = (await vi.importActual("../period")).default as typeof IPeriod; + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text", "foo"]); const videoAda1 = { type: "video", @@ -586,19 +578,19 @@ describe("Manifest - Period", () => { const period = new Period(args, unsupportedAdaptations, codecSupportCache); expect(unsupportedAdaptations).toHaveLength(1); - expect(mockAdaptation).toHaveBeenCalledTimes(2); - expect(mockAdaptation).toHaveReturnedTimes(2); - expect(mockAdaptation).toHaveBeenCalledWith(videoAda1, codecSupportCache, {}); - expect(mockAdaptation).toHaveBeenCalledWith(videoAda2, codecSupportCache, {}); - expect(mockAdaptation).toHaveReturnedWith(period.adaptations.video?.[0]); + expect(mocks.fakeAdaptation).toHaveBeenCalledTimes(2); + expect(mocks.fakeAdaptation).toHaveReturnedTimes(2); + expect(mocks.fakeAdaptation).toHaveBeenCalledWith(videoAda1, codecSupportCache, {}); + expect(mocks.fakeAdaptation).toHaveBeenCalledWith(videoAda2, codecSupportCache, {}); + expect(mocks.fakeAdaptation).toHaveReturnedWith(period.adaptations.video?.[0]); const [adap] = unsupportedAdaptations; expect(adap.id).toBe("56"); expect(adap.supportStatus.hasSupportedCodec).toBe(false); }); - it("should not set a parsing error if an empty unsupported adaptation is given", async () => { - const mockAdaptation = vi.fn( + it("should not set a parsing error if an empty unsupported adaptation is given", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -609,12 +601,7 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text", "foo"], - })); - - const Period = (await vi.importActual("../period")).default as typeof IPeriod; + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text", "foo"]); const videoAda1 = { type: "video", @@ -642,12 +629,12 @@ describe("Manifest - Period", () => { }); expect(unsupportedAdaptations).toHaveLength(0); - expect(mockAdaptation).toHaveBeenCalledTimes(1); - expect(mockAdaptation).toHaveBeenCalledWith(videoAda1, codecSupportCache, {}); + expect(mocks.fakeAdaptation).toHaveBeenCalledTimes(1); + expect(mocks.fakeAdaptation).toHaveBeenCalledWith(videoAda1, codecSupportCache, {}); }); - it("should give a representationFilter to the adaptation", async () => { - const mockAdaptation = vi.fn( + it("should give a representationFilter to the adaptation", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -659,12 +646,8 @@ describe("Manifest - Period", () => { }) as unknown as Adaptation, ); const representationFilter = vi.fn(); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -695,18 +678,28 @@ describe("Manifest - Period", () => { expect(unsupportedAdaptations).toHaveLength(0); expect(period.adaptations.video).toHaveLength(2); - expect(mockAdaptation).toHaveBeenCalledTimes(2); - expect(mockAdaptation).toHaveBeenNthCalledWith(1, videoAda1, codecSupportCache, { - representationFilter, - }); - expect(mockAdaptation).toHaveBeenNthCalledWith(2, videoAda2, codecSupportCache, { - representationFilter, - }); + expect(mocks.fakeAdaptation).toHaveBeenCalledTimes(2); + expect(mocks.fakeAdaptation).toHaveBeenNthCalledWith( + 1, + videoAda1, + codecSupportCache, + { + representationFilter, + }, + ); + expect(mocks.fakeAdaptation).toHaveBeenNthCalledWith( + 2, + videoAda2, + codecSupportCache, + { + representationFilter, + }, + ); expect(representationFilter).not.toHaveBeenCalled(); }); - it("should report if Adaptations are not supported", async () => { - const mockAdaptation = vi.fn( + it("should report if Adaptations are not supported", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -717,12 +710,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -757,8 +746,8 @@ describe("Manifest - Period", () => { expect((adap2 as { id: string }).id).toBe("12"); }); - it("should not report if an Adaptation has no Representation", async () => { - const mockAdaptation = vi.fn( + it("should not report if an Adaptation has no Representation", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -769,12 +758,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -805,8 +790,8 @@ describe("Manifest - Period", () => { expect(unsupportedAdaptations).toHaveLength(0); }); - it("should set the given start", async () => { - const mockAdaptation = vi.fn( + it("should set the given start", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -817,12 +802,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -850,8 +831,8 @@ describe("Manifest - Period", () => { expect(period.end).toEqual(undefined); }); - it("should set a given duration", async () => { - const mockAdaptation = vi.fn( + it("should set a given duration", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -862,12 +843,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -895,8 +872,8 @@ describe("Manifest - Period", () => { expect(period.end).toEqual(12); }); - it("should infer the end from the start and the duration", async () => { - const mockAdaptation = vi.fn( + it("should infer the end from the start and the duration", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -907,12 +884,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -940,8 +913,8 @@ describe("Manifest - Period", () => { expect(period.end).toEqual(62); }); - it("should return every Adaptations combined with `getAdaptations`", async () => { - const mockAdaptation = vi.fn( + it("should return every Adaptations combined with `getAdaptations`", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -952,12 +925,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -1002,8 +971,8 @@ describe("Manifest - Period", () => { expect(period.getAdaptations()).toContain(period.adaptations.audio?.[0]); }); - it("should return every Adaptations from a given type with `getAdaptationsForType`", async () => { - const mockAdaptation = vi.fn( + it("should return every Adaptations from a given type with `getAdaptationsForType`", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -1014,12 +983,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -1073,8 +1038,8 @@ describe("Manifest - Period", () => { expect(period.getAdaptationsForType("text")).toHaveLength(0); }); - it("should return the first Adaptations with a given Id when calling `getAdaptation`", async () => { - const mockAdaptation = vi.fn( + it("should return the first Adaptations with a given Id when calling `getAdaptation`", () => { + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -1085,12 +1050,8 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text"]); - const Period = (await vi.importActual("../period")).default as typeof IPeriod; const videoAda1 = { type: "video", id: "54", @@ -1143,7 +1104,7 @@ describe("Manifest - Period", () => { }); it("should return undefind if no adaptation has the given Id when calling `getAdaptation`", () => { - const mockAdaptation = vi.fn( + mocks.fakeAdaptation.mockImplementation( (arg: IParsedAdaptation): Adaptation => ({ ...arg, @@ -1154,9 +1115,54 @@ describe("Manifest - Period", () => { }, }) as unknown as Adaptation, ); - vi.doMock("../adaptation", () => ({ - default: mockAdaptation, - SUPPORTED_ADAPTATIONS_TYPE: ["audio", "video", "text"], - })); + mocks.SUPPORTED_ADAPTATIONS_TYPE.push(...["audio", "video", "text"]); + + const videoAda1 = { + type: "video", + id: "54", + representations: [{}], + toVideoTrack() { + return videoAda1; + }, + }; + const videoAda2 = { + type: "video", + id: "55", + representations: [{}], + toVideoTrack() { + return videoAda2; + }, + }; + const videoAda3 = { + type: "video", + id: "55", + representations: [{}], + toVideoTrack() { + return videoAda3; + }, + }; + const video = [videoAda1, videoAda2, videoAda3] as unknown as IParsedAdaptation[]; + + const audioAda1 = { + type: "audio", + id: "56", + representations: [{}], + toAudioTrack() { + return audioAda1; + }, + }; + const audio = [audioAda1] as unknown as IParsedAdaptation[]; + + const args = { + id: "12", + adaptations: { video, audio }, + start: 50, + duration: 12, + }; + const unsupportedAdaptations: Adaptation[] = []; + const codecSupportCache = new CodecSupportCache([]); + const period = new Period(args, [], codecSupportCache); + expect(unsupportedAdaptations).toHaveLength(0); + expect(period.getAdaptation("Oh, comely")).toEqual(undefined); }); }); diff --git a/src/manifest/classes/__tests__/update_periods.test.ts b/src/manifest/classes/__tests__/update_periods.test.ts index 96861cb99b..6903c8a2bd 100644 --- a/src/manifest/classes/__tests__/update_periods.test.ts +++ b/src/manifest/classes/__tests__/update_periods.test.ts @@ -1,9 +1,15 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; import type IPeriod from "../period"; -import type { - replacePeriods as IReplacePeriods, - updatePeriods as IUpatePeriods, -} from "../update_periods"; +import { replacePeriods, updatePeriods } from "../update_periods"; + +const mocks = vi.hoisted(() => { + return { + updatePeriodInPlace: vi.fn(), + }; +}); +vi.mock("../update_period_in_place.ts", () => ({ + default: mocks.updatePeriodInPlace, +})); const MANIFEST_UPDATE_TYPE = { Full: 0, @@ -66,26 +72,22 @@ describe("Manifest - replacePeriods", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + mocks.updatePeriodInPlace.mockReset(); + }); // Case 1 : // // old periods : p1, p2 // new periods : p2 - it("should remove old period", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should remove old period", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [ generateFakePeriod({ id: "p1", start: 0 }), generateFakePeriod({ id: "p2" }), ]; const initialPeriods = oldPeriods.slice(); const newPeriods = [generateFakePeriod({ id: "p2" })]; - const replacePeriods = (await vi.importActual("../update_periods")) - .replacePeriods as typeof IReplacePeriods; const res = replacePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [], @@ -105,8 +107,8 @@ describe("Manifest - replacePeriods", () => { }); expect(oldPeriods.length).toBe(1); expect(oldPeriods[0].id).toBe("p2"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(1); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(1); + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 1, initialPeriods[1], newPeriods[0], @@ -118,21 +120,14 @@ describe("Manifest - replacePeriods", () => { // // old periods : p1 // new periods : p1, p2 - it("should add new period", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should add new period", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [generateFakePeriod({ id: "p2" })]; const initialPeriods = oldPeriods.slice(); const newPeriods = [ generateFakePeriod({ id: "p2" }), generateFakePeriod({ id: "p3" }), ]; - const replacePeriods = (await vi.importActual("../update_periods")) - .replacePeriods as typeof IReplacePeriods; const res = replacePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [newPeriods[1].getMetadataSnapshot()], @@ -153,8 +148,8 @@ describe("Manifest - replacePeriods", () => { expect(oldPeriods.length).toBe(2); expect(oldPeriods[0].id).toBe("p2"); expect(oldPeriods[1].id).toBe("p3"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(1); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(1); + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 1, initialPeriods[0], newPeriods[0], @@ -166,17 +161,10 @@ describe("Manifest - replacePeriods", () => { // // old periods: p1 // new periods: p2 - it("should replace period", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should replace period", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [generateFakePeriod({ id: "p1" })]; const newPeriods = [generateFakePeriod({ id: "p2" })]; - const replacePeriods = (await vi.importActual("../update_periods")) - .replacePeriods as typeof IReplacePeriods; const res = replacePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [newPeriods[0].getMetadataSnapshot()], @@ -185,20 +173,15 @@ describe("Manifest - replacePeriods", () => { }); expect(oldPeriods.length).toBe(1); expect(oldPeriods[0].id).toBe("p2"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(0); + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(0); }); // Case 4 : // // old periods: p0, p1, p2 // new periods: p1, a, b, p2, p3 - it("should handle more complex period replacement", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should handle more complex period replacement", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [ generateFakePeriod({ id: "p0" }), generateFakePeriod({ id: "p1" }), @@ -212,8 +195,6 @@ describe("Manifest - replacePeriods", () => { generateFakePeriod({ id: "p3" }), ]; const initialPeriods = oldPeriods.slice(); - const replacePeriods = (await vi.importActual("../update_periods")) - .replacePeriods as typeof IReplacePeriods; const res = replacePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [ @@ -240,14 +221,14 @@ describe("Manifest - replacePeriods", () => { expect(oldPeriods[2].id).toBe("b"); expect(oldPeriods[3].id).toBe("p2"); expect(oldPeriods[4].id).toBe("p3"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(2); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(2); + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 1, initialPeriods[1], newPeriods[0], 0, ); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 2, initialPeriods[2], newPeriods[3], @@ -259,21 +240,14 @@ describe("Manifest - replacePeriods", () => { // // old periods : p2 // new periods : p1, p2 - it("should add new period before", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should add new period before", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [generateFakePeriod({ id: "p2" })]; const newPeriods = [ generateFakePeriod({ id: "p1" }), generateFakePeriod({ id: "p2" }), ]; const initialPeriods = oldPeriods.slice(); - const replacePeriods = (await vi.importActual("../update_periods")) - .replacePeriods as typeof IReplacePeriods; const res = replacePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [newPeriods[0].getMetadataSnapshot()], @@ -288,8 +262,8 @@ describe("Manifest - replacePeriods", () => { expect(oldPeriods.length).toBe(2); expect(oldPeriods[0].id).toBe("p1"); expect(oldPeriods[1].id).toBe("p2"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(1); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(1); + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 1, initialPeriods[0], newPeriods[1], @@ -301,20 +275,13 @@ describe("Manifest - replacePeriods", () => { // // old periods : p1, p2 // new periods : No periods - it("should remove all periods", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should remove all periods", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [ generateFakePeriod({ id: "p1", start: 0 }), generateFakePeriod({ id: "p2", start: 0 }), ]; - const newPeriods = [] as IPeriod[]; - const replacePeriods = (await vi.importActual("../update_periods")) - .replacePeriods as typeof IReplacePeriods; + const newPeriods: IPeriod[] = []; const res = replacePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [], @@ -325,27 +292,20 @@ describe("Manifest - replacePeriods", () => { updatedPeriods: [], }); expect(oldPeriods.length).toBe(0); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(0); + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(0); }); // Case 7 : // // old periods : No periods // new periods : p1, p2 - it("should add all periods to empty array", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); - const oldPeriods = [] as IPeriod[]; + it("should add all periods to empty array", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); + const oldPeriods: IPeriod[] = []; const newPeriods = [ generateFakePeriod({ id: "p1" }), generateFakePeriod({ id: "p2" }), ]; - const replacePeriods = (await vi.importActual("../update_periods")) - .replacePeriods as typeof IReplacePeriods; const res = replacePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [ @@ -358,7 +318,7 @@ describe("Manifest - replacePeriods", () => { expect(oldPeriods.length).toBe(2); expect(oldPeriods[0].id).toBe("p1"); expect(oldPeriods[1].id).toBe("p2"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(0); + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(0); }); }); @@ -366,18 +326,16 @@ describe("Manifest - updatePeriods", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + mocks.updatePeriodInPlace.mockReset(); + }); // Case 1 : // // old periods : p1, p2 // new periods : p2 - it("should not remove old period", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should not remove old period", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [ generateFakePeriod({ id: "p1", start: 50, end: 60 }), generateFakePeriod({ id: "p2", start: 60 }), @@ -385,8 +343,6 @@ describe("Manifest - updatePeriods", () => { const newPeriods = [generateFakePeriod({ id: "p2", start: 60 })]; const initialPeriods = oldPeriods.slice(); - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; const res = updatePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [], @@ -400,8 +356,8 @@ describe("Manifest - updatePeriods", () => { }); expect(oldPeriods.length).toBe(2); expect(oldPeriods[0].id).toBe("p1"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(1); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(1); + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 1, initialPeriods[1], newPeriods[0], @@ -413,21 +369,14 @@ describe("Manifest - updatePeriods", () => { // // old periods : p1 // new periods : p1, p2 - it("should add new period", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should add new period", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [generateFakePeriod({ id: "p2", start: 60 })]; const newPeriods = [ generateFakePeriod({ id: "p2", start: 60, end: 80 }), generateFakePeriod({ id: "p3", start: 80 }), ]; const initialPeriods = oldPeriods.slice(); - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; const res = updatePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [newPeriods[1].getMetadataSnapshot()], @@ -442,8 +391,8 @@ describe("Manifest - updatePeriods", () => { expect(oldPeriods.length).toBe(2); expect(oldPeriods[0].id).toBe("p2"); expect(oldPeriods[1].id).toBe("p3"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(1); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(1); + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 1, initialPeriods[0], newPeriods[0], @@ -455,17 +404,10 @@ describe("Manifest - updatePeriods", () => { // // old periods: p1 // new periods: p3 - it("should throw when encountering two distant Periods", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should throw when encountering two distant Periods", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [generateFakePeriod({ id: "p1", start: 50, end: 60 })]; const newPeriods = [generateFakePeriod({ id: "p3", start: 70, end: 80 })]; - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; let error: unknown = null; try { @@ -487,20 +429,15 @@ describe("Manifest - updatePeriods", () => { ); expect(oldPeriods.length).toBe(1); expect(oldPeriods[0].id).toBe("p1"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(0); + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(0); }); // Case 4 : // // old periods: p0, p1, p2 // new periods: p1, a, b, p2, p3 - it("should handle more complex period replacement", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should handle more complex period replacement", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [ generateFakePeriod({ id: "p0", start: 50, end: 60 }), generateFakePeriod({ id: "p1", start: 60, end: 69 }), @@ -515,8 +452,6 @@ describe("Manifest - updatePeriods", () => { generateFakePeriod({ id: "p3", start: 80 }), ]; const initialPeriods = oldPeriods.slice(); - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; const res = updatePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [ @@ -544,14 +479,14 @@ describe("Manifest - updatePeriods", () => { expect(oldPeriods[3].id).toBe("b"); expect(oldPeriods[4].id).toBe("p2"); expect(oldPeriods[5].id).toBe("p3"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(2); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(2); + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 1, initialPeriods[1], newPeriods[0], MANIFEST_UPDATE_TYPE.Partial, ); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 2, initialPeriods[3], newPeriods[3], @@ -563,22 +498,14 @@ describe("Manifest - updatePeriods", () => { // // old periods : p2 // new periods : p1, p2 - it("should throw when the first period is not encountered", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should throw when the first period is not encountered", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [generateFakePeriod({ id: "p2", start: 70 })]; const newPeriods = [ generateFakePeriod({ id: "p1", start: 50, end: 70 }), generateFakePeriod({ id: "p2", start: 70 }), ]; - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; - let error: unknown = null; try { updatePeriods(oldPeriods, newPeriods); @@ -599,27 +526,20 @@ describe("Manifest - updatePeriods", () => { ); expect(oldPeriods.length).toBe(1); expect(oldPeriods[0].id).toBe("p2"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(0); + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(0); }); // Case 6 : // // old periods : p1, p2 // new periods : No periods - it("should keep old periods if no new Period is available", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should keep old periods if no new Period is available", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [ generateFakePeriod({ id: "p1" }), generateFakePeriod({ id: "p2" }), ]; - const newPeriods = [] as IPeriod[]; - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; + const newPeriods: IPeriod[] = []; const res = updatePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [], @@ -629,27 +549,20 @@ describe("Manifest - updatePeriods", () => { expect(oldPeriods.length).toBe(2); expect(oldPeriods[0].id).toBe("p1"); expect(oldPeriods[1].id).toBe("p2"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(0); + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(0); }); // Case 7 : // // old periods : No periods // new periods : p1, p2 - it("should set only new Periods if none were available before", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); - const oldPeriods = [] as IPeriod[]; + it("should set only new Periods if none were available before", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); + const oldPeriods: IPeriod[] = []; const newPeriods = [ generateFakePeriod({ id: "p1" }), generateFakePeriod({ id: "p2" }), ]; - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; const res = updatePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [ @@ -662,22 +575,15 @@ describe("Manifest - updatePeriods", () => { expect(oldPeriods.length).toBe(2); expect(oldPeriods[0].id).toBe("p1"); expect(oldPeriods[1].id).toBe("p2"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(0); + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(0); }); // Case 8 : // // old periods : p0, p1 // new periods : p4, p5 - it("should throw if the new periods come strictly after", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; + it("should throw if the new periods come strictly after", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [ generateFakePeriod({ id: "p0", start: 50, end: 60 }), generateFakePeriod({ id: "p1", start: 60, end: 70 }), @@ -705,24 +611,17 @@ describe("Manifest - updatePeriods", () => { expect(oldPeriods.length).toBe(2); expect(oldPeriods[0].id).toBe("p0"); expect(oldPeriods[1].id).toBe("p1"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(0); + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(0); }); // Case 9 : // // old periods: p1 // new periods: p2 - it("should concatenate consecutive periods", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should concatenate consecutive periods", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [generateFakePeriod({ id: "p1", start: 50, end: 60 })]; const newPeriods = [generateFakePeriod({ id: "p2", start: 60, end: 80 })]; - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; const res = updatePeriods(oldPeriods, newPeriods); expect(res).toEqual({ @@ -733,24 +632,17 @@ describe("Manifest - updatePeriods", () => { expect(oldPeriods.length).toBe(2); expect(oldPeriods[0].id).toBe("p1"); expect(oldPeriods[1].id).toBe("p2"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(0); + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(0); }); // Case 10 : // // old periods: p1 // new periods: px - it("should throw when encountering two completely different Periods with the same start", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should throw when encountering two completely different Periods with the same start", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [generateFakePeriod({ id: "p1", start: 50, end: 60 })]; const newPeriods = [generateFakePeriod({ id: "px", start: 50, end: 70 })]; - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; let error: unknown = null; try { @@ -772,20 +664,15 @@ describe("Manifest - updatePeriods", () => { ); expect(oldPeriods.length).toBe(1); expect(oldPeriods[0].id).toBe("p1"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(0); + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(0); }); // Case 11 : // // old periods: p0, p1, p2 // new periods: p1, p2, p3 - it("should handle more complex period replacement", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should handle more complex period replacement", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [ generateFakePeriod({ id: "p0", start: 50, end: 60 }), generateFakePeriod({ id: "p1", start: 60, end: 70 }), @@ -797,8 +684,6 @@ describe("Manifest - updatePeriods", () => { generateFakePeriod({ id: "p3", start: 80 }), ]; const initialPeriods = oldPeriods.slice(); - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; const res = updatePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [newPeriods[2].getMetadataSnapshot()], @@ -820,14 +705,14 @@ describe("Manifest - updatePeriods", () => { expect(oldPeriods[1].id).toBe("p1"); expect(oldPeriods[2].id).toBe("p2"); expect(oldPeriods[3].id).toBe("p3"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(2); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(2); + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 1, initialPeriods[1], newPeriods[0], MANIFEST_UPDATE_TYPE.Partial, ); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 2, initialPeriods[2], newPeriods[1], @@ -839,13 +724,8 @@ describe("Manifest - updatePeriods", () => { // // old periods: p0, p1, p2, p3 // new periods: p1, p3 - it("should handle more complex period replacement", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should handle more complex period replacement", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [ generateFakePeriod({ id: "p0", start: 50, end: 60 }), generateFakePeriod({ id: "p1", start: 60, end: 70 }), @@ -857,8 +737,6 @@ describe("Manifest - updatePeriods", () => { generateFakePeriod({ id: "p3", start: 80 }), ]; const initialPeriods = oldPeriods.slice(); - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; const res = updatePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [], @@ -879,14 +757,14 @@ describe("Manifest - updatePeriods", () => { expect(oldPeriods[0].id).toBe("p0"); expect(oldPeriods[1].id).toBe("p1"); expect(oldPeriods[2].id).toBe("p3"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(2); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(2); + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 1, initialPeriods[1], newPeriods[0], MANIFEST_UPDATE_TYPE.Partial, ); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 2, initialPeriods[3], newPeriods[1], @@ -898,13 +776,8 @@ describe("Manifest - updatePeriods", () => { // // old periods: p0, p1, p2, p3, p4 // new periods: p1, p3 - it("should remove periods not included in the new Periods", async () => { - const fakeUpdatePeriodInPlace = vi.fn(() => { - return fakeUpdatePeriodInPlaceRes; - }); - vi.doMock("../update_period_in_place", () => ({ - default: fakeUpdatePeriodInPlace, - })); + it("should remove periods not included in the new Periods", () => { + mocks.updatePeriodInPlace.mockImplementation(() => fakeUpdatePeriodInPlaceRes); const oldPeriods = [ generateFakePeriod({ id: "p0", start: 50, end: 60 }), generateFakePeriod({ id: "p1", start: 60, end: 70 }), @@ -917,8 +790,6 @@ describe("Manifest - updatePeriods", () => { generateFakePeriod({ id: "p1", start: 60, end: 70 }), generateFakePeriod({ id: "p3", start: 80, end: 90 }), ]; - const updatePeriods = (await vi.importActual("../update_periods")) - .updatePeriods as typeof IUpatePeriods; const res = updatePeriods(oldPeriods, newPeriods); expect(res).toEqual({ addedPeriods: [], @@ -942,14 +813,14 @@ describe("Manifest - updatePeriods", () => { expect(oldPeriods[0].id).toBe("p0"); expect(oldPeriods[1].id).toBe("p1"); expect(oldPeriods[2].id).toBe("p3"); - expect(fakeUpdatePeriodInPlace).toHaveBeenCalledTimes(2); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenCalledTimes(2); + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 1, initialPeriods[1], newPeriods[0], MANIFEST_UPDATE_TYPE.Partial, ); - expect(fakeUpdatePeriodInPlace).toHaveBeenNthCalledWith( + expect(mocks.updatePeriodInPlace).toHaveBeenNthCalledWith( 2, initialPeriods[3], newPeriods[1], diff --git a/src/mse/main_media_source_interface.ts b/src/mse/main_media_source_interface.ts index 87592f795b..c792d9be42 100644 --- a/src/mse/main_media_source_interface.ts +++ b/src/mse/main_media_source_interface.ts @@ -1,5 +1,5 @@ import type { IMediaSource, ISourceBuffer } from "../compat/browser_compatibility_types"; -import { MediaSource_ } from "../compat/browser_compatibility_types"; +import BROWSER_GLOBALS from "../compat/browser_compatibility_types"; import tryToChangeSourceBufferType from "../compat/change_source_buffer_type"; import { onSourceClose, onSourceEnded, onSourceOpen } from "../compat/event_listeners"; import { MediaError, SourceBufferError } from "../errors"; @@ -87,6 +87,7 @@ export default class MainMediaSourceInterface this.sourceBuffers = []; this._canceller = new TaskCanceller(); + const { MediaSource_ } = BROWSER_GLOBALS; if (isNullOrUndefined(MediaSource_)) { throw new MediaError( "MEDIA_SOURCE_NOT_SUPPORTED", diff --git a/src/parsers/manifest/dash/common/__tests__/get_clock_offset.test.ts b/src/parsers/manifest/dash/common/__tests__/get_clock_offset.test.ts index 144c4b415a..6a0cf2b5fd 100644 --- a/src/parsers/manifest/dash/common/__tests__/get_clock_offset.test.ts +++ b/src/parsers/manifest/dash/common/__tests__/get_clock_offset.test.ts @@ -1,47 +1,41 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IGetClockOffset from "../get_clock_offset"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import log from "../../../../../log"; +import getClockOffset from "../get_clock_offset"; + +const logWarn = vi.spyOn(log, "warn").mockImplementation(() => { + /* noop */ +}); describe("DASH Parser - getClockOffset", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + logWarn.mockClear(); + }); - it("should calculate a millisecond offset relatively to the monotonically-raising timestamp", async () => { - const mockWarn = vi.fn(); - vi.doMock("../../../../../log", () => ({ - default: { warn: mockWarn }, - })); - - const getClockOffset = (await vi.importActual("../get_clock_offset")) - .default as typeof IGetClockOffset; + it("should calculate a millisecond offset relatively to the monotonically-raising timestamp", () => { const mockDate = vi .spyOn(performance, "now") .mockReturnValue(Date.parse("2019-03-24T13:00:00Z")); expect(getClockOffset("2019-03-25T12:00:00Z")).toEqual(82800000); - expect(mockWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); mockDate.mockRestore(); }); - it("should return undefined and warn if an invalid date is given", async () => { - const mockWarn = vi.fn(); - vi.doMock("../../../../../log", () => ({ - default: { warn: mockWarn }, - })); - const getClockOffset = (await vi.importActual("../get_clock_offset")) - .default as typeof IGetClockOffset; - + it("should return undefined and warn if an invalid date is given", () => { expect(getClockOffset("2018/412/13")).toEqual(undefined); - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "DASH Parser: Invalid clock received: ", "2018/412/13", ); - mockWarn.mockReset(); + logWarn.mockReset(); expect(getClockOffset("foo")).toEqual(undefined); - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn).toHaveBeenCalledWith("DASH Parser: Invalid clock received: ", "foo"); - mockWarn.mockReset(); + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith("DASH Parser: Invalid clock received: ", "foo"); + logWarn.mockReset(); }); }); diff --git a/src/parsers/manifest/dash/common/__tests__/get_http_utc-timing_url.test.ts b/src/parsers/manifest/dash/common/__tests__/get_http_utc-timing_url.test.ts index 6aea2ef4c6..d3cdb9f7c8 100644 --- a/src/parsers/manifest/dash/common/__tests__/get_http_utc-timing_url.test.ts +++ b/src/parsers/manifest/dash/common/__tests__/get_http_utc-timing_url.test.ts @@ -1,13 +1,13 @@ import { describe, beforeEach, it, expect, vi } from "vitest"; import type { IMPDIntermediateRepresentation } from "../../node_parser_types"; -import type IGetHTTPUTCTimingURL from "../get_http_utc-timing_url"; +import getHTTPUTCTimingURL from "../get_http_utc-timing_url"; describe("DASH Parser - getHTTPUTCTimingURL", () => { beforeEach(() => { vi.resetModules(); }); - it("should return undefined if the given intermediate representation has no UTCTimings element", async () => { + it("should return undefined if the given intermediate representation has no UTCTimings element", () => { const mpdIR: IMPDIntermediateRepresentation = { children: { baseURLs: [], @@ -17,12 +17,10 @@ describe("DASH Parser - getHTTPUTCTimingURL", () => { }, attributes: {}, }; - const getHTTPUTCTimingURL = (await vi.importActual("../get_http_utc-timing_url")) - .default as typeof IGetHTTPUTCTimingURL; expect(getHTTPUTCTimingURL(mpdIR)).toEqual(undefined); }); - it("should return undefined if the given intermediate representation has no http-iso UTCTimings element", async () => { + it("should return undefined if the given intermediate representation has no http-iso UTCTimings element", () => { const mpdIR: IMPDIntermediateRepresentation = { children: { baseURLs: [], @@ -41,12 +39,10 @@ describe("DASH Parser - getHTTPUTCTimingURL", () => { }, attributes: {}, }; - const getHTTPUTCTimingURL = (await vi.importActual("../get_http_utc-timing_url")) - .default as typeof IGetHTTPUTCTimingURL; expect(getHTTPUTCTimingURL(mpdIR)).toEqual(undefined); }); - it("should return undefined if the given intermediate representation has no value for its http-iso UTCTimings element", async () => { + it("should return undefined if the given intermediate representation has no value for its http-iso UTCTimings element", () => { const mpdIR: IMPDIntermediateRepresentation = { children: { baseURLs: [], @@ -67,12 +63,10 @@ describe("DASH Parser - getHTTPUTCTimingURL", () => { }, attributes: {}, }; - const getHTTPUTCTimingURL = (await vi.importActual("../get_http_utc-timing_url")) - .default as typeof IGetHTTPUTCTimingURL; expect(getHTTPUTCTimingURL(mpdIR)).toEqual(undefined); }); - it("should return the value of a single http-iso UTCTimings element", async () => { + it("should return the value of a single http-iso UTCTimings element", () => { const mpdIR: IMPDIntermediateRepresentation = { children: { baseURLs: [], @@ -87,12 +81,10 @@ describe("DASH Parser - getHTTPUTCTimingURL", () => { }, attributes: {}, }; - const getHTTPUTCTimingURL = (await vi.importActual("../get_http_utc-timing_url")) - .default as typeof IGetHTTPUTCTimingURL; expect(getHTTPUTCTimingURL(mpdIR)).toEqual("foobar2000"); }); - it("should return the first value of multiple http-iso UTCTimings elements", async () => { + it("should return the first value of multiple http-iso UTCTimings elements", () => { const mpdIR: IMPDIntermediateRepresentation = { children: { baseURLs: [], @@ -115,12 +107,10 @@ describe("DASH Parser - getHTTPUTCTimingURL", () => { }, attributes: {}, }; - const getHTTPUTCTimingURL = (await vi.importActual("../get_http_utc-timing_url")) - .default as typeof IGetHTTPUTCTimingURL; expect(getHTTPUTCTimingURL(mpdIR)).toEqual("foobar1000"); }); - it("should return the first value of a http-iso UTCTimings element when mixed with other elements", async () => { + it("should return the first value of a http-iso UTCTimings element when mixed with other elements", () => { const mpdIR: IMPDIntermediateRepresentation = { children: { baseURLs: [], @@ -151,8 +141,6 @@ describe("DASH Parser - getHTTPUTCTimingURL", () => { }, attributes: {}, }; - const getHTTPUTCTimingURL = (await vi.importActual("../get_http_utc-timing_url")) - .default as typeof IGetHTTPUTCTimingURL; expect(getHTTPUTCTimingURL(mpdIR)).toEqual("foobar2000"); }); }); diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/ContentProtection.test.ts b/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/ContentProtection.test.ts index 83082d11f0..1aad69eafb 100644 --- a/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/ContentProtection.test.ts +++ b/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/ContentProtection.test.ts @@ -1,14 +1,21 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; import type { ITNode } from "../../../../../../utils/xml-parser"; import { parseXml } from "../../../../../../utils/xml-parser"; -import type IContentProtection from "../ContentProtection"; +import parseContentProtection from "../ContentProtection"; + +const mocks = vi.hoisted(() => { + return { + hexToBytes: vi.fn(), + }; +}); +vi.mock("../../../../../../utils/string_parsing", () => ({ + hexToBytes: mocks.hexToBytes, +})); function testStringAttribute(attributeName: string, variableName?: string): void { const _variableName = variableName ?? attributeName; - it(`should correctly parse a ContentProtection element with a correct ${attributeName} attribute`, async () => { - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IContentProtection; + it(`should correctly parse a ContentProtection element with a correct ${attributeName} attribute`, () => { const element1 = parseXml( ``, )[0] as ITNode; @@ -29,10 +36,11 @@ describe("DASH Node Parsers - ContentProtection", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + mocks.hexToBytes.mockReset(); + }); - it("should correctly parse a ContentProtection element without attributes", async () => { - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IContentProtection; + it("should correctly parse a ContentProtection element without attributes", () => { const element = parseXml("")[0] as ITNode; expect(parseContentProtection(element)).toEqual([ { attributes: {}, children: { cencPssh: [] } }, @@ -43,16 +51,11 @@ describe("DASH Node Parsers - ContentProtection", () => { testStringAttribute("schemeIdUri"); testStringAttribute("value"); - it("should correctly parse a ContentProtection element with a correct cenc:default_KID attribute", async () => { + it("should correctly parse a ContentProtection element with a correct cenc:default_KID attribute", () => { const keyId = new Uint8Array([0, 1, 2, 3]); - const mockHexToBytes = vi.fn().mockImplementation(() => { + mocks.hexToBytes.mockImplementation(() => { return keyId; }); - vi.doMock("../../../../../../utils/string_parsing", () => ({ - hexToBytes: mockHexToBytes, - })); - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IContentProtection; const element1 = parseXml( '', )[0] as ITNode; @@ -61,20 +64,15 @@ describe("DASH Node Parsers - ContentProtection", () => { { attributes: { keyId }, children: { cencPssh: [] } }, [], ]); - expect(mockHexToBytes).toHaveBeenCalledTimes(1); - expect(mockHexToBytes).toHaveBeenCalledWith("deadbeef"); + expect(mocks.hexToBytes).toHaveBeenCalledTimes(1); + expect(mocks.hexToBytes).toHaveBeenCalledWith("deadbeef"); }); - it("should correctly parse a ContentProtection with every attributes", async () => { + it("should correctly parse a ContentProtection with every attributes", () => { const keyId = new Uint8Array([0, 1, 2, 3]); - const mockHexToBytes = vi.fn().mockImplementation(() => { + mocks.hexToBytes.mockImplementation(() => { return keyId; }); - vi.doMock("../../../../../../utils/string_parsing", () => ({ - hexToBytes: mockHexToBytes, - })); - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IContentProtection; const element = parseXml( ` { ]); }); - it("should correctly parse a ContentProtection with cenc:pssh children", async () => { - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IContentProtection; + it("should correctly parse a ContentProtection with cenc:pssh children", () => { const element = parseXml( ` AABBCC @@ -113,16 +109,11 @@ describe("DASH Node Parsers - ContentProtection", () => { ]); }); - it("should correctly parse a ContentProtection with both cenc:pssh children and every attributes", async () => { + it("should correctly parse a ContentProtection with both cenc:pssh children and every attributes", () => { const keyId = new Uint8Array([0, 1, 2, 3]); - const mockHexToBytes = vi.fn().mockImplementation(() => { + mocks.hexToBytes.mockImplementation(() => { return keyId; }); - vi.doMock("../../../../../../utils/string_parsing", () => ({ - hexToBytes: mockHexToBytes, - })); - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IContentProtection; const element = parseXml( ` { ]); }); - it("should return a warning if one of the cenc:pssh is invalid base64", async () => { - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IContentProtection; + it("should return a warning if one of the cenc:pssh is invalid base64", () => { const element = parseXml( ` AA!BCC diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/Initialization.test.ts b/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/Initialization.test.ts index 9104a42976..9a263ff6ef 100644 --- a/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/Initialization.test.ts +++ b/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/Initialization.test.ts @@ -1,101 +1,72 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import log from "../../../../../../log"; import type { ITNode } from "../../../../../../utils/xml-parser"; import { parseXml } from "../../../../../../utils/xml-parser"; -import type IParseInitialization from "../Initialization"; -import type { MPDError as IMPDError } from "../utils"; +import parseInitialization from "../Initialization"; +import { MPDError } from "../utils"; + +const logWarn = vi.spyOn(log, "warn").mockImplementation(() => { + /* noop */ +}); describe("DASH Node Parsers - Initialization", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + logWarn.mockClear(); + }); - it("should correctly parse an element with no known attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IParseInitialization; + it("should correctly parse an element with no known attribute", () => { const element1 = parseXml("")[0] as ITNode; expect(parseInitialization(element1)).toEqual([{}, []]); const element2 = parseXml('')[0] as ITNode; expect(parseInitialization(element2)).toEqual([{}, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with a well-formed `range` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IParseInitialization; + it("should correctly parse an element with a well-formed `range` attribute", () => { const element1 = parseXml('')[0] as ITNode; expect(parseInitialization(element1)).toEqual([{ range: [0, 1] }, []]); const element2 = parseXml('')[0] as ITNode; expect(parseInitialization(element2)).toEqual([{ range: [100, 1000] }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with an incorrect `range` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn").mockImplementation(vi.fn()); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IParseInitialization; - const MPDError = (await vi.importActual("../utils")).MPDError as typeof IMPDError; + it("should correctly parse an element with an incorrect `range` attribute", () => { const element1 = parseXml('')[0] as ITNode; const error1 = new MPDError('`range` property has an unrecognized format "a"'); expect(parseInitialization(element1)).toEqual([{}, [error1]]); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog).toHaveBeenCalledWith(error1.message); + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith(error1.message); const element2 = parseXml('')[0] as ITNode; const error2 = new MPDError('`range` property has an unrecognized format ""'); expect(parseInitialization(element2)).toEqual([{}, [error2]]); - expect(mockLog).toHaveBeenCalledTimes(2); - expect(mockLog).toHaveBeenCalledWith(error2.message); - - mockLog.mockRestore(); + expect(logWarn).toHaveBeenCalledTimes(2); + expect(logWarn).toHaveBeenCalledWith(error2.message); }); - it("should correctly parse an element with a sourceURL attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IParseInitialization; + it("should correctly parse an element with a sourceURL attribute", () => { const element1 = parseXml('')[0] as ITNode; expect(parseInitialization(element1)).toEqual([{ media: "a" }, []]); const element2 = parseXml('')[0] as ITNode; expect(parseInitialization(element2)).toEqual([{ media: "" }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with both a sourceURL and range attributes", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IParseInitialization; + it("should correctly parse an element with both a sourceURL and range attributes", () => { const element1 = parseXml('')[0] as ITNode; expect(parseInitialization(element1)).toEqual([{ media: "a", range: [4, 10] }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); }); diff --git a/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/SegmentURL.test.ts b/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/SegmentURL.test.ts index be4d2a4345..c7d50b0c3c 100644 --- a/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/SegmentURL.test.ts +++ b/src/parsers/manifest/dash/fast-js-parser/node_parsers/__tests__/SegmentURL.test.ts @@ -1,148 +1,101 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import log from "../../../../../../log"; import type { ITNode } from "../../../../../../utils/xml-parser"; import { parseXml } from "../../../../../../utils/xml-parser"; -import type IParseSegmentURL from "../SegmentURL"; -import type { MPDError as IMPDError } from "../utils"; +import parseSegmentURL from "../SegmentURL"; +import { MPDError } from "../utils"; + +const logWarn = vi.spyOn(log, "warn").mockImplementation(() => { + /* noop */ +}); describe("DASH Node Parsers - SegmentURL", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + logWarn.mockClear(); + }); - it("should correctly parse an element with no known attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof IParseSegmentURL; + it("should correctly parse an element with no known attribute", () => { const element1 = parseXml("")[0] as ITNode; expect(parseSegmentURL(element1)).toEqual([{}, []]); const element2 = parseXml('')[0] as ITNode; expect(parseSegmentURL(element2)).toEqual([{}, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with a well-formed `mediaRange` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof IParseSegmentURL; + it("should correctly parse an element with a well-formed `mediaRange` attribute", () => { const element1 = parseXml('')[0] as ITNode; expect(parseSegmentURL(element1)).toEqual([{ mediaRange: [10, 100] }, []]); const element2 = parseXml('')[0] as ITNode; expect(parseSegmentURL(element2)).toEqual([{ mediaRange: [0, 1] }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with an incorrect `mediaRange` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn").mockImplementation(vi.fn()); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof IParseSegmentURL; - const MPDError = (await vi.importActual("../utils")).MPDError as typeof IMPDError; + it("should correctly parse an element with an incorrect `mediaRange` attribute", () => { const element1 = parseXml('')[0] as ITNode; const error1 = new MPDError('`mediaRange` property has an unrecognized format "a"'); expect(parseSegmentURL(element1)).toEqual([{}, [error1]]); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog).toHaveBeenCalledWith(error1.message); + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith(error1.message); const element2 = parseXml('')[0] as ITNode; const error2 = new MPDError('`mediaRange` property has an unrecognized format ""'); expect(parseSegmentURL(element2)).toEqual([{}, [error2]]); - expect(mockLog).toHaveBeenCalledTimes(2); - expect(mockLog).toHaveBeenCalledWith(error2.message); - - mockLog.mockRestore(); + expect(logWarn).toHaveBeenCalledTimes(2); + expect(logWarn).toHaveBeenCalledWith(error2.message); }); - it("should correctly parse an element with a well-formed `indexRange` attribute", async () => { - const log = { - default: { warn: () => null }, - }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof IParseSegmentURL; + it("should correctly parse an element with a well-formed `indexRange` attribute", () => { const element1 = parseXml('')[0] as ITNode; expect(parseSegmentURL(element1)).toEqual([{ indexRange: [0, 100] }, []]); const element2 = parseXml('')[0] as ITNode; expect(parseSegmentURL(element2)).toEqual([{ indexRange: [72, 47] }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with an incorrect `indexRange` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn").mockImplementation(vi.fn()); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof IParseSegmentURL; - const MPDError = (await vi.importActual("../utils")).MPDError as typeof IMPDError; + it("should correctly parse an element with an incorrect `indexRange` attribute", () => { const element1 = parseXml('')[0] as ITNode; const error1 = new MPDError('`indexRange` property has an unrecognized format "a"'); expect(parseSegmentURL(element1)).toEqual([{}, [error1]]); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog).toHaveBeenCalledWith(error1.message); + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith(error1.message); const element2 = parseXml('')[0] as ITNode; const error2 = new MPDError('`indexRange` property has an unrecognized format ""'); expect(parseSegmentURL(element2)).toEqual([{}, [error2]]); - expect(mockLog).toHaveBeenCalledTimes(2); - expect(mockLog).toHaveBeenCalledWith(error2.message); - - mockLog.mockRestore(); + expect(logWarn).toHaveBeenCalledTimes(2); + expect(logWarn).toHaveBeenCalledWith(error2.message); }); - it("should correctly parse an element with a media attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof IParseSegmentURL; + it("should correctly parse an element with a media attribute", () => { const element1 = parseXml('')[0] as ITNode; expect(parseSegmentURL(element1)).toEqual([{ media: "a" }, []]); const element2 = parseXml('')[0] as ITNode; expect(parseSegmentURL(element2)).toEqual([{ media: "" }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with a index attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof IParseSegmentURL; + it("should correctly parse an element with a index attribute", () => { const element1 = parseXml('')[0] as ITNode; expect(parseSegmentURL(element1)).toEqual([{ index: "a" }, []]); const element2 = parseXml('')[0] as ITNode; expect(parseSegmentURL(element2)).toEqual([{ index: "" }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); }); diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/AdaptationSet.ts b/src/parsers/manifest/dash/native-parser/node_parsers/AdaptationSet.ts index 09ddfe0811..8513606bee 100644 --- a/src/parsers/manifest/dash/native-parser/node_parsers/AdaptationSet.ts +++ b/src/parsers/manifest/dash/native-parser/node_parsers/AdaptationSet.ts @@ -198,6 +198,9 @@ function parseAdaptationSetAttributes( const warnings: Error[] = []; const parseValue = ValueParser(parsedAdaptation, warnings); + if (isNullOrUndefined(root.attributes)) { + return [parsedAdaptation, warnings]; + } for (let i = 0; i < root.attributes.length; i++) { const attribute = root.attributes[i]; diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/ContentProtection.test.ts b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/ContentProtection.test.ts index 740f12d3ba..c5b9e5bf73 100644 --- a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/ContentProtection.test.ts +++ b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/ContentProtection.test.ts @@ -1,12 +1,19 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IParseContentProtection from "../ContentProtection"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import parseContentProtection from "../ContentProtection"; + +const mocks = vi.hoisted(() => { + return { + hexToBytes: vi.fn(), + }; +}); +vi.mock("../../../../../../utils/string_parsing", () => ({ + hexToBytes: mocks.hexToBytes, +})); function testStringAttribute(attributeName: string, variableName?: string): void { const _variableName = variableName ?? attributeName; - it(`should correctly parse a ContentProtection element with a correct ${attributeName} attribute`, async () => { - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; + it(`should correctly parse a ContentProtection element with a correct ${attributeName} attribute`, () => { const element1 = new DOMParser().parseFromString( ``, "text/xml", @@ -31,10 +38,11 @@ describe("DASH Node Parsers - ContentProtection", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + mocks.hexToBytes.mockReset(); + }); - it("should correctly parse a ContentProtection element without attributes", async () => { - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; + it("should correctly parse a ContentProtection element without attributes", () => { const element = new DOMParser().parseFromString("", "text/xml") .childNodes[0] as Element; expect(parseContentProtection(element)).toEqual([ @@ -46,16 +54,11 @@ describe("DASH Node Parsers - ContentProtection", () => { testStringAttribute("schemeIdUri"); testStringAttribute("value"); - it("should correctly parse a ContentProtection element with a correct cenc:default_KID attribute", async () => { + it("should correctly parse a ContentProtection element with a correct cenc:default_KID attribute", () => { const keyId = new Uint8Array([0, 1, 2, 3]); - const mockHexToBytes = vi.fn().mockImplementation(() => { + mocks.hexToBytes.mockImplementation(() => { return keyId; }); - vi.doMock("../../../../../../utils/string_parsing", () => ({ - hexToBytes: mockHexToBytes, - })); - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; const element1 = new DOMParser() .parseFromString( ` @@ -77,20 +80,15 @@ describe("DASH Node Parsers - ContentProtection", () => { { attributes: { keyId }, children: { cencPssh: [] } }, [], ]); - expect(mockHexToBytes).toHaveBeenCalledTimes(1); - expect(mockHexToBytes).toHaveBeenCalledWith("deadbeef"); + expect(mocks.hexToBytes).toHaveBeenCalledTimes(1); + expect(mocks.hexToBytes).toHaveBeenCalledWith("deadbeef"); }); - it("should correctly parse a ContentProtection with every attributes", async () => { + it("should correctly parse a ContentProtection with every attributes", () => { const keyId = new Uint8Array([0, 1, 2, 3]); - const mockHexToBytes = vi.fn().mockImplementation(() => { + mocks.hexToBytes.mockImplementation(() => { return keyId; }); - vi.doMock("../../../../../../utils/string_parsing", () => ({ - hexToBytes: mockHexToBytes, - })); - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; const element = new DOMParser() .parseFromString( ` @@ -120,9 +118,7 @@ describe("DASH Node Parsers - ContentProtection", () => { ]); }); - it("should correctly parse a ContentProtection with cenc:pssh children", async () => { - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; + it("should correctly parse a ContentProtection with cenc:pssh children", () => { const element = new DOMParser() .parseFromString( ` @@ -153,16 +149,11 @@ describe("DASH Node Parsers - ContentProtection", () => { ]); }); - it("should correctly parse a ContentProtection with both cenc:pssh children and every attributes", async () => { + it("should correctly parse a ContentProtection with both cenc:pssh children and every attributes", () => { const keyId = new Uint8Array([0, 1, 2, 3]); - const mockHexToBytes = vi.fn().mockImplementation(() => { + mocks.hexToBytes.mockImplementation(() => { return keyId; }); - vi.doMock("../../../../../../utils/string_parsing", () => ({ - hexToBytes: mockHexToBytes, - })); - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; const element = new DOMParser() .parseFromString( ` @@ -197,9 +188,7 @@ describe("DASH Node Parsers - ContentProtection", () => { ]); }); - it("should return a warning if one of the cenc:pssh is invalid base64", async () => { - const parseContentProtection = (await vi.importActual("../ContentProtection")) - .default as typeof IParseContentProtection; + it("should return a warning if one of the cenc:pssh is invalid base64", () => { const element = new DOMParser() .parseFromString( ` diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/Initialization.test.ts b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/Initialization.test.ts index 252e395494..7381803fc4 100644 --- a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/Initialization.test.ts +++ b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/Initialization.test.ts @@ -1,19 +1,21 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IInitialization from "../Initialization"; -import type { MPDError as IMPDError } from "../utils"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import log from "../../../../../../log"; +import parseInitialization from "../Initialization"; +import { MPDError } from "../utils"; + +const logWarn = vi.spyOn(log, "warn").mockImplementation(() => { + /* noop */ +}); describe("DASH Node Parsers - Initialization", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + logWarn.mockClear(); + }); - it("should correctly parse an element with no known attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IInitialization; + it("should correctly parse an element with no known attribute", () => { const element1 = new DOMParser().parseFromString("", "text/xml") .childNodes[0] as Element; expect(parseInitialization(element1)).toEqual([{}, []]); @@ -22,17 +24,10 @@ describe("DASH Node Parsers - Initialization", () => { .childNodes[0] as Element; expect(parseInitialization(element2)).toEqual([{}, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with a well-formed `range` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IInitialization; + it("should correctly parse an element with a well-formed `range` attribute", () => { const element1 = new DOMParser().parseFromString('', "text/xml") .childNodes[0] as Element; expect(parseInitialization(element1)).toEqual([{ range: [0, 1] }, []]); @@ -43,44 +38,28 @@ describe("DASH Node Parsers - Initialization", () => { ).childNodes[0] as Element; expect(parseInitialization(element2)).toEqual([{ range: [100, 1000] }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with an incorrect `range` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn").mockImplementation(vi.fn()); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IInitialization; - const MPDError = (await vi.importActual("../utils")).MPDError as typeof IMPDError; + it("should correctly parse an element with an incorrect `range` attribute", () => { const element1 = new DOMParser().parseFromString('', "text/xml") .childNodes[0] as Element; const error1 = new MPDError('`range` property has an unrecognized format "a"'); expect(parseInitialization(element1)).toEqual([{}, [error1]]); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog).toHaveBeenCalledWith(error1.message); + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith(error1.message); const element2 = new DOMParser().parseFromString('', "text/xml") .childNodes[0] as Element; const error2 = new MPDError('`range` property has an unrecognized format ""'); expect(parseInitialization(element2)).toEqual([{}, [error2]]); - expect(mockLog).toHaveBeenCalledTimes(2); - expect(mockLog).toHaveBeenCalledWith(error2.message); - - mockLog.mockRestore(); + expect(logWarn).toHaveBeenCalledTimes(2); + expect(logWarn).toHaveBeenCalledWith(error2.message); }); - it("should correctly parse an element with a sourceURL attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IInitialization; + it("should correctly parse an element with a sourceURL attribute", () => { const element1 = new DOMParser().parseFromString('', "text/xml") .childNodes[0] as Element; expect(parseInitialization(element1)).toEqual([{ media: "a" }, []]); @@ -89,24 +68,16 @@ describe("DASH Node Parsers - Initialization", () => { .childNodes[0] as Element; expect(parseInitialization(element2)).toEqual([{ media: "" }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with both a sourceURL and range attributes", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseInitialization = (await vi.importActual("../Initialization")) - .default as typeof IInitialization; + it("should correctly parse an element with both a sourceURL and range attributes", () => { const element1 = new DOMParser().parseFromString( '', "text/xml", ).childNodes[0] as Element; expect(parseInitialization(element1)).toEqual([{ media: "a", range: [4, 10] }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); }); diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentTimeline.test.ts b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentTimeline.test.ts index 10a2a4b687..2cbb1cbd5a 100644 --- a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentTimeline.test.ts +++ b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentTimeline.test.ts @@ -1,34 +1,28 @@ import { describe, beforeEach, it, expect, vi } from "vitest"; -import type SegmentTimelineParser from "../SegmentTimeline"; +import createSegmentTimelineParser from "../SegmentTimeline"; describe("DASH Node parsers - SegmentTimeline", () => { beforeEach(() => { vi.resetModules(); }); - it("should return a function to parse lazily the timeline", async () => { - const parseSegmentTimeline = (await vi.importActual("../SegmentTimeline")) - .default as typeof SegmentTimelineParser; - + it("should return a function to parse lazily the timeline", () => { const element = new DOMParser().parseFromString("", "text/xml") .childNodes[0] as Element; const mockGetElementsByTagName = vi.spyOn(element, "getElementsByTagName"); - const timeline = parseSegmentTimeline(element); + const timeline = createSegmentTimelineParser(element); expect(typeof timeline).toEqual("function"); expect(timeline.length).toEqual(0); expect(mockGetElementsByTagName).not.toHaveBeenCalled(); mockGetElementsByTagName.mockReset(); }); - it("should return an empty HTMLCollection if no S element is present", async () => { - const parseSegmentTimeline = (await vi.importActual("../SegmentTimeline")) - .default as typeof SegmentTimelineParser; - + it("should return an empty HTMLCollection if no S element is present", () => { const element = new DOMParser().parseFromString("", "text/xml") .childNodes[0] as Element; const mockGetElementsByTagName = vi.spyOn(element, "getElementsByTagName"); - const timeline = parseSegmentTimeline(element); + const timeline = createSegmentTimelineParser(element); const res = timeline(); expect(res).toBeInstanceOf(HTMLCollection); expect(res).toHaveLength(0); @@ -37,17 +31,18 @@ describe("DASH Node parsers - SegmentTimeline", () => { mockGetElementsByTagName.mockReset(); }); - it("should return an empty HTMLCollection for an Invalid XML", async () => { - const parseSegmentTimeline = (await vi.importActual("../SegmentTimeline")) - .default as typeof SegmentTimelineParser; - - const element = new DOMParser().parseFromString( - "", - "text/xml", - ).childNodes[0] as Element; - const mockGetElementsByTagName = vi.spyOn(element, "getElementsByTagName"); + it("should return an empty HTMLCollection for an Invalid XML", () => { + let element: Element; + let mockGetElementsByTagName; + try { + element = new DOMParser().parseFromString("aethtrs", "text/xml") + .childNodes[0] as Element; + mockGetElementsByTagName = vi.spyOn(element, "getElementsByTagName"); + } catch (_err) { + return; + } - const timeline = parseSegmentTimeline(element); + const timeline = createSegmentTimelineParser(element); const res = timeline(); expect(res).toBeInstanceOf(HTMLCollection); expect(res).toHaveLength(0); @@ -56,10 +51,7 @@ describe("DASH Node parsers - SegmentTimeline", () => { mockGetElementsByTagName.mockReset(); }); - it("should parse S elements only when called for the first time", async () => { - const parseSegmentTimeline = (await vi.importActual("../SegmentTimeline")) - .default as typeof SegmentTimelineParser; - + it("should parse S elements only when called for the first time", () => { const sElement1 = new DOMParser().parseFromString("1", "text/xml") .childNodes[0] as Element; const sElement2 = new DOMParser().parseFromString("2", "text/xml") @@ -79,7 +71,7 @@ describe("DASH Node parsers - SegmentTimeline", () => { element.appendChild(sElement2); const mockGetElementsByTagName = vi.spyOn(element, "getElementsByTagName"); - const timeline = parseSegmentTimeline(element); + const timeline = createSegmentTimelineParser(element); const res1 = timeline(); expect(res1).toBeInstanceOf(HTMLCollection); expect(res1).toHaveLength(2); diff --git a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentURL.test.ts b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentURL.test.ts index c9d00d89c7..546423e353 100644 --- a/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentURL.test.ts +++ b/src/parsers/manifest/dash/native-parser/node_parsers/__tests__/SegmentURL.test.ts @@ -1,19 +1,21 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type ISegmentUrl from "../SegmentURL"; -import type { MPDError as IMPDError } from "../utils"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import log from "../../../../../../log"; +import parseSegmentURL from "../SegmentURL"; +import { MPDError } from "../utils"; + +const logWarn = vi.spyOn(log, "warn").mockImplementation(() => { + /* noop */ +}); describe("DASH Node Parsers - SegmentURL", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + logWarn.mockClear(); + }); - it("should correctly parse an element with no known attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; + it("should correctly parse an element with no known attribute", () => { const element1 = new DOMParser().parseFromString("", "text/xml") .childNodes[0] as Element; expect(parseSegmentURL(element1)).toEqual([{}, []]); @@ -22,17 +24,10 @@ describe("DASH Node Parsers - SegmentURL", () => { .childNodes[0] as Element; expect(parseSegmentURL(element2)).toEqual([{}, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with a well-formed `mediaRange` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; + it("should correctly parse an element with a well-formed `mediaRange` attribute", () => { const element1 = new DOMParser().parseFromString( '', "text/xml", @@ -45,46 +40,28 @@ describe("DASH Node Parsers - SegmentURL", () => { ).childNodes[0] as Element; expect(parseSegmentURL(element2)).toEqual([{ mediaRange: [0, 1] }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with an incorrect `mediaRange` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn").mockImplementation(vi.fn()); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; - const MPDError = (await vi.importActual("../utils")).MPDError as typeof IMPDError; + it("should correctly parse an element with an incorrect `mediaRange` attribute", () => { const element1 = new DOMParser().parseFromString('', "text/xml") .childNodes[0] as Element; const error1 = new MPDError('`mediaRange` property has an unrecognized format "a"'); expect(parseSegmentURL(element1)).toEqual([{}, [error1]]); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog).toHaveBeenCalledWith(error1.message); + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith(error1.message); const element2 = new DOMParser().parseFromString('', "text/xml") .childNodes[0] as Element; const error2 = new MPDError('`mediaRange` property has an unrecognized format ""'); expect(parseSegmentURL(element2)).toEqual([{}, [error2]]); - expect(mockLog).toHaveBeenCalledTimes(2); - expect(mockLog).toHaveBeenCalledWith(error2.message); - - mockLog.mockRestore(); + expect(logWarn).toHaveBeenCalledTimes(2); + expect(logWarn).toHaveBeenCalledWith(error2.message); }); - it("should correctly parse an element with a well-formed `indexRange` attribute", async () => { - const log = { - default: { warn: () => null }, - }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; + it("should correctly parse an element with a well-formed `indexRange` attribute", () => { const element1 = new DOMParser().parseFromString( '', "text/xml", @@ -97,44 +74,28 @@ describe("DASH Node Parsers - SegmentURL", () => { ).childNodes[0] as Element; expect(parseSegmentURL(element2)).toEqual([{ indexRange: [72, 47] }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with an incorrect `indexRange` attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn").mockImplementation(vi.fn()); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; - const MPDError = (await vi.importActual("../utils")).MPDError as typeof IMPDError; + it("should correctly parse an element with an incorrect `indexRange` attribute", () => { const element1 = new DOMParser().parseFromString('', "text/xml") .childNodes[0] as Element; const error1 = new MPDError('`indexRange` property has an unrecognized format "a"'); expect(parseSegmentURL(element1)).toEqual([{}, [error1]]); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog).toHaveBeenCalledWith(error1.message); + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith(error1.message); const element2 = new DOMParser().parseFromString('', "text/xml") .childNodes[0] as Element; const error2 = new MPDError('`indexRange` property has an unrecognized format ""'); expect(parseSegmentURL(element2)).toEqual([{}, [error2]]); - expect(mockLog).toHaveBeenCalledTimes(2); - expect(mockLog).toHaveBeenCalledWith(error2.message); - - mockLog.mockRestore(); + expect(logWarn).toHaveBeenCalledTimes(2); + expect(logWarn).toHaveBeenCalledWith(error2.message); }); - it("should correctly parse an element with a media attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; + it("should correctly parse an element with a media attribute", () => { const element1 = new DOMParser().parseFromString('', "text/xml") .childNodes[0] as Element; expect(parseSegmentURL(element1)).toEqual([{ media: "a" }, []]); @@ -143,17 +104,10 @@ describe("DASH Node Parsers - SegmentURL", () => { .childNodes[0] as Element; expect(parseSegmentURL(element2)).toEqual([{ media: "" }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); - it("should correctly parse an element with a index attribute", async () => { - const log = { default: { warn: () => null } }; - vi.doMock("../../../../../../log", () => log); - const mockLog = vi.spyOn(log.default, "warn"); - - const parseSegmentURL = (await vi.importActual("../SegmentURL")) - .default as typeof ISegmentUrl; + it("should correctly parse an element with a index attribute", () => { const element1 = new DOMParser().parseFromString('', "text/xml") .childNodes[0] as Element; expect(parseSegmentURL(element1)).toEqual([{ index: "a" }, []]); @@ -162,7 +116,6 @@ describe("DASH Node Parsers - SegmentURL", () => { .childNodes[0] as Element; expect(parseSegmentURL(element2)).toEqual([{ index: "" }, []]); - expect(mockLog).not.toHaveBeenCalled(); - mockLog.mockRestore(); + expect(logWarn).not.toHaveBeenCalled(); }); }); diff --git a/src/parsers/manifest/utils/__tests__/update_segment_timeline.test.ts b/src/parsers/manifest/utils/__tests__/update_segment_timeline.test.ts index 3a7ac7c6aa..5c5906068b 100644 --- a/src/parsers/manifest/utils/__tests__/update_segment_timeline.test.ts +++ b/src/parsers/manifest/utils/__tests__/update_segment_timeline.test.ts @@ -1,58 +1,50 @@ -import type { MockInstance } from "vitest"; import { describe, beforeEach, afterEach, it, expect, vi } from "vitest"; +import log from "../../../../log"; import type { IIndexSegment } from "../index_helpers"; -import type IUpdateSegmentTimeline from "../update_segment_timeline"; +import updateSegmentTimeline from "../update_segment_timeline"; + +const logWarn = vi.spyOn(log, "warn").mockImplementation(() => { + /* noop */ +}); describe("Manifest Parsers utils - updateSegmentTimeline", () => { - let mockLogWarn: MockInstance | undefined; - let updateSegmentTimeline: - | ((a: IIndexSegment[], b: IIndexSegment[]) => boolean) - | undefined; - beforeEach(async () => { + beforeEach(() => { vi.resetModules(); - - mockLogWarn = vi.fn(); - vi.doMock("../../../../log", () => ({ - default: { - warn: mockLogWarn, - }, - })); - updateSegmentTimeline = (await vi.importActual("../update_segment_timeline")) - .default as typeof IUpdateSegmentTimeline; }); afterEach(() => { vi.resetModules(); vi.resetAllMocks(); + logWarn.mockClear(); }); it("should just replace with the new timeline if the old was empty", () => { const oldTimeline: IIndexSegment[] = []; const newTimeline1 = [{ start: 0, duration: 1000, repeatCount: 10 }]; const newTimeline2: IIndexSegment[] = []; - expect(updateSegmentTimeline?.(oldTimeline, newTimeline1)).toEqual(true); + expect(updateSegmentTimeline(oldTimeline, newTimeline1)).toEqual(true); expect(oldTimeline).toEqual(newTimeline1); oldTimeline.length = 0; // reset - updateSegmentTimeline?.(oldTimeline, newTimeline2); + updateSegmentTimeline(oldTimeline, newTimeline2); expect(oldTimeline).toEqual(newTimeline2); - expect(mockLogWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should not do anything if the new timeline is empty", () => { const oldTimeline = [{ start: 0, duration: 1000, repeatCount: 10 }]; const newTimeline: IIndexSegment[] = []; const oldTimelineCloned = oldTimeline.slice(); - expect(updateSegmentTimeline?.(oldTimeline, newTimeline)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline, newTimeline)).toEqual(false); expect(oldTimeline).toEqual(oldTimelineCloned); - expect(mockLogWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should not do anything if the timelines are equal", () => { const oldTimeline1 = [{ start: 0, duration: 1000, repeatCount: 10 }]; const newTimeline1 = [{ start: 0, duration: 1000, repeatCount: 10 }]; const oldTimeline1Cloned = oldTimeline1.slice(); - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).toEqual(false); expect(oldTimeline1).toEqual(oldTimeline1Cloned); const oldTimeline2 = [ @@ -66,9 +58,9 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 12000, duration: 1000, repeatCount: 1 }, ]; const oldTimeline2Cloned = oldTimeline2.slice(); - expect(updateSegmentTimeline?.(oldTimeline2, newTimeline2)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline2, newTimeline2)).toEqual(false); expect(oldTimeline2).toEqual(oldTimeline2Cloned); - expect(mockLogWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should throw if the new timeline begin long after the old one", () => { @@ -85,7 +77,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { let err: unknown = null; try { - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).not.toHaveReturned(); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).not.toHaveReturned(); } catch (e) { err = e; } @@ -102,7 +94,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { "MANIFEST_UPDATE_ERROR: Cannot perform partial update: not enough data", ); expect(oldTimeline1).toEqual(oldTimeline1Cloned); - expect(mockLogWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should merge consecutive timelines", () => { @@ -117,9 +109,9 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { ]; const oldTimeline1Cloned = oldTimeline1.slice(); const newTimeline1Cloned = newTimeline1.slice(); - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).toEqual(false); expect(oldTimeline1).toEqual([...oldTimeline1Cloned, ...newTimeline1Cloned]); - expect(mockLogWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); // With repeats @@ -134,9 +126,9 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { ]; const oldTimeline2Cloned = oldTimeline2.slice(); const newTimeline2Cloned = newTimeline2.slice(); - expect(updateSegmentTimeline?.(oldTimeline2, newTimeline2)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline2, newTimeline2)).toEqual(false); expect(oldTimeline2).toEqual([...oldTimeline2Cloned, ...newTimeline2Cloned]); - expect(mockLogWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should merge consecutive timelines with a repeatCount set to -1 for the old timeline", () => { @@ -149,7 +141,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 24000, duration: 1100, repeatCount: 0 }, { start: 25100, duration: 1000, repeatCount: 1 }, ]; - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).toEqual(false); expect(oldTimeline1).toEqual([ { start: 0, duration: 500, repeatCount: 20 }, { start: 11000, duration: 1000, repeatCount: 0 }, @@ -167,7 +159,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 24000, duration: 1100, repeatCount: 0 }, { start: 25100, duration: 1000, repeatCount: 1 }, ]; - expect(updateSegmentTimeline?.(oldTimeline2, newTimeline2)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline2, newTimeline2)).toEqual(false); expect(oldTimeline2).toEqual([ { start: 0, duration: 500, repeatCount: 20 }, { start: 11000, duration: 1000, repeatCount: 8 }, @@ -175,7 +167,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 24000, duration: 1100, repeatCount: 0 }, { start: 25100, duration: 1000, repeatCount: 1 }, ]); - expect(mockLogWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should merge perfectly overlapping timelines without repeatCounts", () => { @@ -190,7 +182,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 2500, duration: 500, repeatCount: 0 }, { start: 3000, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).toEqual(false); expect(oldTimeline1).toEqual([ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 0 }, @@ -198,7 +190,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 2500, duration: 500, repeatCount: 0 }, { start: 3000, duration: 5000, repeatCount: 0 }, ]); - expect(mockLogWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should merge perfectly overlapping timelines with repeatCounts", () => { @@ -213,7 +205,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).toEqual(false); expect(oldTimeline1).toEqual([ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 21 }, @@ -221,7 +213,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]); - expect(mockLogWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); const oldTimeline2 = [ { start: 1000, duration: 500, repeatCount: 21 }, @@ -233,7 +225,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline2, newTimeline2)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline2, newTimeline2)).toEqual(false); expect(oldTimeline2).toEqual([ { start: 1000, duration: 500, repeatCount: 21 }, { start: 12000, duration: 1000, repeatCount: 0 }, @@ -251,14 +243,14 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline3, newTimeline3)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline3, newTimeline3)).toEqual(false); expect(oldTimeline3).toEqual([ { start: 1000, duration: 500, repeatCount: -1 }, { start: 12000, duration: 1000, repeatCount: 0 }, { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]); - expect(mockLogWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it('should merge even if there are "holes" in the old timeline', () => { @@ -273,7 +265,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).toEqual(false); expect(oldTimeline1).toEqual([ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 0 }, @@ -294,7 +286,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline2, newTimeline2)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline2, newTimeline2)).toEqual(false); expect(oldTimeline2).toEqual([ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 3 }, @@ -304,7 +296,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 20000, duration: 5000, repeatCount: 0 }, ]); - expect(mockLogWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should handle cases where the new timeline's start cannot be reached with the old timeline's repeatCount ", () => { @@ -319,7 +311,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13700, duration: 7000, repeatCount: 0 }, { start: 20700, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).toEqual(false); expect(oldTimeline1).toEqual([ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 2 }, @@ -328,11 +320,11 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13700, duration: 7000, repeatCount: 0 }, { start: 20700, duration: 5000, repeatCount: 0 }, ]); - expect(mockLogWarn).toHaveBeenCalledTimes(1); - expect(mockLogWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "RepresentationIndex: Manifest update removed previous segments", ); - mockLogWarn?.mockClear(); + logWarn?.mockClear(); const oldTimeline2 = [ { start: 0, duration: 1000, repeatCount: 0 }, @@ -344,7 +336,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13700, duration: 7000, repeatCount: 0 }, { start: 20700, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline2, newTimeline2)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline2, newTimeline2)).toEqual(false); expect(oldTimeline2).toEqual([ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 2 }, @@ -353,25 +345,25 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13700, duration: 7000, repeatCount: 0 }, { start: 20700, duration: 5000, repeatCount: 0 }, ]); - expect(mockLogWarn).toHaveBeenCalledTimes(1); - expect(mockLogWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "RepresentationIndex: Manifest update removed previous segments", ); - mockLogWarn?.mockClear(); + logWarn?.mockClear(); const oldTimeline3 = [ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 21 }, ]; const newTimeline3 = [{ start: 2700, duration: 500, repeatCount: 19 }]; - expect(updateSegmentTimeline?.(oldTimeline3, newTimeline3)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline3, newTimeline3)).toEqual(false); expect(oldTimeline3).toEqual([ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 2 }, { start: 2700, duration: 500, repeatCount: 19 }, ]); - expect(mockLogWarn).toHaveBeenCalledTimes(1); - expect(mockLogWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "RepresentationIndex: Manifest update removed previous segments", ); }); @@ -388,7 +380,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).toEqual(false); expect(oldTimeline1).toEqual([ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 1 }, @@ -397,11 +389,11 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]); - expect(mockLogWarn).toHaveBeenCalledTimes(1); - expect(mockLogWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "RepresentationIndex: Manifest update removed previous segments", ); - mockLogWarn?.mockClear(); + logWarn?.mockClear(); const oldTimeline2 = [ { start: 0, duration: 1000, repeatCount: 0 }, @@ -413,7 +405,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline2, newTimeline2)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline2, newTimeline2)).toEqual(false); expect(oldTimeline2).toEqual([ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 1 }, @@ -422,21 +414,21 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]); - expect(mockLogWarn).toHaveBeenCalledTimes(1); - expect(mockLogWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "RepresentationIndex: Manifest update removed previous segments", ); - mockLogWarn?.mockClear(); + logWarn?.mockClear(); const oldTimeline3 = [{ start: 1000, duration: 500, repeatCount: 21 }]; const newTimeline3 = [{ start: 2000, duration: 1000, repeatCount: 9 }]; - expect(updateSegmentTimeline?.(oldTimeline3, newTimeline3)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline3, newTimeline3)).toEqual(false); expect(oldTimeline3).toEqual([ { start: 1000, duration: 500, repeatCount: 1 }, { start: 2000, duration: 1000, repeatCount: 9 }, ]); - expect(mockLogWarn).toHaveBeenCalledTimes(1); - expect(mockLogWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "RepresentationIndex: Manifest update removed previous segments", ); }); @@ -455,7 +447,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).toEqual(true); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).toEqual(true); expect(oldTimeline1).toEqual([ { start: 2000, duration: 1000, repeatCount: 0 }, { start: 3000, duration: 9000, repeatCount: 0 }, @@ -463,8 +455,8 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]); - expect(mockLogWarn).toHaveBeenCalledTimes(1); - expect(mockLogWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "RepresentationIndex: Manifest update removed all previous segments", ); }); @@ -475,7 +467,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 1000, duration: 500, repeatCount: 21 }, ]; const newTimeline1 = [{ start: 1000, duration: 500, repeatCount: 51 }]; - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).toEqual(false); expect(oldTimeline1).toEqual([ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 51 }, @@ -483,7 +475,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { const oldTimeline2 = [{ start: 1000, duration: 500, repeatCount: 64 }]; const newTimeline2 = [{ start: 1000, duration: 500, repeatCount: 72 }]; - expect(updateSegmentTimeline?.(oldTimeline2, newTimeline2)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline2, newTimeline2)).toEqual(false); expect(oldTimeline2).toEqual([{ start: 1000, duration: 500, repeatCount: 72 }]); const oldTimeline3 = [{ start: 1000, duration: 500, repeatCount: 64 }]; @@ -491,13 +483,13 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 1000, duration: 500, repeatCount: 72 }, { start: 37500, duration: 1000, repeatCount: 5 }, ]; - expect(updateSegmentTimeline?.(oldTimeline3, newTimeline3)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline3, newTimeline3)).toEqual(false); expect(oldTimeline3).toEqual([ { start: 1000, duration: 500, repeatCount: 72 }, { start: 37500, duration: 1000, repeatCount: 5 }, ]); - expect(mockLogWarn).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should handle when the newer timeline has more depth than the older one", () => { @@ -512,7 +504,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).toEqual(true); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).toEqual(true); expect(oldTimeline1).toEqual([ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 21 }, @@ -521,12 +513,12 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 20000, duration: 5000, repeatCount: 0 }, ]); - expect(mockLogWarn).toHaveBeenCalledTimes(1); - expect(mockLogWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( 'RepresentationIndex: The new index is "bigger" than the previous one', ); - mockLogWarn?.mockClear(); + logWarn?.mockClear(); const oldTimeline2 = [ { start: 1000, duration: 500, repeatCount: 21 }, @@ -539,7 +531,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 13000, duration: 7000, repeatCount: 0 }, { start: 20000, duration: 5000, repeatCount: 0 }, ]; - expect(updateSegmentTimeline?.(oldTimeline2, newTimeline2)).toEqual(true); + expect(updateSegmentTimeline(oldTimeline2, newTimeline2)).toEqual(true); expect(oldTimeline2).toEqual([ { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 21 }, @@ -548,8 +540,8 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 20000, duration: 5000, repeatCount: 0 }, ]); - expect(mockLogWarn).toHaveBeenCalledTimes(1); - expect(mockLogWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( 'RepresentationIndex: The new index is "bigger" than the previous one', ); }); @@ -565,7 +557,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 21 }, ]; - expect(updateSegmentTimeline?.(oldTimeline1, newTimeline1)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline1, newTimeline1)).toEqual(false); expect(oldTimeline1).toEqual([ { start: 1000, duration: 500, repeatCount: 21 }, { start: 12000, duration: 1000, repeatCount: 0 }, @@ -573,12 +565,12 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 20000, duration: 5000, repeatCount: 0 }, ]); - expect(mockLogWarn).toHaveBeenCalledTimes(1); - expect(mockLogWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "RepresentationIndex: The new index is older than the previous one", ); - mockLogWarn?.mockClear(); + logWarn?.mockClear(); const oldTimeline2 = [ { start: 1000, duration: 500, repeatCount: 21 }, @@ -590,7 +582,7 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 0, duration: 1000, repeatCount: 0 }, { start: 1000, duration: 500, repeatCount: 21 }, ]; - expect(updateSegmentTimeline?.(oldTimeline2, newTimeline2)).toEqual(false); + expect(updateSegmentTimeline(oldTimeline2, newTimeline2)).toEqual(false); expect(oldTimeline2).toEqual([ { start: 1000, duration: 500, repeatCount: 21 }, { start: 12000, duration: 1000, repeatCount: 0 }, @@ -598,11 +590,11 @@ describe("Manifest Parsers utils - updateSegmentTimeline", () => { { start: 20000, duration: 5000, repeatCount: -1 }, ]); - expect(mockLogWarn).toHaveBeenCalledTimes(1); - expect(mockLogWarn).toHaveBeenCalledWith( + expect(logWarn).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledWith( "RepresentationIndex: The new index is older than the previous one", ); - mockLogWarn?.mockClear(); + logWarn?.mockClear(); }); }); diff --git a/src/parsers/texttracks/ttml/__tests__/resolve_styles_inheritance.test.ts b/src/parsers/texttracks/ttml/__tests__/resolve_styles_inheritance.test.ts index d522e653e6..0f3ca119a7 100644 --- a/src/parsers/texttracks/ttml/__tests__/resolve_styles_inheritance.test.ts +++ b/src/parsers/texttracks/ttml/__tests__/resolve_styles_inheritance.test.ts @@ -1,22 +1,16 @@ -import { describe, beforeEach, afterEach, it, expect, vi } from "vitest"; -import type IResolveStylesInheritance from "../resolve_styles_inheritance"; +import { describe, afterEach, it, expect, vi } from "vitest"; +import log from "../../../../log"; +import resolveStylesInheritance from "../resolve_styles_inheritance"; -const logWarnMock = vi.fn(); -let resolveStylesInheritance: typeof IResolveStylesInheritance; +const logWarn = vi.spyOn(log, "warn").mockImplementation(() => { + /* noop */ +}); describe("resolve_styles_inheritance", () => { - beforeEach(async () => { - vi.doMock("../../../../log", () => ({ - default: { - warn: logWarnMock, - }, - })); - resolveStylesInheritance = (await vi.importActual("../resolve_styles_inheritance")) - .default as typeof IResolveStylesInheritance; - }); afterEach(() => { vi.resetModules(); vi.resetAllMocks(); + logWarn.mockClear(); }); it("should not update styles without any inheritance", () => { @@ -31,7 +25,7 @@ describe("resolve_styles_inheritance", () => { { id: "2", style: { toti: "toti", tati: "totu" }, extendsStyles: [] }, { id: "3", style: { titu: "totu", tatu: "tatu" }, extendsStyles: [] }, ]); - expect(logWarnMock).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should resolve simple inheritance", () => { @@ -65,7 +59,7 @@ describe("resolve_styles_inheritance", () => { extendsStyles: [], }, ]); - expect(logWarnMock).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should be able to inherit multiple styles at once", () => { @@ -95,7 +89,7 @@ describe("resolve_styles_inheritance", () => { { id: "2", style: { toti: "toti", tati: "totu" }, extendsStyles: [] }, { id: "3", style: { titu: "totu", tatu: "tatu" }, extendsStyles: [] }, ]); - expect(logWarnMock).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should correctly overwrite inherited properties", () => { @@ -118,7 +112,7 @@ describe("resolve_styles_inheritance", () => { { id: "2", style: { titi: "tito", tata: "titu" }, extendsStyles: [] }, { id: "3", style: { teti: "teto", tata: "tutu" }, extendsStyles: [] }, ]); - expect(logWarnMock).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should correctly handle multiple levels of inheritance", () => { @@ -153,7 +147,7 @@ describe("resolve_styles_inheritance", () => { { id: "3", style: { teti: "teto", tata: "tutu" }, extendsStyles: [] }, { id: "4", style: { four: "4", four2: "four2" }, extendsStyles: [] }, ]); - expect(logWarnMock).not.toHaveBeenCalled(); + expect(logWarn).not.toHaveBeenCalled(); }); it("should avoid infinite inheritance loops", () => { @@ -178,12 +172,12 @@ describe("resolve_styles_inheritance", () => { }, ]); - expect(logWarnMock).toHaveBeenNthCalledWith( + expect(logWarn).toHaveBeenNthCalledWith( 1, "TTML Parser: infinite style inheritance loop avoided", ); - expect(logWarnMock).toHaveBeenCalledTimes(1); - logWarnMock.mockReset(); + expect(logWarn).toHaveBeenCalledTimes(1); + logWarn.mockReset(); // 2. More complex case const initialStyle2 = [ @@ -213,15 +207,15 @@ describe("resolve_styles_inheritance", () => { extendsStyles: [], }, ]); - expect(logWarnMock).toHaveBeenNthCalledWith( + expect(logWarn).toHaveBeenNthCalledWith( 1, "TTML Parser: infinite style inheritance loop avoided", ); - expect(logWarnMock).toHaveBeenNthCalledWith( + expect(logWarn).toHaveBeenNthCalledWith( 2, "TTML Parser: infinite style inheritance loop avoided", ); - expect(logWarnMock).toHaveBeenCalledTimes(2); + expect(logWarn).toHaveBeenCalledTimes(2); }); it("should ignore unknown IDs", () => { @@ -244,10 +238,10 @@ describe("resolve_styles_inheritance", () => { { id: "2", style: { titi: "tito", teta: "tutu" }, extendsStyles: [] }, { id: "3", style: { tata: "toto", tota: "tutu" }, extendsStyles: [] }, ]); - expect(logWarnMock).toHaveBeenNthCalledWith( + expect(logWarn).toHaveBeenNthCalledWith( 1, "TTML Parser: unknown style inheritance: 6", ); - expect(logWarnMock).toHaveBeenCalledTimes(1); + expect(logWarn).toHaveBeenCalledTimes(1); }); }); diff --git a/src/parsers/texttracks/ttml/html/__tests__/__global__/html_ttml_parser.test.ts b/src/parsers/texttracks/ttml/html/__tests__/__global__/html_ttml_parser.test.ts index 5716ea18e7..f95651c5be 100644 --- a/src/parsers/texttracks/ttml/html/__tests__/__global__/html_ttml_parser.test.ts +++ b/src/parsers/texttracks/ttml/html/__tests__/__global__/html_ttml_parser.test.ts @@ -1,6 +1,5 @@ import { describe, it, expect } from "vitest"; import parseTTMLToDiv from "../../"; -import globalScope from "../../../../../../utils/global_scope"; const testingText = ` @@ -167,9 +166,7 @@ describe("Global TTML HTML parsing tests", () => { for (const textNode of textNodes) { const parentElement = textNode.parentElement; if (parentElement !== null) { - expect(globalScope.getComputedStyle(parentElement).color).toEqual( - "rgb(255, 255, 0)", - ); + expect(parentElement.style.color).toEqual("yellow"); nbTextNodes++; } } @@ -179,9 +176,7 @@ describe("Global TTML HTML parsing tests", () => { for (const textNode of textNodes) { const parentElement = textNode.parentElement; if (parentElement !== null) { - expect(globalScope.getComputedStyle(parentElement).color).toEqual( - "rgb(255, 255, 255)", - ); + expect(parentElement.style.color).toEqual("white"); nbTextNodes++; } } diff --git a/src/parsers/texttracks/webvtt/__tests__/parse_cue_block.test.ts b/src/parsers/texttracks/webvtt/__tests__/parse_cue_block.test.ts index 099784b079..54fabb9a68 100644 --- a/src/parsers/texttracks/webvtt/__tests__/parse_cue_block.test.ts +++ b/src/parsers/texttracks/webvtt/__tests__/parse_cue_block.test.ts @@ -1,5 +1,16 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IParseCueBlock from "../parse_cue_block"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import parseCueBlock from "../parse_cue_block"; +import type parseTimestamp from "../parse_timestamp"; + +const mocks = vi.hoisted(() => { + return { + parseTimestamp: vi.fn(), + }; +}); + +vi.mock("../parse_timestamp", () => ({ + default: mocks.parseTimestamp, +})); const cueBlock1 = [ "112", @@ -35,13 +46,17 @@ const notCueBlock6 = ["aa:18:31.080 --> 00:18:32.200", "TOTO", "TATA"]; const notCueBlock7 = ["00:18:31.080 --> bb:18:32.200", "TOTO", "TATA"]; describe("parsers - srt - parseCueBlocks", () => { - beforeEach(() => { + beforeEach(async () => { vi.resetModules(); + const actualParseTimestamp = (await vi.importActual("../parse_timestamp")) + .default as typeof parseTimestamp; + mocks.parseTimestamp.mockImplementation(actualParseTimestamp); + }); + afterEach(() => { + mocks.parseTimestamp.mockReset(); }); - it("should correctly parse regular cue blocks", async () => { - const parseCueBlock = (await vi.importActual("../parse_cue_block")) - .default as typeof IParseCueBlock; + it("should correctly parse regular cue blocks", () => { expect(parseCueBlock(cueBlock1, 0)).toEqual({ start: 31.08, end: 452.2, @@ -87,9 +102,7 @@ describe("parsers - srt - parseCueBlocks", () => { }); }); - it("should add timeOffset in seconds", async () => { - const parseCueBlock = (await vi.importActual("../parse_cue_block")) - .default as typeof IParseCueBlock; + it("should add timeOffset in seconds", () => { expect(parseCueBlock(cueBlock1, 10.1)).toEqual({ start: 41.18, end: 462.3, @@ -146,9 +159,7 @@ describe("parsers - srt - parseCueBlocks", () => { }); }); - it("should return null for invalid cue blocks", async () => { - const parseCueBlock = (await vi.importActual("../parse_cue_block")) - .default as typeof IParseCueBlock; + it("should return null for invalid cue blocks", () => { expect(parseCueBlock(notCueBlock1, 0)).toEqual(null); expect(parseCueBlock(notCueBlock1, 5)).toEqual(null); expect(parseCueBlock(notCueBlock2, 0)).toEqual(null); @@ -161,27 +172,19 @@ describe("parsers - srt - parseCueBlocks", () => { expect(parseCueBlock(notCueBlock7, 0)).toEqual(null); }); - it("should return null if parseTimestamp returns undefined either for the starting timestamp", async () => { - const parseTimestamp = vi.fn((arg) => (arg === "00:00:31.080" ? undefined : 10)); - vi.doMock("../parse_timestamp", () => ({ - default: parseTimestamp, - })); - const parseCueBlock = (await vi.importActual("../parse_cue_block")) - .default as typeof IParseCueBlock; - + it("should return null if parseTimestamp returns undefined either for the starting timestamp", () => { + mocks.parseTimestamp.mockImplementation((arg) => + arg === "00:00:31.080" ? undefined : 10, + ); expect(parseCueBlock(cueBlock1, 0)).toEqual(null); - expect(parseTimestamp).toHaveBeenCalledTimes(2); + expect(mocks.parseTimestamp).toHaveBeenCalledTimes(2); }); - it("should return null if parseTimestamp returns undefined either for the ending timestamp", async () => { - const parseTimestamp = vi.fn((arg) => (arg === "00:07:32.200" ? undefined : 10)); - vi.doMock("../parse_timestamp", () => ({ - default: parseTimestamp, - })); - const parseCueBlock = (await vi.importActual("../parse_cue_block")) - .default as typeof IParseCueBlock; - + it("should return null if parseTimestamp returns undefined either for the ending timestamp", () => { + mocks.parseTimestamp.mockImplementation((arg) => + arg === "00:07:32.200" ? undefined : 10, + ); expect(parseCueBlock(cueBlock1, 0)).toEqual(null); - expect(parseTimestamp).toHaveBeenCalledTimes(2); + expect(mocks.parseTimestamp).toHaveBeenCalledTimes(2); }); }); diff --git a/src/parsers/texttracks/webvtt/html/__tests__/convert_payload_to_html.test.ts b/src/parsers/texttracks/webvtt/html/__tests__/convert_payload_to_html.test.ts index d55b71f0cb..a1f49cb0f1 100644 --- a/src/parsers/texttracks/webvtt/html/__tests__/convert_payload_to_html.test.ts +++ b/src/parsers/texttracks/webvtt/html/__tests__/convert_payload_to_html.test.ts @@ -1,16 +1,26 @@ import { describe, beforeEach, it, expect, vi } from "vitest"; import globalScope from "../../../../../utils/global_scope"; -import type IConvertPayloadToHTML from "../convert_payload_to_html"; +import convertPayloadToHTML from "../convert_payload_to_html"; + +const mocks = vi.hoisted(() => { + return { + createStyledElement: vi.fn(), + }; +}); +vi.mock("../create_styled_element", () => ({ + default: mocks.createStyledElement, +})); describe("parsers - webvtt - convertPayloadToHTML", () => { beforeEach(() => { vi.resetModules(); + mocks.createStyledElement.mockReset(); }); const gs = globalScope as { DOMParser: unknown; }; - it("should return empty payload when input text is empty", async () => { + it("should return empty payload when input text is empty", () => { const spyParseFromString = vi.fn(() => { return { body: { @@ -26,20 +36,13 @@ describe("parsers - webvtt - convertPayloadToHTML", () => { } }; - const spy = vi.fn(); - vi.doMock("../create_styled_element", () => ({ - default: spy, - })); - - const convertPayloadToHTML = (await vi.importActual("../convert_payload_to_html")) - .default as typeof IConvertPayloadToHTML; expect(convertPayloadToHTML("", {})).toEqual([]); expect(spyParseFromString).toHaveBeenCalledTimes(1); - expect(spy).not.toHaveBeenCalled(); + expect(mocks.createStyledElement).not.toHaveBeenCalled(); gs.DOMParser = origDOMParser; }); - it("should convert normal input text with no style", async () => { + it("should convert normal input text with no style", () => { const innerText = "Hello"; const bNode = document.createElement("b"); const textNode = document.createTextNode("Hello"); @@ -53,16 +56,13 @@ describe("parsers - webvtt - convertPayloadToHTML", () => { const span = document.createElement("span"); span.textContent = "Hello"; - const spyCreateStyledElement = vi.fn((input: Node) => { + mocks.createStyledElement.mockImplementation((input: Node) => { if (input.nodeName === bNode.nodeName) { return bNode; } else if (input.nodeName === textNode.nodeName) { return span; } }); - vi.doMock("../create_styled_element", () => ({ - default: spyCreateStyledElement, - })); const origDOMParser = gs.DOMParser; gs.DOMParser = class MockDOMParser { @@ -71,11 +71,9 @@ describe("parsers - webvtt - convertPayloadToHTML", () => { } }; - const convertPayloadToHTML = (await vi.importActual("../convert_payload_to_html")) - .default as typeof IConvertPayloadToHTML; expect(convertPayloadToHTML(innerText, {})).toEqual([bNode, span]); expect(spyParseFromString).toHaveBeenCalledTimes(1); - expect(spyCreateStyledElement).toHaveBeenCalledTimes(2); + expect(mocks.createStyledElement).toHaveBeenCalledTimes(2); gs.DOMParser = origDOMParser; }); }); diff --git a/src/parsers/texttracks/webvtt/html/__tests__/parse_style_block.test.ts b/src/parsers/texttracks/webvtt/html/__tests__/parse_style_block.test.ts index 3c08dff74c..9faff3748d 100644 --- a/src/parsers/texttracks/webvtt/html/__tests__/parse_style_block.test.ts +++ b/src/parsers/texttracks/webvtt/html/__tests__/parse_style_block.test.ts @@ -1,29 +1,32 @@ import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IParseStyleBlock from "../parse_style_block"; +import parseStyleBlock from "../parse_style_block"; + +const mocks = vi.hoisted(() => { + return { + createDefaultStyleElements: vi.fn(), + }; +}); +vi.mock("../create_default_style_elements", () => ({ + default: mocks.createDefaultStyleElements, +})); describe("parsers - webvtt - parseStyleBlock", () => { beforeEach(() => { vi.resetModules(); + mocks.createDefaultStyleElements.mockReset(); }); - it("should correctly handle empty style blocks", async () => { + it("should correctly handle empty style blocks", () => { const webvttStyle = [["STYLE"], []]; + mocks.createDefaultStyleElements.mockImplementation(() => ({})); - const mockCreateDefaultStyleElements = vi.fn(() => ({})); - vi.doMock("../create_default_style_elements", () => ({ - default: () => { - return mockCreateDefaultStyleElements(); - }, - })); - const parseStyleBlock = (await vi.importActual("../parse_style_block")) - .default as typeof IParseStyleBlock; expect(parseStyleBlock(webvttStyle)).toEqual({ classes: {}, global: "", }); }); - it("should parse global style", async () => { + it("should parse global style", () => { const webvttStyle = [ [ "STYLE", @@ -33,15 +36,8 @@ describe("parsers - webvtt - parseStyleBlock", () => { "}", ], ]; + mocks.createDefaultStyleElements.mockImplementation(() => ({})); - const mockCreateDefaultStyleElements = vi.fn(() => ({})); - vi.doMock("../create_default_style_elements", () => ({ - default: () => { - return mockCreateDefaultStyleElements(); - }, - })); - const parseStyleBlock = (await vi.importActual("../parse_style_block")) - .default as typeof IParseStyleBlock; expect(parseStyleBlock(webvttStyle)).toEqual({ classes: {}, global: @@ -50,17 +46,10 @@ describe("parsers - webvtt - parseStyleBlock", () => { }); }); - it("should parse class style", async () => { + it("should parse class style", () => { const webvttStyle = [["STYLE", "::cue(b) {", " color: peachpuff;", "}"]]; + mocks.createDefaultStyleElements.mockImplementation(() => ({})); - const mockCreateDefaultStyleElements = vi.fn(() => ({})); - vi.doMock("../create_default_style_elements", () => ({ - default: () => { - return mockCreateDefaultStyleElements(); - }, - })); - const parseStyleBlock = (await vi.importActual("../parse_style_block")) - .default as typeof IParseStyleBlock; expect(parseStyleBlock(webvttStyle)).toEqual({ classes: { b: " color: peachpuff;", @@ -69,7 +58,7 @@ describe("parsers - webvtt - parseStyleBlock", () => { }); }); - it("should parse both global and class style", async () => { + it("should parse both global and class style", () => { const webvttStyle = [ [ "STYLE", @@ -80,15 +69,8 @@ describe("parsers - webvtt - parseStyleBlock", () => { ], ["STYLE", "::cue(b) {", " color: peachpuff;", "}"], ]; + mocks.createDefaultStyleElements.mockImplementation(() => ({})); - const mockCreateDefaultStyleElements = vi.fn(() => ({})); - vi.doMock("../create_default_style_elements", () => ({ - default: () => { - return mockCreateDefaultStyleElements(); - }, - })); - const parseStyleBlock = (await vi.importActual("../parse_style_block")) - .default as typeof IParseStyleBlock; expect(parseStyleBlock(webvttStyle)).toEqual({ global: "background-image: linear-gradient(to bottom, dimgray, lightgray);" + @@ -99,20 +81,13 @@ describe("parsers - webvtt - parseStyleBlock", () => { }); }); - it("should not parse unformed styles", async () => { + it("should not parse unformed styles", () => { const webvttStyle = [ ["BAD STYLE"], ["STYLE", "::cue(b) {", " color: peachpuff;", "}"], ]; + mocks.createDefaultStyleElements.mockImplementation(() => ({})); - const mockCreateDefaultStyleElements = vi.fn(() => ({})); - vi.doMock("../create_default_style_elements", () => ({ - default: () => { - return mockCreateDefaultStyleElements(); - }, - })); - const parseStyleBlock = (await vi.importActual("../parse_style_block")) - .default as typeof IParseStyleBlock; expect(parseStyleBlock(webvttStyle)).toEqual({ classes: { b: " color: peachpuff;", @@ -121,20 +96,13 @@ describe("parsers - webvtt - parseStyleBlock", () => { }); }); - it("should not override styles if class if declared several times", async () => { + it("should not override styles if class if declared several times", () => { const webvttStyle = [ ["STYLE", "::cue(b) {", " color: peachpuff;", "}"], ["STYLE", "::cue(b) {", " background-color: dark;", "}"], ]; + mocks.createDefaultStyleElements.mockImplementation(() => ({})); - const mockCreateDefaultStyleElements = vi.fn(() => ({})); - vi.doMock("../create_default_style_elements", () => ({ - default: () => { - return mockCreateDefaultStyleElements(); - }, - })); - const parseStyleBlock = (await vi.importActual("../parse_style_block")) - .default as typeof IParseStyleBlock; expect(parseStyleBlock(webvttStyle)).toEqual({ classes: { b: " color: peachpuff; background-color: dark;", @@ -143,7 +111,7 @@ describe("parsers - webvtt - parseStyleBlock", () => { }); }); - it("should take into account all cues declared in one style block", async () => { + it("should take into account all cues declared in one style block", () => { const webvttStyle = [ [ "STYLE", @@ -155,15 +123,8 @@ describe("parsers - webvtt - parseStyleBlock", () => { "}", ], ]; + mocks.createDefaultStyleElements.mockImplementation(() => ({})); - const mockCreateDefaultStyleElements = vi.fn(() => ({})); - vi.doMock("../create_default_style_elements", () => ({ - default: () => { - return mockCreateDefaultStyleElements(); - }, - })); - const parseStyleBlock = (await vi.importActual("../parse_style_block")) - .default as typeof IParseStyleBlock; expect(parseStyleBlock(webvttStyle)).toEqual({ classes: { b: " background-color: dark;", @@ -172,7 +133,7 @@ describe("parsers - webvtt - parseStyleBlock", () => { }); }); - it("should consider a cue declared in multi-cue and mono-cue style blocks", async () => { + it("should consider a cue declared in multi-cue and mono-cue style blocks", () => { const webvttStyle = [ [ "STYLE", @@ -185,15 +146,8 @@ describe("parsers - webvtt - parseStyleBlock", () => { ], ["STYLE", "::cue(b) {", " color: salmon;", "}"], ]; + mocks.createDefaultStyleElements.mockImplementation(() => ({})); - const mockCreateDefaultStyleElements = vi.fn(() => ({})); - vi.doMock("../create_default_style_elements", () => ({ - default: () => { - return mockCreateDefaultStyleElements(); - }, - })); - const parseStyleBlock = (await vi.importActual("../parse_style_block")) - .default as typeof IParseStyleBlock; expect(parseStyleBlock(webvttStyle)).toEqual({ classes: { b: " background-color: dark; color: salmon;", @@ -201,7 +155,7 @@ describe("parsers - webvtt - parseStyleBlock", () => { global: " color: peachpuff;", }); }); - it("should consider a cue declared in multi-cue and mono-cue style blocks", async () => { + it("should consider a cue declared in multi-cue and mono-cue style blocks", () => { const webvttStyle = [ [ "STYLE", @@ -214,15 +168,8 @@ describe("parsers - webvtt - parseStyleBlock", () => { ], ["STYLE", "::cue(b) {", " color: salmon;", "}"], ]; + mocks.createDefaultStyleElements.mockImplementation(() => ({})); - const mockCreateDefaultStyleElements = vi.fn(() => ({})); - vi.doMock("../create_default_style_elements", () => ({ - default: () => { - return mockCreateDefaultStyleElements(); - }, - })); - const parseStyleBlock = (await vi.importActual("../parse_style_block")) - .default as typeof IParseStyleBlock; expect(parseStyleBlock(webvttStyle)).toEqual({ classes: { b: " background-color: dark; color: salmon;", @@ -231,20 +178,13 @@ describe("parsers - webvtt - parseStyleBlock", () => { }); }); - it("should consider multiple class declaration for one stylesheet", async () => { + it("should consider multiple class declaration for one stylesheet", () => { const webvttStyle = [ ["STYLE", "::cue(c),", "::cue(d),", "::cue(b) {", " background-color: dark;", "}"], ["STYLE", "::cue(c) {", " color: salmon;", "}"], ]; + mocks.createDefaultStyleElements.mockImplementation(() => ({})); - const mockCreateDefaultStyleElements = vi.fn(() => ({})); - vi.doMock("../create_default_style_elements", () => ({ - default: () => { - return mockCreateDefaultStyleElements(); - }, - })); - const parseStyleBlock = (await vi.importActual("../parse_style_block")) - .default as typeof IParseStyleBlock; expect(parseStyleBlock(webvttStyle)).toEqual({ classes: { b: " background-color: dark;", @@ -255,17 +195,10 @@ describe("parsers - webvtt - parseStyleBlock", () => { }); }); - it("should return empty style if no style block", async () => { + it("should return empty style if no style block", () => { const webvttStyle: string[][] = []; + mocks.createDefaultStyleElements.mockImplementation(() => ({})); - const mockCreateDefaultStyleElements = vi.fn(() => ({})); - vi.doMock("../create_default_style_elements", () => ({ - default: () => { - return mockCreateDefaultStyleElements(); - }, - })); - const parseStyleBlock = (await vi.importActual("../parse_style_block")) - .default as typeof IParseStyleBlock; expect(parseStyleBlock(webvttStyle)).toEqual({ classes: {}, global: "", diff --git a/src/parsers/texttracks/webvtt/html/__tests__/parse_webvtt_to_div.test.ts b/src/parsers/texttracks/webvtt/html/__tests__/parse_webvtt_to_div.test.ts index f221f0d220..5e9a11288f 100644 --- a/src/parsers/texttracks/webvtt/html/__tests__/parse_webvtt_to_div.test.ts +++ b/src/parsers/texttracks/webvtt/html/__tests__/parse_webvtt_to_div.test.ts @@ -1,78 +1,91 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type IParseWebVTT from "../parse_webvtt_to_div"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import parseWebVTT from "../parse_webvtt_to_div"; + +const mocks = vi.hoisted(() => { + return { + getStyleBlocks: vi.fn(), + getCueBlocks: vi.fn(), + parseStyleBlock: vi.fn(), + parseCueBlock: vi.fn(), + toHtml: vi.fn(), + getFirstLineAfterHeader: vi.fn(), + }; +}); +vi.mock("../../get_style_blocks", () => ({ + default: mocks.getStyleBlocks, +})); +vi.mock("../../get_cue_blocks", () => ({ + default: mocks.getCueBlocks, +})); +vi.mock("../../parse_cue_block", () => ({ + default: mocks.parseCueBlock, +})); +vi.mock("../parse_style_block", () => ({ + default: mocks.parseStyleBlock, +})); +vi.mock("../to_html", () => ({ + default: mocks.toHtml, +})); +vi.mock("../../utils", () => ({ + getFirstLineAfterHeader: mocks.getFirstLineAfterHeader, +})); describe("parsers - webvtt - parseWebVTT", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + mocks.getStyleBlocks.mockReset(); + mocks.getCueBlocks.mockReset(); + mocks.parseStyleBlock.mockReset(); + mocks.parseCueBlock.mockReset(); + mocks.toHtml.mockReset(); + mocks.getFirstLineAfterHeader.mockReset(); + }); - it("should throw if text is empty", async () => { - const parseWebVTT = (await vi.importActual("../parse_webvtt_to_div")) - .default as typeof IParseWebVTT; + it("should throw if text is empty", () => { expect(() => parseWebVTT("", 0)).toThrowError("Can't parse WebVTT: Invalid File."); }); - it("should throw if file seems to be invalid", async () => { - const parseWebVTT = (await vi.importActual("../parse_webvtt_to_div")) - .default as typeof IParseWebVTT; + it("should throw if file seems to be invalid", () => { expect(() => parseWebVTT("WEBWTT\n", 0)).toThrowError( "Can't parse WebVTT: Invalid File.", ); }); - it("should return cues if inner contains right cues", async () => { - const spyGetStyleBlock = vi.fn(() => [ + it("should return cues if inner contains right cues", () => { + mocks.getStyleBlocks.mockImplementation(() => [ ["STYLE", ""], ["STYLE", ""], ]); - vi.doMock("../../get_style_blocks", () => ({ - default: spyGetStyleBlock, - })); - const spyGetCueBlock = vi.fn(() => [ + mocks.getCueBlocks.mockImplementation(() => [ ["CUE", ""], ["CUE", ""], ]); - vi.doMock("../../get_cue_blocks", () => ({ - default: spyGetCueBlock, - })); - const spyParseCueBlock = vi.fn(() => ({ + mocks.parseCueBlock.mockImplementation(() => ({ start: 0, end: 100, payload: "TestBonjour", header: "b", settings: {}, })); - vi.doMock("../../parse_cue_block", () => ({ - default: spyParseCueBlock, - })); - const spyParseStyleBlock = vi.fn(() => ({ + mocks.parseStyleBlock.mockImplementation(() => ({ b: { styleContent: "color:blue;", }, })); - vi.doMock("../parse_style_block", () => ({ - default: spyParseStyleBlock, - })); - const spyToHTML = vi.fn(() => ({ + mocks.toHtml.mockImplementation(() => ({ start: 0, end: 100, element: document.createElement("div"), })); - vi.doMock("../to_html", () => ({ - default: spyToHTML, - })); - const spyGetFirstLineAfterHeader = vi.fn(() => 1); - vi.doMock("../../utils", () => ({ - getFirstLineAfterHeader: spyGetFirstLineAfterHeader, - })); + mocks.getFirstLineAfterHeader.mockImplementation(() => 1); - const parseWebVTT = (await vi.importActual("../parse_webvtt_to_div")) - .default as typeof IParseWebVTT; expect(parseWebVTT("WEBVTT\n", 0)).toEqual([ { element: document.createElement("div"), @@ -85,67 +98,47 @@ describe("parsers - webvtt - parseWebVTT", () => { start: 0, }, ]); - expect(spyGetFirstLineAfterHeader).toHaveBeenCalledTimes(1); - expect(spyGetStyleBlock).toHaveBeenCalledTimes(1); - expect(spyGetCueBlock).toHaveBeenCalledTimes(1); - expect(spyParseStyleBlock).toHaveBeenCalledTimes(1); - expect(spyParseCueBlock).toHaveBeenCalledTimes(2); - expect(spyToHTML).toHaveBeenCalledTimes(2); + expect(mocks.getFirstLineAfterHeader).toHaveBeenCalledTimes(1); + expect(mocks.getStyleBlocks).toHaveBeenCalledTimes(1); + expect(mocks.getCueBlocks).toHaveBeenCalledTimes(1); + expect(mocks.parseStyleBlock).toHaveBeenCalledTimes(1); + expect(mocks.parseCueBlock).toHaveBeenCalledTimes(2); + expect(mocks.toHtml).toHaveBeenCalledTimes(2); }); - it("should return empty array if cue blocks can't be parsed", async () => { - const spyGetStyleBlock = vi.fn(() => [ + it("should return empty array if cue blocks can't be parsed", () => { + mocks.getStyleBlocks.mockImplementation(() => [ ["STYLE", ""], ["STYLE", ""], ]); - vi.doMock("../../get_style_blocks", () => ({ - default: spyGetStyleBlock, - })); - const spyGetCueBlock = vi.fn(() => [ + mocks.getCueBlocks.mockImplementation(() => [ ["CUE", ""], ["CUE", ""], ]); - vi.doMock("../../get_cue_blocks", () => ({ - default: spyGetCueBlock, - })); - const spyParseCueBlock = vi.fn(() => null); - vi.doMock("../../parse_cue_block", () => ({ - default: spyParseCueBlock, - })); + mocks.parseCueBlock.mockImplementation(() => null); - const spyParseStyleBlock = vi.fn(() => ({ + mocks.parseStyleBlock.mockImplementation(() => ({ b: { styleContent: "color:blue;", }, })); - vi.doMock("../parse_style_block", () => ({ - default: spyParseStyleBlock, - })); - const spyToHTML = vi.fn(() => ({ + mocks.toHtml.mockImplementation(() => ({ start: 0, end: 100, element: document.createElement("div"), })); - vi.doMock("../to_html", () => ({ - default: spyToHTML, - })); - const spyGetFirstLineAfterHeader = vi.fn(() => 1); - vi.doMock("../../utils", () => ({ - getFirstLineAfterHeader: spyGetFirstLineAfterHeader, - })); + mocks.getFirstLineAfterHeader.mockImplementation(() => 1); - const parseWebVTT = (await vi.importActual("../parse_webvtt_to_div")) - .default as typeof IParseWebVTT; expect(parseWebVTT("WEBVTT\n", 0)).toEqual([]); - expect(spyGetFirstLineAfterHeader).toHaveBeenCalledTimes(1); - expect(spyGetStyleBlock).toHaveBeenCalledTimes(1); - expect(spyGetCueBlock).toHaveBeenCalledTimes(1); - expect(spyParseStyleBlock).toHaveBeenCalledTimes(1); - expect(spyParseCueBlock).toHaveBeenCalledTimes(2); - expect(spyToHTML).not.toHaveBeenCalled(); + expect(mocks.getFirstLineAfterHeader).toHaveBeenCalledTimes(1); + expect(mocks.getStyleBlocks).toHaveBeenCalledTimes(1); + expect(mocks.getCueBlocks).toHaveBeenCalledTimes(1); + expect(mocks.parseStyleBlock).toHaveBeenCalledTimes(1); + expect(mocks.parseCueBlock).toHaveBeenCalledTimes(2); + expect(mocks.toHtml).not.toHaveBeenCalled(); }); }); diff --git a/src/parsers/texttracks/webvtt/html/__tests__/to_html.test.ts b/src/parsers/texttracks/webvtt/html/__tests__/to_html.test.ts index b6ca94aa30..18e0e352b6 100644 --- a/src/parsers/texttracks/webvtt/html/__tests__/to_html.test.ts +++ b/src/parsers/texttracks/webvtt/html/__tests__/to_html.test.ts @@ -1,20 +1,30 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; import type { IStyleElements } from "../parse_style_block"; -import type IToHtml from "../to_html"; +import toHTML from "../to_html"; + +const mocks = vi.hoisted(() => { + return { + convertPayloadToHTML: vi.fn(), + }; +}); +vi.mock("../convert_payload_to_html", () => ({ + default: mocks.convertPayloadToHTML, +})); describe("parsers - webvtt - toHTML", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + mocks.convertPayloadToHTML.mockReset(); + }); - it("should include payload HTML", async () => { - vi.doMock("../convert_payload_to_html", () => ({ - default: () => { - return [document.createElement("b"), document.createTextNode("Hello")]; - }, - })); + it("should include payload HTML", () => { + mocks.convertPayloadToHTML.mockImplementation(() => [ + document.createElement("b"), + document.createTextNode("Hello"), + ]); - const toHTML = (await vi.importActual("../to_html")).default as typeof IToHtml; const cueObject = { start: 0, end: 100, @@ -46,14 +56,12 @@ describe("parsers - webvtt - toHTML", () => { ); }); - it("should include payload HTML and apply correclty style class element", async () => { - vi.doMock("../convert_payload_to_html", () => ({ - default: () => { - return [document.createElement("b"), document.createTextNode("Hello")]; - }, - })); + it("should include payload HTML and apply correclty style class element", () => { + mocks.convertPayloadToHTML.mockImplementation(() => [ + document.createElement("b"), + document.createTextNode("Hello"), + ]); - const toHTML = (await vi.importActual("../to_html")).default as typeof IToHtml; const cueObject = { start: 0, end: 100, @@ -87,14 +95,12 @@ describe("parsers - webvtt - toHTML", () => { ); }); - it("should include payload HTML and apply correctly global style element", async () => { - vi.doMock("../convert_payload_to_html", () => ({ - default: () => { - return [document.createElement("b"), document.createTextNode("Hello")]; - }, - })); + it("should include payload HTML and apply correctly global style element", () => { + mocks.convertPayloadToHTML.mockImplementation(() => [ + document.createElement("b"), + document.createTextNode("Hello"), + ]); - const toHTML = (await vi.importActual("../to_html")).default as typeof IToHtml; const cueObject = { start: 0, end: 100, @@ -127,14 +133,12 @@ describe("parsers - webvtt - toHTML", () => { ); }); - it("should apply both the global style element and a given class", async () => { - vi.doMock("../convert_payload_to_html", () => ({ - default: () => { - return [document.createElement("b"), document.createTextNode("Hello")]; - }, - })); + it("should apply both the global style element and a given class", () => { + mocks.convertPayloadToHTML.mockImplementation(() => [ + document.createElement("b"), + document.createTextNode("Hello"), + ]); - const toHTML = (await vi.importActual("../to_html")).default as typeof IToHtml; const cueObject = { start: 0, end: 100, @@ -168,14 +172,9 @@ describe("parsers - webvtt - toHTML", () => { ); }); - it("should return default element if no payload", async () => { - vi.doMock("../convert_payload_to_html", () => ({ - default: () => { - return []; - }, - })); + it("should return default element if no payload", () => { + mocks.convertPayloadToHTML.mockImplementation(() => []); - const toHTML = (await vi.importActual("../to_html")).default as typeof IToHtml; const cueObject = { start: 0, end: 100, diff --git a/src/transports/smooth/isobmff/__tests__/create_boxes.test.ts b/src/transports/smooth/isobmff/__tests__/create_boxes.test.ts index 694568ce2e..0440bd7124 100644 --- a/src/transports/smooth/isobmff/__tests__/create_boxes.test.ts +++ b/src/transports/smooth/isobmff/__tests__/create_boxes.test.ts @@ -1,60 +1,127 @@ +import type { Mock } from "vitest"; import { describe, beforeEach, it, expect, vi } from "vitest"; -import type { - createFRMABox as ICreateFRMABox, - createFreeBox as ICreateFreeBox, - createHDLRBox as ICreateHDLRBox, - createMDHDBox as ICreateMDHDBox, - createSMHDBox as ICreateSMHDBox, - createVMHDBox as ICreateVMHDBox, +import { + createFRMABox, + createFreeBox, + createHDLRBox, + createMDHDBox, + createSMHDBox, + createVMHDBox, } from "../create_boxes"; +const mocks = vi.hoisted(() => { + return { + isobmff: { + createBox: vi.fn(), + }, + byteParsing: { + itobe2: vi.fn(), + itobe4: vi.fn(), + itobe8: vi.fn(), + le2toi: vi.fn(), + be2toi: vi.fn(), + be3toi: vi.fn(), + be4toi: vi.fn(), + be8toi: vi.fn(), + concat: vi.fn(), + }, + stringParsing: { + strToUtf8: vi.fn(), + bytesToHex: vi.fn(), + guidToUuid: vi.fn(), + utf16LEToStr: vi.fn(), + hexToBytes: vi.fn(), + readNullTerminatedString: vi.fn(), + }, + }; +}); +vi.mock("../../../../parsers/containers/isobmff", () => ({ + createBox: mocks.isobmff.createBox, +})); +vi.mock("../../../../utils/byte_parsing", () => ({ + itobe2: mocks.byteParsing.itobe2, + itobe4: mocks.byteParsing.itobe4, + itobe8: mocks.byteParsing.itobe8, + le2toi: mocks.byteParsing.le2toi, + be2toi: mocks.byteParsing.be2toi, + be3toi: mocks.byteParsing.be3toi, + be4toi: mocks.byteParsing.be4toi, + be8toi: mocks.byteParsing.be8toi, + concat: mocks.byteParsing.concat, +})); +vi.mock("../../../../utils/string_parsing", () => ({ + strToUtf8: mocks.stringParsing.strToUtf8, + bytesToHex: mocks.stringParsing.bytesToHex, + guidToUuid: mocks.stringParsing.guidToUuid, + utf16LEToStr: mocks.stringParsing.utf16LEToStr, + hexToBytes: mocks.stringParsing.hexToBytes, + readNullTerminatedString: mocks.stringParsing.readNullTerminatedString, +})); + describe("Smooth - ISOBMFF - boxes creation", () => { - beforeEach(() => { + beforeEach(async () => { vi.resetModules(); + + const actualIsobmff = await vi.importActual("../../../../parsers/containers/isobmff"); + const actualByteParsing = await vi.importActual("../../../../utils/byte_parsing"); + const actualStringParsing = await vi.importActual("../../../../utils/string_parsing"); + + const isobmffKeys = Object.keys(mocks.isobmff) as Array; + isobmffKeys.forEach((key: keyof typeof mocks.isobmff) => { + mocks.isobmff[key].mockReset(); + mocks.isobmff[key].mockImplementation( + actualIsobmff[key] as Mock>, + ); + }); + + const byteParsingKeys = Object.keys(mocks.byteParsing) as Array< + keyof typeof mocks.byteParsing + >; + byteParsingKeys.forEach((key: keyof typeof mocks.byteParsing) => { + mocks.byteParsing[key].mockReset(); + mocks.byteParsing[key].mockImplementation( + actualByteParsing[key] as Mock>, + ); + }); + + const stringParsingKeys = Object.keys(mocks.stringParsing) as Array< + keyof typeof mocks.stringParsing + >; + stringParsingKeys.forEach((key: keyof typeof mocks.stringParsing) => { + mocks.stringParsing[key].mockReset(); + mocks.stringParsing[key].mockImplementation( + actualStringParsing[key] as Mock>, + ); + }); }); describe("createVMHDBox", () => { - it("should create always the same vmhd box", async () => { + it("should create always the same vmhd box", () => { const vmhdContent = new Uint8Array([0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]); const box = new Uint8Array([1, 2, 3, 4]); - const mockCreateBox = vi.fn().mockImplementation(() => box); - vi.doMock("../../../../parsers/containers/isobmff", () => { - return { createBox: mockCreateBox }; - }); - const createVMHDBox = (await vi.importActual("../create_boxes")) - .createVMHDBox as typeof ICreateVMHDBox; + mocks.isobmff.createBox.mockImplementation(() => box); expect(createVMHDBox()).toBe(box); - expect(mockCreateBox).toHaveBeenCalledTimes(1); - expect(mockCreateBox).toHaveBeenCalledWith("vmhd", vmhdContent); + expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1); + expect(mocks.isobmff.createBox).toHaveBeenCalledWith("vmhd", vmhdContent); }); }); describe("createFreeBox", () => { - it("should create box full of 0s", async () => { + it("should create box full of 0s", () => { const box = new Uint8Array([1, 2, 3, 4]); - const mockCreateBox = vi.fn().mockImplementation(() => box); - vi.doMock("../../../../parsers/containers/isobmff", () => { - return { createBox: mockCreateBox }; - }); - const createFreeBox = (await vi.importActual("../create_boxes")) - .createFreeBox as typeof ICreateFreeBox; + mocks.isobmff.createBox.mockImplementation(() => box); expect(createFreeBox(8)).toBe(box); - expect(mockCreateBox).toHaveBeenCalledTimes(1); - expect(mockCreateBox).toHaveBeenCalledWith("free", new Uint8Array([])); + expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1); + expect(mocks.isobmff.createBox).toHaveBeenCalledWith("free", new Uint8Array([])); expect(createFreeBox(15)).toBe(box); - expect(mockCreateBox).toHaveBeenCalledTimes(2); - expect(mockCreateBox).toHaveBeenCalledWith("free", new Uint8Array(7)); + expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(2); + expect(mocks.isobmff.createBox).toHaveBeenCalledWith("free", new Uint8Array(7)); }); - it("should throw when given a length below 8", async () => { + it("should throw when given a length below 8", () => { const box = new Uint8Array([1, 2, 3, 4]); - const mockCreateBox = vi.fn().mockImplementation(() => box); - vi.doMock("../../../../parsers/containers/isobmff", () => { - return { createBox: mockCreateBox }; - }); - const createFreeBox = (await vi.importActual("../create_boxes")) - .createFreeBox as typeof ICreateFreeBox; + mocks.isobmff.createBox.mockImplementation(() => box); expect(() => createFreeBox(7)).toThrow(); expect(() => createFreeBox(6)).toThrow(); expect(() => createFreeBox(5)).toThrow(); @@ -63,47 +130,32 @@ describe("Smooth - ISOBMFF - boxes creation", () => { expect(() => createFreeBox(2)).toThrow(); expect(() => createFreeBox(1)).toThrow(); expect(() => createFreeBox(0)).toThrow(); - expect(mockCreateBox).not.toHaveBeenCalled(); + expect(mocks.isobmff.createBox).not.toHaveBeenCalled(); }); - it("should throw when given a negative length", async () => { + it("should throw when given a negative length", () => { const box = new Uint8Array([1, 2, 3, 4]); - const mockCreateBox = vi.fn().mockImplementation(() => box); - vi.doMock("../../../../parsers/containers/isobmff", () => { - return { createBox: mockCreateBox }; - }); - const createFreeBox = (await vi.importActual("../create_boxes")) - .createFreeBox as typeof ICreateFreeBox; + mocks.isobmff.createBox.mockImplementation(() => box); expect(() => createFreeBox(-1)).toThrow(); - expect(mockCreateBox).not.toHaveBeenCalled(); + expect(mocks.isobmff.createBox).not.toHaveBeenCalled(); }); - it("should throw when given a non-finite length", async () => { + it("should throw when given a non-finite length", () => { const box = new Uint8Array([1, 2, 3, 4]); - const mockCreateBox = vi.fn().mockImplementation(() => box); - vi.doMock("../../../../parsers/containers/isobmff", () => { - return { createBox: mockCreateBox }; - }); - const createFreeBox = (await vi.importActual("../create_boxes")) - .createFreeBox as typeof ICreateFreeBox; + mocks.isobmff.createBox.mockImplementation(() => box); expect(() => createFreeBox(-Infinity)).toThrow(); expect(() => createFreeBox(+Infinity)).toThrow(); - expect(mockCreateBox).not.toHaveBeenCalled(); + expect(mocks.isobmff.createBox).not.toHaveBeenCalled(); }); }); describe("createHDLRBox", () => { - it("should always create the same audio box", async () => { + it("should always create the same audio box", () => { const box = new Uint8Array([1, 2, 3, 4]); - const mockCreateBox = vi.fn().mockImplementation(() => box); - vi.doMock("../../../../parsers/containers/isobmff", () => { - return { createBox: mockCreateBox }; - }); - const createHDLRBox = (await vi.importActual("../create_boxes")) - .createHDLRBox as typeof ICreateHDLRBox; + mocks.isobmff.createBox.mockImplementation(() => box); expect(createHDLRBox("audio")).toBe(box); - expect(mockCreateBox).toHaveBeenCalledTimes(1); - expect(mockCreateBox).toHaveBeenCalledWith( + expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1); + expect(mocks.isobmff.createBox).toHaveBeenCalledWith( "hdlr", new Uint8Array([ 0, @@ -147,17 +199,12 @@ describe("Smooth - ISOBMFF - boxes creation", () => { ); }); - it("should always create the same video box", async () => { + it("should always create the same video box", () => { const box = new Uint8Array([1, 2, 3, 4]); - const mockCreateBox = vi.fn().mockImplementation(() => box); - vi.doMock("../../../../parsers/containers/isobmff", () => { - return { createBox: mockCreateBox }; - }); - const createHDLRBox = (await vi.importActual("../create_boxes")) - .createHDLRBox as typeof ICreateHDLRBox; + mocks.isobmff.createBox.mockImplementation(() => box); expect(createHDLRBox("video")).toBe(box); - expect(mockCreateBox).toHaveBeenCalledTimes(1); - expect(mockCreateBox).toHaveBeenCalledWith( + expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1); + expect(mocks.isobmff.createBox).toHaveBeenCalledWith( "hdlr", new Uint8Array([ 0, @@ -201,17 +248,12 @@ describe("Smooth - ISOBMFF - boxes creation", () => { ); }); - it("should always create the same hint box", async () => { + it("should always create the same hint box", () => { const box = new Uint8Array([1, 2, 3, 4]); - const mockCreateBox = vi.fn().mockImplementation(() => box); - vi.doMock("../../../../parsers/containers/isobmff", () => { - return { createBox: mockCreateBox }; - }); - const createHDLRBox = (await vi.importActual("../create_boxes")) - .createHDLRBox as typeof ICreateHDLRBox; + mocks.isobmff.createBox.mockImplementation(() => box); expect(createHDLRBox("hint")).toBe(box); - expect(mockCreateBox).toHaveBeenCalledTimes(1); - expect(mockCreateBox).toHaveBeenCalledWith( + expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1); + expect(mocks.isobmff.createBox).toHaveBeenCalledWith( "hdlr", new Uint8Array([ 0, @@ -245,81 +287,60 @@ describe("Smooth - ISOBMFF - boxes creation", () => { }); describe("createMDHDBox", () => { - it("should just integrate the timescale given", async () => { + it("should just integrate the timescale given", () => { const translatedTimeScale = new Uint8Array([4, 3, 2, 1]); const concatenated = new Uint8Array([9, 10, 11, 12]); const box = new Uint8Array([1, 2, 3, 4]); - const mockItobe4 = vi.fn().mockImplementation(() => translatedTimeScale); - const mockConcat = vi.fn().mockImplementation(() => concatenated); - const mockCreateBox = vi.fn().mockImplementation(() => box); - vi.doMock("../../../../utils/byte_parsing", () => { - return { itobe4: mockItobe4, concat: mockConcat }; - }); - vi.doMock("../../../../parsers/containers/isobmff", () => { - return { createBox: mockCreateBox }; - }); - const createMDHDBox = (await vi.importActual("../create_boxes")) - .createMDHDBox as typeof ICreateMDHDBox; + mocks.byteParsing.itobe4.mockImplementation(() => translatedTimeScale); + mocks.byteParsing.concat.mockImplementation(() => concatenated); + mocks.isobmff.createBox.mockImplementation(() => box); expect(createMDHDBox(8)).toBe(box); - expect(mockCreateBox).toHaveBeenCalledTimes(1); - expect(mockCreateBox).toHaveBeenCalledWith("mdhd", concatenated); + expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1); + expect(mocks.isobmff.createBox).toHaveBeenCalledWith("mdhd", concatenated); - expect(mockItobe4).toHaveBeenCalledTimes(1); - expect(mockItobe4).toHaveBeenCalledWith(8); + expect(mocks.byteParsing.itobe4).toHaveBeenCalledTimes(1); + expect(mocks.byteParsing.itobe4).toHaveBeenCalledWith(8); - expect(mockConcat).toHaveBeenCalledTimes(1); - expect(mockConcat).toHaveBeenCalledWith(12, translatedTimeScale, 8); + expect(mocks.byteParsing.concat).toHaveBeenCalledTimes(1); + expect(mocks.byteParsing.concat).toHaveBeenCalledWith(12, translatedTimeScale, 8); expect(createMDHDBox(99)).toBe(box); - expect(mockCreateBox).toHaveBeenCalledTimes(2); - expect(mockCreateBox).toHaveBeenCalledWith("mdhd", concatenated); + expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(2); + expect(mocks.isobmff.createBox).toHaveBeenCalledWith("mdhd", concatenated); - expect(mockItobe4).toHaveBeenCalledTimes(2); - expect(mockItobe4).toHaveBeenCalledWith(99); + expect(mocks.byteParsing.itobe4).toHaveBeenCalledTimes(2); + expect(mocks.byteParsing.itobe4).toHaveBeenCalledWith(99); - expect(mockConcat).toHaveBeenCalledTimes(2); - expect(mockConcat).toHaveBeenCalledWith(12, translatedTimeScale, 8); + expect(mocks.byteParsing.concat).toHaveBeenCalledTimes(2); + expect(mocks.byteParsing.concat).toHaveBeenCalledWith(12, translatedTimeScale, 8); }); }); describe("createSMHDBox", () => { - it("should create always the same smhd box", async () => { + it("should create always the same smhd box", () => { const smhdContent = new Uint8Array(8); const box = new Uint8Array([1, 2, 3, 4]); - const mockCreateBox = vi.fn().mockImplementation(() => box); - vi.doMock("../../../../parsers/containers/isobmff", () => { - return { createBox: mockCreateBox }; - }); - const createSMHDBox = (await vi.importActual("../create_boxes")) - .createSMHDBox as typeof ICreateSMHDBox; + mocks.isobmff.createBox.mockImplementation(() => box); expect(createSMHDBox()).toBe(box); - expect(mockCreateBox).toHaveBeenCalledTimes(1); - expect(mockCreateBox).toHaveBeenCalledWith("smhd", smhdContent); + expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1); + expect(mocks.isobmff.createBox).toHaveBeenCalledWith("smhd", smhdContent); }); }); describe("createFRMABox", () => { - it("should just integrate the data format", async () => { + it("should just integrate the data format", () => { const dataFormatToBytes = new Uint8Array([4, 3, 2, 1]); const box = new Uint8Array([1, 2, 3, 4]); - const mockStrToUtf8 = vi.fn().mockImplementation(() => dataFormatToBytes); - const mockCreateBox = vi.fn().mockImplementation(() => box); - vi.doMock("../../../../utils/string_parsing", () => { - return { strToUtf8: mockStrToUtf8 }; - }); - vi.doMock("../../../../parsers/containers/isobmff", () => { - return { createBox: mockCreateBox }; - }); - const createFRMABox = (await vi.importActual("../create_boxes")) - .createFRMABox as typeof ICreateFRMABox; + mocks.stringParsing.strToUtf8.mockImplementation(() => dataFormatToBytes); + mocks.isobmff.createBox.mockImplementation(() => box); expect(createFRMABox("foo")).toBe(box); - expect(mockCreateBox).toHaveBeenCalledTimes(1); - expect(mockCreateBox).toHaveBeenCalledWith("frma", dataFormatToBytes); - expect(mockStrToUtf8).toHaveBeenCalledTimes(1); - expect(mockStrToUtf8).toHaveBeenCalledWith("foo"); + expect(mocks.isobmff.createBox).toHaveBeenCalledTimes(1); + expect(mocks.isobmff.createBox).toHaveBeenCalledWith("frma", dataFormatToBytes); + expect(mocks.stringParsing.strToUtf8).toHaveBeenCalledTimes(1); + expect(mocks.stringParsing.strToUtf8).toHaveBeenCalledWith("foo"); }); }); }); diff --git a/src/transports/utils/__tests__/check_isobmff_integrity.test.ts b/src/transports/utils/__tests__/check_isobmff_integrity.test.ts index 77bdda597b..e369bd7ee6 100644 --- a/src/transports/utils/__tests__/check_isobmff_integrity.test.ts +++ b/src/transports/utils/__tests__/check_isobmff_integrity.test.ts @@ -1,49 +1,44 @@ -import { describe, beforeEach, it, expect, vi } from "vitest"; -import type { OtherError as IOtherError } from "../../../errors"; -import type ICheckISOBMFFIntegrity from "../check_isobmff_integrity"; +import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; +import { OtherError } from "../../../errors"; +import checkISOBMFFIntegrity from "../check_isobmff_integrity"; + +const mocks = vi.hoisted(() => { + return { + findCompleteBox: vi.fn(), + }; +}); +vi.mock("../../../parsers/containers/isobmff", () => ({ + findCompleteBox: mocks.findCompleteBox, +})); describe("transports utils - checkISOBMFFIntegrity", () => { beforeEach(() => { vi.resetModules(); }); + afterEach(() => { + mocks.findCompleteBox.mockReset(); + }); - it("should check just ftyp and and moov integrity for init segments", async () => { - const mockFindCompleteBox = vi.fn(() => 45); - vi.doMock("../../../parsers/containers/isobmff", () => ({ - findCompleteBox: mockFindCompleteBox, - })); - const checkISOBMFFIntegrity = (await vi.importActual("../check_isobmff_integrity")) - .default as typeof ICheckISOBMFFIntegrity; + it("should check just ftyp and and moov integrity for init segments", () => { + mocks.findCompleteBox.mockImplementation(() => 45); const myUint8Array = new Uint8Array([0, 1, 2]); expect(() => checkISOBMFFIntegrity(myUint8Array, true)).not.toThrow(); - expect(mockFindCompleteBox).toHaveBeenCalledTimes(2); - expect(mockFindCompleteBox).toHaveBeenCalledWith(myUint8Array, 0x66747970); - expect(mockFindCompleteBox).toHaveBeenCalledWith(myUint8Array, 0x6d6f6f76); + expect(mocks.findCompleteBox).toHaveBeenCalledTimes(2); + expect(mocks.findCompleteBox).toHaveBeenCalledWith(myUint8Array, 0x66747970); + expect(mocks.findCompleteBox).toHaveBeenCalledWith(myUint8Array, 0x6d6f6f76); }); - it("should check just moof and and mdat integrity for regular segments", async () => { - const mockFindCompleteBox = vi.fn(() => 45); - vi.doMock("../../../parsers/containers/isobmff", () => ({ - findCompleteBox: mockFindCompleteBox, - })); - const checkISOBMFFIntegrity = (await vi.importActual("../check_isobmff_integrity")) - .default as typeof ICheckISOBMFFIntegrity; + it("should check just moof and and mdat integrity for regular segments", () => { + mocks.findCompleteBox.mockImplementation(() => 45); const myUint8Array = new Uint8Array([0, 1, 2]); expect(() => checkISOBMFFIntegrity(myUint8Array, false)).not.toThrow(); - expect(mockFindCompleteBox).toHaveBeenCalledTimes(2); - expect(mockFindCompleteBox).toHaveBeenCalledWith(myUint8Array, 0x6d6f6f66); - expect(mockFindCompleteBox).toHaveBeenCalledWith(myUint8Array, 0x6d646174); + expect(mocks.findCompleteBox).toHaveBeenCalledTimes(2); + expect(mocks.findCompleteBox).toHaveBeenCalledWith(myUint8Array, 0x6d6f6f66); + expect(mocks.findCompleteBox).toHaveBeenCalledWith(myUint8Array, 0x6d646174); }); - it("should throw an other error if an init segment is missing a complete ftyp", async () => { - const mockFindCompleteBox = vi.fn((_, box) => (box === 0x66747970 ? -1 : 45)); - vi.doMock("../../../parsers/containers/isobmff", () => ({ - findCompleteBox: mockFindCompleteBox, - })); - const OtherError = (await vi.importActual("../../../errors")) - .OtherError as typeof IOtherError; - const checkISOBMFFIntegrity = (await vi.importActual("../check_isobmff_integrity")) - .default as typeof ICheckISOBMFFIntegrity; + it("should throw an other error if an init segment is missing a complete ftyp", () => { + mocks.findCompleteBox.mockImplementation((_, box) => (box === 0x66747970 ? -1 : 45)); const myUint8Array = new Uint8Array([0, 1, 2]); let error: unknown = null; try { @@ -52,23 +47,16 @@ describe("transports utils - checkISOBMFFIntegrity", () => { error = e; } expect(error).toBeInstanceOf(OtherError); - expect((error as IOtherError).name).toEqual("OtherError"); - expect((error as IOtherError).type).toEqual("OTHER_ERROR"); - expect((error as IOtherError).code).toEqual("INTEGRITY_ERROR"); - expect((error as IOtherError).message).toEqual( + expect((error as OtherError).name).toEqual("OtherError"); + expect((error as OtherError).type).toEqual("OTHER_ERROR"); + expect((error as OtherError).code).toEqual("INTEGRITY_ERROR"); + expect((error as OtherError).message).toEqual( "INTEGRITY_ERROR: Incomplete `ftyp` box", ); }); - it("should throw an other error if an init segment is missing a complete moov", async () => { - const mockFindCompleteBox = vi.fn((_, box) => (box === 0x6d6f6f76 ? -1 : 45)); - vi.doMock("../../../parsers/containers/isobmff", () => ({ - findCompleteBox: mockFindCompleteBox, - })); - const OtherError = (await vi.importActual("../../../errors")) - .OtherError as typeof IOtherError; - const checkISOBMFFIntegrity = (await vi.importActual("../check_isobmff_integrity")) - .default as typeof ICheckISOBMFFIntegrity; + it("should throw an other error if an init segment is missing a complete moov", () => { + mocks.findCompleteBox.mockImplementation((_, box) => (box === 0x6d6f6f76 ? -1 : 45)); const myUint8Array = new Uint8Array([0, 1, 2]); let error: unknown = null; try { @@ -77,23 +65,16 @@ describe("transports utils - checkISOBMFFIntegrity", () => { error = e; } expect(error).toBeInstanceOf(OtherError); - expect((error as IOtherError).name).toEqual("OtherError"); - expect((error as IOtherError).type).toEqual("OTHER_ERROR"); - expect((error as IOtherError).code).toEqual("INTEGRITY_ERROR"); - expect((error as IOtherError).message).toEqual( + expect((error as OtherError).name).toEqual("OtherError"); + expect((error as OtherError).type).toEqual("OTHER_ERROR"); + expect((error as OtherError).code).toEqual("INTEGRITY_ERROR"); + expect((error as OtherError).message).toEqual( "INTEGRITY_ERROR: Incomplete `moov` box", ); }); - it("should throw an other error if a regular segment is missing a complete moof", async () => { - const mockFindCompleteBox = vi.fn((_, box) => (box === 0x6d6f6f66 ? -1 : 45)); - vi.doMock("../../../parsers/containers/isobmff", () => ({ - findCompleteBox: mockFindCompleteBox, - })); - const OtherError = (await vi.importActual("../../../errors")) - .OtherError as typeof IOtherError; - const checkISOBMFFIntegrity = (await vi.importActual("../check_isobmff_integrity")) - .default as typeof ICheckISOBMFFIntegrity; + it("should throw an other error if a regular segment is missing a complete moof", () => { + mocks.findCompleteBox.mockImplementation((_, box) => (box === 0x6d6f6f66 ? -1 : 45)); const myUint8Array = new Uint8Array([0, 1, 2]); let error: unknown = null; try { @@ -102,23 +83,16 @@ describe("transports utils - checkISOBMFFIntegrity", () => { error = e; } expect(error).toBeInstanceOf(OtherError); - expect((error as IOtherError).name).toEqual("OtherError"); - expect((error as IOtherError).type).toEqual("OTHER_ERROR"); - expect((error as IOtherError).code).toEqual("INTEGRITY_ERROR"); - expect((error as IOtherError).message).toEqual( + expect((error as OtherError).name).toEqual("OtherError"); + expect((error as OtherError).type).toEqual("OTHER_ERROR"); + expect((error as OtherError).code).toEqual("INTEGRITY_ERROR"); + expect((error as OtherError).message).toEqual( "INTEGRITY_ERROR: Incomplete `moof` box", ); }); - it("should throw an other error if a regular segment is missing a complete mdat", async () => { - const mockFindCompleteBox = vi.fn((_, box) => (box === 0x6d646174 ? -1 : 45)); - vi.doMock("../../../parsers/containers/isobmff", () => ({ - findCompleteBox: mockFindCompleteBox, - })); - const OtherError = (await vi.importActual("../../../errors")) - .OtherError as typeof IOtherError; - const checkISOBMFFIntegrity = (await vi.importActual("../check_isobmff_integrity")) - .default as typeof ICheckISOBMFFIntegrity; + it("should throw an other error if a regular segment is missing a complete mdat", () => { + mocks.findCompleteBox.mockImplementation((_, box) => (box === 0x6d646174 ? -1 : 45)); const myUint8Array = new Uint8Array([0, 1, 2]); let error: unknown = null; try { @@ -127,10 +101,10 @@ describe("transports utils - checkISOBMFFIntegrity", () => { error = e; } expect(error).toBeInstanceOf(OtherError); - expect((error as IOtherError).name).toEqual("OtherError"); - expect((error as IOtherError).type).toEqual("OTHER_ERROR"); - expect((error as IOtherError).code).toEqual("INTEGRITY_ERROR"); - expect((error as IOtherError).message).toEqual( + expect((error as OtherError).name).toEqual("OtherError"); + expect((error as OtherError).type).toEqual("OTHER_ERROR"); + expect((error as OtherError).code).toEqual("INTEGRITY_ERROR"); + expect((error as OtherError).message).toEqual( "INTEGRITY_ERROR: Incomplete `mdat` box", ); }); diff --git a/src/utils/__tests__/base64.test.ts b/src/utils/__tests__/base64.test.ts index 0029ec3400..05809755bf 100644 --- a/src/utils/__tests__/base64.test.ts +++ b/src/utils/__tests__/base64.test.ts @@ -1,10 +1,12 @@ import { describe, beforeEach, it, expect, vi, afterEach } from "vitest"; -import type { - base64ToBytes as IBase64ToBytes, - bytesToBase64 as IBytesToBase64, -} from "../base64"; +import log from "../../log"; +import { base64ToBytes, bytesToBase64 } from "../base64"; import globalScope from "../global_scope"; +const logWarn = vi.spyOn(log, "warn").mockImplementation(() => { + /* noop */ +}); + /** Every chars defined in base64. */ const CHARS = [ "A", @@ -74,27 +76,17 @@ const CHARS = [ ]; describe("base64ToBytes", () => { - const logWarn = vi.fn(); - beforeEach(() => { - vi.doMock("../../log", () => ({ - default: { warn: logWarn }, - })); - }); afterEach(() => { vi.resetModules(); - logWarn.mockReset(); + logWarn.mockClear(); }); - it("should return an empty Uint8Array for an empty string", async () => { - const base64ToBytes = (await vi.importActual("../base64")) - .base64ToBytes as typeof IBase64ToBytes; + it("should return an empty Uint8Array for an empty string", () => { expect(base64ToBytes("")).toEqual(new Uint8Array([])); expect(logWarn).not.toHaveBeenCalled(); }); - it("should convert a base64 to an Uint8Array", async () => { - const base64ToBytes = (await vi.importActual("../base64")) - .base64ToBytes as typeof IBase64ToBytes; + it("should convert a base64 to an Uint8Array", () => { expect(base64ToBytes("woDCge+/vg==")).toEqual( new Uint8Array([194, 128, 194, 129, 239, 191, 190]), ); @@ -112,9 +104,6 @@ describe("base64ToBytes", () => { ); expect(logWarn).not.toHaveBeenCalled(); - const bytesToBase64 = (await vi.importActual("../base64")) - .bytesToBase64 as typeof IBytesToBase64; - for (let i = 0; i < CHARS.length; i++) { const char1 = CHARS[i]; for (let j = 0; j < CHARS.length; j++) { @@ -131,9 +120,7 @@ describe("base64ToBytes", () => { } }); - it("should convert a non-padded base64 to an Uint8Array", async () => { - const base64ToBytes = (await vi.importActual("../base64")) - .base64ToBytes as typeof IBase64ToBytes; + it("should convert a non-padded base64 to an Uint8Array", () => { expect(base64ToBytes("woDCge+/vg")).toEqual( new Uint8Array([194, 128, 194, 129, 239, 191, 190]), ); @@ -152,9 +139,7 @@ describe("base64ToBytes", () => { ); }); - it("should fail on invalid data", async () => { - const base64ToBytes = (await vi.importActual("../base64")) - .base64ToBytes as typeof IBase64ToBytes; + it("should fail on invalid data", () => { expect(() => base64ToBytes("woD=Cge+/vg=")).toThrowError( "Unable to parse base64 string.", ); @@ -168,25 +153,17 @@ describe("base64ToBytes", () => { }); describe("bytesToBase64", () => { - const logWarn = vi.fn(); beforeEach(() => { vi.resetModules(); - logWarn.mockReset(); - vi.doMock("../../log", () => ({ - default: { warn: logWarn }, - })); + logWarn.mockClear(); }); - it("should return an empty string for an empty Uint8Array", async () => { - const bytesToBase64 = (await vi.importActual("../base64")) - .bytesToBase64 as typeof IBytesToBase64; + it("should return an empty string for an empty Uint8Array", () => { expect(bytesToBase64(new Uint8Array([]))).toEqual(""); expect(logWarn).not.toHaveBeenCalled(); }); - it("should convert a base64 to an Uint8Array", async () => { - const bytesToBase64 = (await vi.importActual("../base64")) - .bytesToBase64 as typeof IBytesToBase64; + it("should convert a base64 to an Uint8Array", () => { expect(bytesToBase64(new Uint8Array([194, 128, 194, 129, 239, 191, 190]))).toEqual( "woDCge+/vg==", ); diff --git a/src/utils/__tests__/object_assign.test.ts b/src/utils/__tests__/object_assign.test.ts index 8b7ff6ba75..c176f29db9 100644 --- a/src/utils/__tests__/object_assign.test.ts +++ b/src/utils/__tests__/object_assign.test.ts @@ -5,10 +5,10 @@ describe("utils - objectAssign", () => { it("should throw if target is not an object", () => { expect(() => { objectAssign(null as unknown as object, {}); - }).toThrow("Cannot convert undefined or null to object"); + }).toThrow(); expect(() => { objectAssign(undefined as unknown as object, {}); - }).toThrow("Cannot convert undefined or null to object"); + }).toThrow(); }); it("should update the first argument and return it", () => { diff --git a/tests/contents/server.mjs b/tests/contents/server.mjs index b14ce29945..4334ed363e 100644 --- a/tests/contents/server.mjs +++ b/tests/contents/server.mjs @@ -19,7 +19,7 @@ const DEFAULT_CONTENT_SERVER_PORT = 3000; * @param {number} port * @returns {Object} */ -export function createContentServer(port = DEFAULT_CONTENT_SERVER_PORT) { +export default function createContentServer(port = DEFAULT_CONTENT_SERVER_PORT) { const server = createServer(function (req, res) { if (routeObj[req.url] == null) { res.setHeader("Content-Type", "text/plain"); @@ -143,10 +143,3 @@ function parseRangeHeader(rangeHeader, dataLength) { } return [rangesNb[0], rangesNb[1]]; } -/** Default export that returns a teardown function that is executed by - * Vitest on test run - * @see https://vitest.dev/config/#globalsetup - * */ -export default () => { - createContentServer(); -}; diff --git a/tests/globalSetup.mjs b/tests/globalSetup.mjs new file mode 100644 index 0000000000..f608e25a8d --- /dev/null +++ b/tests/globalSetup.mjs @@ -0,0 +1,43 @@ +import createContentServer from "./contents/server.mjs"; + +const realConsoleWarn = console.warn; +let contentServer; + +/** + * Peform actions we want to setup before tests. + */ +export function setup() { + removeAnnoyingDeprecationNotice(); + contentServer = createContentServer(); +} + +/** + * Peform actions to clean-up after tests. + */ +export function teardown() { + contentServer?.close(); +} + +/** + * Webdriverio just spams a deprecation notice with the current version of + * vitest (one per test, though as we have thousands of tests, it just fills the + * output into something unreadable). + * + * This is so annoying that I just chose to mute it by monkey-patching the + * console function here. + * + * This should hopefully be very temporary. + */ +function removeAnnoyingDeprecationNotice() { + console.warn = function (...args) { + if ( + typeof args[0] === "string" && + args[0].startsWith( + '⚠️ [WEBDRIVERIO DEPRECATION NOTICE] The "switchToFrame" command is deprecated and we encourage everyone to use `switchFrame` instead for switching into frames.', + ) + ) { + return; + } + return realConsoleWarn.apply(console, args); + }; +} diff --git a/vitest.config.mjs b/vitest.config.mjs index 75afe7c366..7845bf48e2 100644 --- a/vitest.config.mjs +++ b/vitest.config.mjs @@ -26,6 +26,7 @@ function getBrowserConfig(browser) { name: "chrome", provider: "webdriverio", headless: true, + screenshotFailures: false, providerOptions: { capabilities: { "goog:chromeOptions": { @@ -45,6 +46,7 @@ function getBrowserConfig(browser) { name: "firefox", provider: "webdriverio", headless: true, + screenshotFailures: false, providerOptions: { capabilities: { "moz:firefoxOptions": { @@ -90,9 +92,17 @@ export default defineConfig({ watch: false, globals: false, reporters: "dot", - include: ["tests/**/*.[jt]s?(x)"], - exclude: ["tests/performance/**/*.[jt]s?(x)"], - globalSetup: "tests/contents/server.mjs", - browser: getBrowserConfig(process.env.BROWSER_CONFIG), + include: [ + // integration tests + "tests/integration/scenarios/**/*.[jt]s?(x)", + "tests/integration/**/*.test.[jt]s?(x)", + // memory tests + "tests/memory/**/*.[jt]s?(x)", + // unit tests + "src/**/__tests__/*.[jt]s?(x)", + "src/**/*.test.[jt]s?(x)", + ], + globalSetup: "tests/globalSetup.mjs", + browser: getBrowserConfig(process.env.BROWSER_CONFIG ?? "chrome"), }, }); diff --git a/vitest.config.unit.mjs b/vitest.config.unit.mjs deleted file mode 100644 index 7aa35f109c..0000000000 --- a/vitest.config.unit.mjs +++ /dev/null @@ -1,24 +0,0 @@ -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - define: { - // global variables - __ENVIRONMENT__: { - PRODUCTION: 0, - DEV: 1, - CURRENT_ENV: 1, - }, - __LOGGER_LEVEL__: { - CURRENT_LEVEL: '"NONE"', - }, - }, - test: { - watch: process.env.WATCH === "true", - reporters: "dot", - include: ["src/**/*.test.ts", "src/__tests__/**/*.ts"], - environment: "jsdom", - - // Force explicit imports - globals: false, - }, -});