Skip to content

Commit dad19e1

Browse files
committed
[WIP] Switch unit tests to use vitest
To extrapolate on #1444, this PR shows how it would look like to switch from relying on Jest to rely on vitest for our unit tests. The end goal being to simplify our codebase by relying on a single testing framework. --- I only done so for testing files in the `src/compat` directory in this demo. It can be tested right now by calling `npm run test:unit:vitest`. --- Sadly for now, we are still forced to rely on a JSDom-ed Node.js environment for unit tests and a browser environment for integration tests - meaning we have very different configs for both. This is because we want to mock imported files in unit tests - something that is not possible for now in browser environment through vitest (though vitest-dev/vitest#5765 seems to have been merged very recently so maybe we could rely on the browser for both soon), yet we want to replicate as much as a real browser as possible in our integration tests (because we're also testing that media playback on the tested browsers goes as expected).
1 parent 7f6a8fe commit dad19e1

28 files changed

+407
-646
lines changed

.eslintrc.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,9 @@ module.exports = {
199199
"import/no-extraneous-dependencies": [
200200
"error",
201201
{
202-
devDependencies: false,
202+
// TODO This one is to make it work with unit tests.
203+
// Perhaps a better solution could be a different config for both?
204+
devDependencies: true,
203205
},
204206
],
205207
"import/no-internal-modules": "off",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@
175175
"standalone": "node ./scripts/run_standalone_demo.mjs",
176176
"start": "node ./scripts/start_demo_web_server.mjs",
177177
"start:wasm": "node ./scripts/start_demo_web_server.mjs --include-wasm",
178+
"test:unit:vitest": "vitest --config vitest.config.unit.mjs",
178179
"test:vitest": "node ./tests/integration/run_vitest.mjs",
179-
"vitest": "vitest",
180180
"test:integration": "vitest tests/integration",
181181
"test:integration:chrome": "node tests/integration/run.mjs --bchrome",
182182
"test:integration:chrome:watch": "node tests/integration/run.mjs --bchrome --watch",

src/compat/__tests__/add_text_track.test.ts

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,66 @@
1-
/**
2-
* Copyright 2015 CANAL+ Group
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
1+
import { describe, beforeEach, it, expect, vi } from "vitest";
162

17-
// Needed for calling require (which itself is needed to mock properly) because
3+
// Needed for calling require (which itself is needed to doMock properly) because
184
// it is not type-checked:
195
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
206
/* eslint-disable @typescript-eslint/no-var-requires */
217
/* eslint-disable @typescript-eslint/no-unsafe-call */
228
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
239
/* eslint-disable @typescript-eslint/no-unsafe-argument */
10+
/* eslint-disable @typescript-eslint/no-explicit-any */
2411

2512
describe("compat - addTextTrack", () => {
2613
beforeEach(() => {
27-
jest.resetModules();
14+
vi.resetModules();
2815
});
2916

30-
it("should re-use text track on IE / EDGE", () => {
17+
it("should re-use text track on IE / EDGE", async () => {
3118
const fakeTextTrack = {
3219
id: "textTrack1",
3320
HIDDEN: "hidden",
3421
SHOWING: "showing",
3522
} as unknown as TextTrack;
36-
const mockAddTextTrack = jest.fn(() => null);
23+
const mockAddTextTrack = vi.fn(() => null);
3724
const fakeMediaElement = {
3825
textTracks: [fakeTextTrack],
3926
addTextTrack: mockAddTextTrack,
40-
};
27+
} as unknown as HTMLMediaElement;
4128

42-
jest.mock("../browser_detection", () => ({
29+
vi.doMock("../browser_detection", () => ({
4330
__esModule: true as const,
4431
isIEOrEdge: true,
4532
}));
46-
47-
const addTextTrack = jest.requireActual("../add_text_track").default;
33+
const { default: addTextTrack } = (await vi.importActual("../add_text_track")) as any;
4834
const { track, trackElement } = addTextTrack(fakeMediaElement);
4935
expect(trackElement).toBe(undefined);
5036
expect(track).toBe(fakeTextTrack);
5137
expect(track.mode).toBe("showing");
5238
expect(mockAddTextTrack).not.toHaveBeenCalled();
5339
});
5440

55-
it("should add text track if no track on media element on IE / EDGE", () => {
41+
it("should add text track if no track on media element on IE / EDGE", async () => {
5642
const fakeTextTrack = {
5743
id: "textTrack1",
5844
HIDDEN: "hidden",
5945
SHOWING: "showing",
6046
} as unknown as TextTrack;
6147
const fakeTextTracks: TextTrack[] = [];
62-
const mockAddTextTrack = jest.fn(() => {
48+
const mockAddTextTrack = vi.fn(() => {
6349
fakeTextTracks.push(fakeTextTrack);
6450
return fakeTextTrack;
6551
});
6652

6753
const fakeMediaElement = {
6854
textTracks: fakeTextTracks,
6955
addTextTrack: mockAddTextTrack,
70-
};
56+
} as unknown as HTMLMediaElement;
7157

72-
jest.mock("../browser_detection", () => ({
58+
vi.doMock("../browser_detection", () => ({
7359
__esModule: true as const,
7460
isIEOrEdge: true,
7561
}));
7662

77-
const addTextTrack = jest.requireActual("../add_text_track").default;
63+
const { default: addTextTrack } = (await vi.importActual("../add_text_track")) as any;
7864
const { track, trackElement } = addTextTrack(fakeMediaElement);
7965
expect(trackElement).toBe(undefined);
8066
expect(track).toBe(fakeTextTrack);
@@ -84,11 +70,12 @@ describe("compat - addTextTrack", () => {
8470
expect(mockAddTextTrack).toHaveBeenCalledTimes(1);
8571
});
8672

87-
it("should create showing trackElement and set track on mediaElement", () => {
88-
jest.mock("../browser_detection", () => ({
73+
it("should create showing trackElement and set track on mediaElement", async () => {
74+
vi.doMock("../browser_detection", () => ({
8975
__esModule: true as const,
9076
isIEOrEdge: false,
9177
}));
78+
const { default: addTextTrack } = (await vi.importActual("../add_text_track")) as any;
9279

9380
const fakeTextTrack = {
9481
id: "textTrack1",
@@ -103,7 +90,7 @@ describe("compat - addTextTrack", () => {
10390
const fakeTextTracks: TextTrack[] = [];
10491
const fakeChildNodes: ChildNode[] = [];
10592

106-
const mockAppendChild = jest.fn((_trackElement) => {
93+
const mockAppendChild = vi.fn((_trackElement) => {
10794
fakeChildNodes.push(_trackElement);
10895
fakeTextTracks.push(_trackElement.track);
10996
});
@@ -112,13 +99,12 @@ describe("compat - addTextTrack", () => {
11299
textTracks: fakeTextTracks,
113100
appendChild: mockAppendChild,
114101
childNodes: fakeChildNodes,
115-
};
102+
} as unknown as HTMLMediaElement;
116103

117-
const spyOnCreateElement = jest
104+
const spyOnCreateElement = vi
118105
.spyOn(document, "createElement")
119106
.mockImplementation(() => fakeTextTrackElement as unknown as HTMLElement);
120107

121-
const addTextTrack = jest.requireActual("../add_text_track").default;
122108
const { track, trackElement } = addTextTrack(fakeMediaElement);
123109
expect(track).toBe(fakeTextTrack);
124110
expect(track.mode).toBe("showing");

src/compat/__tests__/browser_compatibility_types.test.ts

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,7 @@
1-
/**
2-
* Copyright 2015 CANAL+ Group
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
16-
1+
import { describe, beforeEach, it, expect, vi } from "vitest";
172
import globalScope from "../../utils/global_scope";
183

19-
// Needed for calling require (which itself is needed to mock properly) because
4+
// Needed for calling require (which itself is needed to doMock properly) because
205
// it is not type-checked:
216
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
227
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
@@ -34,11 +19,11 @@ describe("compat - browser compatibility types", () => {
3419
}
3520
const gs = globalScope as IFakeWindow;
3621
beforeEach(() => {
37-
jest.resetModules();
22+
vi.resetModules();
3823
});
3924

40-
it("should use the native MediaSource if defined", () => {
41-
jest.mock("../../utils/is_node", () => ({
25+
it("should use the native MediaSource if defined", async () => {
26+
vi.doMock("../../utils/is_node", () => ({
4227
__esModule: true as const,
4328
default: false,
4429
}));
@@ -53,7 +38,7 @@ describe("compat - browser compatibility types", () => {
5338
gs.WebKitMediaSource = { a: 3 };
5439
gs.MSMediaSource = { a: 4 };
5540

56-
const { MediaSource_ } = jest.requireActual("../browser_compatibility_types");
41+
const { MediaSource_ } = await vi.importActual("../browser_compatibility_types");
5742
expect(MediaSource_).toEqual({ a: 1 });
5843

5944
gs.MediaSource = origMediaSource;
@@ -62,8 +47,8 @@ describe("compat - browser compatibility types", () => {
6247
gs.MSMediaSource = origMSMediaSource;
6348
});
6449

65-
it("should use MozMediaSource if defined and MediaSource is not", () => {
66-
jest.mock("../../utils/is_node", () => ({
50+
it("should use MozMediaSource if defined and MediaSource is not", async () => {
51+
vi.doMock("../../utils/is_node", () => ({
6752
__esModule: true as const,
6853
default: false,
6954
}));
@@ -78,7 +63,7 @@ describe("compat - browser compatibility types", () => {
7863
gs.WebKitMediaSource = undefined;
7964
gs.MSMediaSource = undefined;
8065

81-
const { MediaSource_ } = jest.requireActual("../browser_compatibility_types");
66+
const { MediaSource_ } = await vi.importActual("../browser_compatibility_types");
8267
expect(MediaSource_).toEqual({ a: 2 });
8368

8469
gs.MediaSource = origMediaSource;
@@ -87,8 +72,8 @@ describe("compat - browser compatibility types", () => {
8772
gs.MSMediaSource = origMSMediaSource;
8873
});
8974

90-
it("should use WebKitMediaSource if defined and MediaSource is not", () => {
91-
jest.mock("../../utils/is_node", () => ({
75+
it("should use WebKitMediaSource if defined and MediaSource is not", async () => {
76+
vi.doMock("../../utils/is_node", () => ({
9277
__esModule: true as const,
9378
default: false,
9479
}));
@@ -103,7 +88,7 @@ describe("compat - browser compatibility types", () => {
10388
gs.WebKitMediaSource = { a: 3 };
10489
gs.MSMediaSource = undefined;
10590

106-
const { MediaSource_ } = jest.requireActual("../browser_compatibility_types");
91+
const { MediaSource_ } = await vi.importActual("../browser_compatibility_types");
10792
expect(MediaSource_).toEqual({ a: 3 });
10893

10994
gs.MediaSource = origMediaSource;
@@ -112,8 +97,8 @@ describe("compat - browser compatibility types", () => {
11297
gs.MSMediaSource = origMSMediaSource;
11398
});
11499

115-
it("should use MSMediaSource if defined and MediaSource is not", () => {
116-
jest.mock("../../utils/is_node", () => ({
100+
it("should use MSMediaSource if defined and MediaSource is not", async () => {
101+
vi.doMock("../../utils/is_node", () => ({
117102
__esModule: true as const,
118103
default: false,
119104
}));
@@ -128,7 +113,7 @@ describe("compat - browser compatibility types", () => {
128113
gs.WebKitMediaSource = undefined;
129114
gs.MSMediaSource = { a: 4 };
130115

131-
const { MediaSource_ } = jest.requireActual("../browser_compatibility_types");
116+
const { MediaSource_ } = await vi.importActual("../browser_compatibility_types");
132117
expect(MediaSource_).toEqual({ a: 4 });
133118

134119
gs.MediaSource = origMediaSource;

src/compat/__tests__/browser_version.test.ts

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,4 @@
1-
/**
2-
* Copyright 2015 CANAL+ Group
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
1+
import { describe, afterEach, it, expect, vi } from "vitest";
162

173
/* eslint-disable @typescript-eslint/no-unsafe-call */
184
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
@@ -42,43 +28,43 @@ describe("Compat - Browser version", () => {
4228

4329
afterEach(() => {
4430
nav.userAgent = origUserAgent;
45-
jest.resetModules();
31+
vi.resetModules();
4632
});
4733

48-
it("Should return correct Firefox version (60)", () => {
49-
jest.mock("../browser_detection", () => {
34+
it("Should return correct Firefox version (60)", async () => {
35+
vi.doMock("../browser_detection", () => {
5036
return { __esModule: true as const, isFirefox: true };
5137
});
52-
const { getFirefoxVersion } = jest.requireActual("../browser_version");
38+
const { getFirefoxVersion } = await vi.importActual("../browser_version");
5339
nav.userAgent = "Firefox/60.0";
5440
const version = getFirefoxVersion();
5541
expect(version).toBe(60);
5642
});
5743

58-
it("Should return correct Firefox version (80)", () => {
59-
jest.mock("../browser_detection", () => {
44+
it("Should return correct Firefox version (80)", async () => {
45+
vi.doMock("../browser_detection", () => {
6046
return { __esModule: true as const, isFirefox: true };
6147
});
62-
const { getFirefoxVersion } = jest.requireActual("../browser_version");
48+
const { getFirefoxVersion } = await vi.importActual("../browser_version");
6349
nav.userAgent = "Firefox/80.0";
6450
const version = getFirefoxVersion();
6551
expect(version).toBe(80);
6652
});
6753

68-
it("Should return null when not on Firefox", () => {
69-
jest.mock("../browser_detection", () => {
54+
it("Should return null when not on Firefox", async () => {
55+
vi.doMock("../browser_detection", () => {
7056
return { __esModule: true as const, isFirefox: false };
7157
});
72-
const { getFirefoxVersion } = jest.requireActual("../browser_version");
58+
const { getFirefoxVersion } = await vi.importActual("../browser_version");
7359
const version = getFirefoxVersion();
7460
expect(version).toBe(null);
7561
});
7662

77-
it("Should return null when obscure Firefox user agent", () => {
78-
jest.mock("../browser_detection", () => {
63+
it("Should return null when obscure Firefox user agent", async () => {
64+
vi.doMock("../browser_detection", () => {
7965
return { __esModule: true as const, isFirefox: true };
8066
});
81-
const { getFirefoxVersion } = jest.requireActual("../browser_version");
67+
const { getFirefoxVersion } = await vi.importActual("../browser_version");
8268
nav.userAgent = "FireFennec/80.0";
8369
const version = getFirefoxVersion();
8470
expect(version).toBe(-1);
Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,4 @@
1-
/**
2-
* Copyright 2015 CANAL+ Group
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
1+
import { describe, beforeEach, it, expect, vi } from "vitest";
162

173
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
184
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
@@ -23,28 +9,28 @@
239

2410
describe("compat - canPatchISOBMFFSegment", () => {
2511
beforeEach(() => {
26-
jest.resetModules();
12+
vi.resetModules();
2713
});
2814

29-
it("should return true if we are not on IE11 nor Edge", () => {
30-
jest.mock("../browser_detection", () => {
15+
it("should return true if we are not on IE11 nor Edge", async () => {
16+
vi.doMock("../browser_detection", () => {
3117
return {
3218
__esModule: true as const,
3319
isIEOrEdge: false,
3420
};
3521
});
36-
const canPatchISOBMFFSegment = jest.requireActual("../can_patch_isobmff");
22+
const canPatchISOBMFFSegment = await vi.importActual("../can_patch_isobmff");
3723
expect(canPatchISOBMFFSegment.default()).toBe(true);
3824
});
3925

40-
it("should return false if we are on IE11 or Edge", () => {
41-
jest.mock("../browser_detection", () => {
26+
it("should return false if we are on IE11 or Edge", async () => {
27+
vi.doMock("../browser_detection", () => {
4228
return {
4329
__esModule: true as const,
4430
isIEOrEdge: true,
4531
};
4632
});
47-
const canPatchISOBMFFSegment = jest.requireActual("../can_patch_isobmff");
33+
const canPatchISOBMFFSegment = await vi.importActual("../can_patch_isobmff");
4834
expect(canPatchISOBMFFSegment.default()).toBe(false);
4935
});
5036
});

0 commit comments

Comments
 (0)