Use vitest for some EW unit tests (#33816)
* Use vitest for some EW unit tests * Ensure library builds are done before unit tests * Stabilise jest tests * Move more tests over * Make sonar happier * Update types/node for happy-dom compat again * Decrease max-workers to stabilise jest tests * Split jest over 3 runners to alleviate memory woes * Switch jest to runInBand * Attempt to deflake jest tests * tweak coverage * tweak coverage
This commit is contained in:
committed by
GitHub
parent
7949980a7e
commit
2f4e6a4ec4
@@ -232,7 +232,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["test/**/*.{ts,tsx}", "playwright/**/*.ts"],
|
||||
files: ["src/**/*.test.{ts,tsx}", "test/**/*.{ts,tsx}", "playwright/**/*.ts"],
|
||||
extends: ["plugin:matrix-org/jest"],
|
||||
rules: {
|
||||
// We don't need super strict typing in test utilities
|
||||
|
||||
@@ -52,16 +52,19 @@ const config: Config = {
|
||||
],
|
||||
collectCoverageFrom: [
|
||||
"<rootDir>/src/**/*.{js,ts,tsx}",
|
||||
"<rootDir>/packages/**/*.{js,ts,tsx}",
|
||||
// getSessionLock is piped into a different JS context via stringification, and the coverage functionality is
|
||||
// not available in that contest. So, turn off coverage instrumentation for it.
|
||||
"!<rootDir>/src/utils/SessionLock.ts",
|
||||
// Coverage chokes on type definition files
|
||||
"!<rootDir>/src/**/*.d.ts",
|
||||
// Ignore vitest tests
|
||||
"!<rootDir>/src/**/*.test.{ts,tsx}",
|
||||
"!<rootDir>/src/test/**",
|
||||
],
|
||||
coverageReporters: ["text-summary", ["lcov", { projectRoot: "../../" }]],
|
||||
prettierPath: null,
|
||||
moduleDirectories: ["node_modules", "test/test-utils"],
|
||||
workerIdleMemoryLimit: "512MB",
|
||||
};
|
||||
|
||||
// if we're running under GHA, enable relevant reporters
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"lint:types": "nx lint:types",
|
||||
"lint:style": "stylelint \"res/css/**/*.pcss\"",
|
||||
"test": "nx test:unit",
|
||||
"test:vitest": "nx test:vitest",
|
||||
"test:playwright": "nx test:playwright --",
|
||||
"test:playwright:open": "nx test:playwright -- --ui",
|
||||
"test:playwright:screenshots": "nx test:playwright:screenshots --",
|
||||
@@ -129,6 +130,7 @@
|
||||
"@element-hq/element-call-embedded": "0.20.1",
|
||||
"@element-hq/element-web-playwright-common": "workspace:*",
|
||||
"@fetch-mock/jest": "^0.2.20",
|
||||
"@fetch-mock/vitest": "^0.2.18",
|
||||
"@jest/globals": "^30.2.0",
|
||||
"@peculiar/webcrypto": "^1.4.3",
|
||||
"@playwright/test": "catalog:",
|
||||
@@ -190,6 +192,7 @@
|
||||
"express": "^5.0.0",
|
||||
"fake-indexeddb": "^6.0.0",
|
||||
"file-loader": "^6.0.0",
|
||||
"happy-dom": "^20.10.2",
|
||||
"html-webpack-plugin": "^5.5.3",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^30.0.0",
|
||||
@@ -226,6 +229,7 @@
|
||||
"testcontainers": "^12.0.0",
|
||||
"typescript": "catalog:",
|
||||
"util": "^0.12.5",
|
||||
"vitest": "catalog:",
|
||||
"web-streams-polyfill": "^4.0.0",
|
||||
"webpack": "^5.89.0",
|
||||
"webpack-bundle-analyzer": "^5.0.0",
|
||||
|
||||
+10
-1
@@ -46,11 +46,20 @@
|
||||
},
|
||||
"dependsOn": ["^build", "^build:playwright"]
|
||||
},
|
||||
"test:unit:prepare": {
|
||||
"executor": "nx:noop",
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"test:unit": {
|
||||
// We avoid the jest executor because it doesn't seem to give any benefit, and it mangles the summary of failing tests.
|
||||
"command": "jest",
|
||||
"options": { "cwd": "apps/web" },
|
||||
"dependsOn": ["^build"]
|
||||
"dependsOn": ["test:unit:prepare"]
|
||||
},
|
||||
"test:vitest": {
|
||||
"command": "vitest run",
|
||||
"options": { "cwd": "apps/web" },
|
||||
"dependsOn": ["test:unit:prepare"]
|
||||
},
|
||||
"test:playwright": {
|
||||
"command": "playwright test",
|
||||
|
||||
@@ -5,9 +5,12 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import EventEmitter from "events";
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import UserActivity from "../../src/UserActivity";
|
||||
import { vi, describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||
import EventEmitter from "node:events";
|
||||
|
||||
import UserActivity from "./UserActivity";
|
||||
|
||||
class FakeDomEventEmitter extends EventEmitter {
|
||||
addEventListener(what: string, l: (...args: any[]) => void) {
|
||||
@@ -29,7 +32,7 @@ describe("UserActivity", function () {
|
||||
fakeDocument = new FakeDomEventEmitter();
|
||||
userActivity = new UserActivity(fakeWindow as unknown as Window, fakeDocument as unknown as Document);
|
||||
userActivity.start();
|
||||
jest.useFakeTimers();
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
@@ -49,7 +52,7 @@ describe("UserActivity", function () {
|
||||
});
|
||||
|
||||
it("should not consider user active after activity if no window focus", function () {
|
||||
fakeDocument.hasFocus = jest.fn().mockReturnValue(false);
|
||||
fakeDocument.hasFocus = vi.fn().mockReturnValue(false);
|
||||
|
||||
userActivity.onUserActivity({ type: "event" } as Event);
|
||||
expect(userActivity.userActiveNow()).toBe(false);
|
||||
@@ -57,62 +60,62 @@ describe("UserActivity", function () {
|
||||
});
|
||||
|
||||
it("should consider user active shortly after activity", function () {
|
||||
fakeDocument.hasFocus = jest.fn().mockReturnValue(true);
|
||||
fakeDocument.hasFocus = vi.fn().mockReturnValue(true);
|
||||
|
||||
userActivity.onUserActivity({ type: "event" } as Event);
|
||||
expect(userActivity.userActiveNow()).toBe(true);
|
||||
expect(userActivity.userActiveRecently()).toBe(true);
|
||||
jest.advanceTimersByTime(200);
|
||||
vi.advanceTimersByTime(200);
|
||||
expect(userActivity.userActiveNow()).toBe(true);
|
||||
expect(userActivity.userActiveRecently()).toBe(true);
|
||||
});
|
||||
|
||||
it("should consider user not active after 10s of no activity", function () {
|
||||
fakeDocument.hasFocus = jest.fn().mockReturnValue(true);
|
||||
fakeDocument.hasFocus = vi.fn().mockReturnValue(true);
|
||||
|
||||
userActivity.onUserActivity({ type: "event" } as Event);
|
||||
jest.advanceTimersByTime(10000);
|
||||
vi.advanceTimersByTime(10000);
|
||||
expect(userActivity.userActiveNow()).toBe(false);
|
||||
});
|
||||
|
||||
it("should consider user passive after 10s of no activity", function () {
|
||||
fakeDocument.hasFocus = jest.fn().mockReturnValue(true);
|
||||
fakeDocument.hasFocus = vi.fn().mockReturnValue(true);
|
||||
|
||||
userActivity.onUserActivity({ type: "event" } as Event);
|
||||
jest.advanceTimersByTime(10000);
|
||||
vi.advanceTimersByTime(10000);
|
||||
expect(userActivity.userActiveRecently()).toBe(true);
|
||||
});
|
||||
|
||||
it("should not consider user passive after 10s if window un-focused", function () {
|
||||
fakeDocument.hasFocus = jest.fn().mockReturnValue(true);
|
||||
fakeDocument.hasFocus = vi.fn().mockReturnValue(true);
|
||||
|
||||
userActivity.onUserActivity({ type: "event" } as Event);
|
||||
jest.advanceTimersByTime(10000);
|
||||
vi.advanceTimersByTime(10000);
|
||||
|
||||
fakeDocument.hasFocus = jest.fn().mockReturnValue(false);
|
||||
fakeDocument.hasFocus = vi.fn().mockReturnValue(false);
|
||||
fakeWindow.emit("blur", {});
|
||||
|
||||
expect(userActivity.userActiveRecently()).toBe(false);
|
||||
});
|
||||
|
||||
it("should not consider user passive after 3 mins", function () {
|
||||
fakeDocument.hasFocus = jest.fn().mockReturnValue(true);
|
||||
fakeDocument.hasFocus = vi.fn().mockReturnValue(true);
|
||||
|
||||
userActivity.onUserActivity({ type: "event" } as Event);
|
||||
jest.advanceTimersByTime(3 * 60 * 1000);
|
||||
vi.advanceTimersByTime(3 * 60 * 1000);
|
||||
|
||||
expect(userActivity.userActiveRecently()).toBe(false);
|
||||
});
|
||||
|
||||
it("should extend timer on activity", function () {
|
||||
fakeDocument.hasFocus = jest.fn().mockReturnValue(true);
|
||||
fakeDocument.hasFocus = vi.fn().mockReturnValue(true);
|
||||
|
||||
userActivity.onUserActivity({ type: "event" } as Event);
|
||||
jest.advanceTimersByTime(1 * 60 * 1000);
|
||||
vi.advanceTimersByTime(1 * 60 * 1000);
|
||||
userActivity.onUserActivity({ type: "event" } as Event);
|
||||
jest.advanceTimersByTime(1 * 60 * 1000);
|
||||
vi.advanceTimersByTime(1 * 60 * 1000);
|
||||
userActivity.onUserActivity({ type: "event" } as Event);
|
||||
jest.advanceTimersByTime(1 * 60 * 1000);
|
||||
vi.advanceTimersByTime(1 * 60 * 1000);
|
||||
|
||||
expect(userActivity.userActiveRecently()).toBe(true);
|
||||
});
|
||||
@@ -6,11 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { WorkerManager } from "../../src/WorkerManager";
|
||||
import { vi, describe, it, expect } from "vitest";
|
||||
|
||||
import { WorkerManager } from "./WorkerManager";
|
||||
|
||||
describe("WorkerManager", () => {
|
||||
it("should generate consecutive sequence numbers for each call", () => {
|
||||
const postMessage = jest.fn();
|
||||
const postMessage = vi.fn();
|
||||
const manager = new WorkerManager({ postMessage } as unknown as Worker);
|
||||
|
||||
manager.call({ data: "One" });
|
||||
@@ -27,7 +29,7 @@ describe("WorkerManager", () => {
|
||||
});
|
||||
|
||||
it("should support resolving out of order", async () => {
|
||||
const postMessage = jest.fn();
|
||||
const postMessage = vi.fn();
|
||||
const worker = { postMessage } as unknown as Worker;
|
||||
const manager = new WorkerManager(worker);
|
||||
|
||||
@@ -6,7 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { looksValid } from "../../src/email";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { looksValid } from "./email";
|
||||
|
||||
describe("looksValid", () => {
|
||||
it.each([
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { beforeEach } from "vitest";
|
||||
import fetchMock, { manageFetchMockGlobally } from "@fetch-mock/vitest";
|
||||
|
||||
manageFetchMockGlobally();
|
||||
|
||||
beforeEach(() => {
|
||||
// set up fetch API mock
|
||||
fetchMock.hardReset();
|
||||
fetchMock.catch(404);
|
||||
fetchMock.mockGlobal();
|
||||
});
|
||||
+3
-1
@@ -6,7 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { lerp } from "../../../src/utils/AnimationUtils";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { lerp } from "./AnimationUtils";
|
||||
|
||||
describe("lerp", () => {
|
||||
it("correctly interpolates", () => {
|
||||
+3
-1
@@ -6,7 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { FixedRollingArray } from "../../../src/utils/FixedRollingArray";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { FixedRollingArray } from "./FixedRollingArray";
|
||||
|
||||
describe("FixedRollingArray", () => {
|
||||
it("should seed the array with the given value", () => {
|
||||
@@ -6,10 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
import { blobIsAnimated, mayBeAnimated } from "../../src/utils/Image";
|
||||
import { blobIsAnimated, mayBeAnimated } from "./Image";
|
||||
|
||||
const imagesDir = path.resolve(__dirname, "../../test/unit-tests/images");
|
||||
|
||||
describe("Image", () => {
|
||||
describe("mayBeAnimated", () => {
|
||||
@@ -32,28 +35,28 @@ describe("Image", () => {
|
||||
|
||||
describe("blobIsAnimated", () => {
|
||||
it("Animated GIF", async () => {
|
||||
const img = new Blob([fs.readFileSync(path.resolve(__dirname, "images", "animated-logo.gif")).slice()], {
|
||||
const img = new Blob([fs.readFileSync(path.resolve(imagesDir, "animated-logo.gif")).slice()], {
|
||||
type: "image/gif",
|
||||
});
|
||||
expect(await blobIsAnimated(img)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("Static GIF", async () => {
|
||||
const img = new Blob([fs.readFileSync(path.resolve(__dirname, "images", "static-logo.gif")).slice()], {
|
||||
const img = new Blob([fs.readFileSync(path.resolve(imagesDir, "static-logo.gif")).slice()], {
|
||||
type: "image/gif",
|
||||
});
|
||||
expect(await blobIsAnimated(img)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("Animated WEBP", async () => {
|
||||
const img = new Blob([fs.readFileSync(path.resolve(__dirname, "images", "animated-logo.webp")).slice()], {
|
||||
const img = new Blob([fs.readFileSync(path.resolve(imagesDir, "animated-logo.webp")).slice()], {
|
||||
type: "image/webp",
|
||||
});
|
||||
expect(await blobIsAnimated(img)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("Static WEBP", async () => {
|
||||
const img = new Blob([fs.readFileSync(path.resolve(__dirname, "images", "static-logo.webp")).slice()], {
|
||||
const img = new Blob([fs.readFileSync(path.resolve(imagesDir, "static-logo.webp")).slice()], {
|
||||
type: "image/webp",
|
||||
});
|
||||
expect(await blobIsAnimated(img)).toBeFalsy();
|
||||
@@ -61,14 +64,14 @@ describe("Image", () => {
|
||||
|
||||
it("Static WEBP in extended file format", async () => {
|
||||
const img = new Blob(
|
||||
[fs.readFileSync(path.resolve(__dirname, "images", "static-logo-extended-file-format.webp")).slice()],
|
||||
[fs.readFileSync(path.resolve(imagesDir, "static-logo-extended-file-format.webp")).slice()],
|
||||
{ type: "image/webp" },
|
||||
);
|
||||
expect(await blobIsAnimated(img)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("Animated PNG", async () => {
|
||||
const img = new Blob([fs.readFileSync(path.resolve(__dirname, "images", "animated-logo.apng")).slice()]);
|
||||
const img = new Blob([fs.readFileSync(path.resolve(imagesDir, "animated-logo.apng")).slice()]);
|
||||
const pngBlob = img.slice(0, img.size, "image/png");
|
||||
const apngBlob = img.slice(0, img.size, "image/apng");
|
||||
expect(await blobIsAnimated(pngBlob)).toBeTruthy();
|
||||
@@ -76,7 +79,7 @@ describe("Image", () => {
|
||||
});
|
||||
|
||||
it("Static PNG", async () => {
|
||||
const img = new Blob([fs.readFileSync(path.resolve(__dirname, "images", "static-logo.png")).slice()]);
|
||||
const img = new Blob([fs.readFileSync(path.resolve(imagesDir, "static-logo.png")).slice()]);
|
||||
const pngBlob = img.slice(0, img.size, "image/png");
|
||||
const apngBlob = img.slice(0, img.size, "image/apng");
|
||||
expect(await blobIsAnimated(pngBlob)).toBeFalsy();
|
||||
+5
-8
@@ -6,21 +6,18 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { vi, describe, it, expect, beforeEach } from "vitest";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import { LruCache } from "../../../src/utils/LruCache";
|
||||
import { LruCache } from "./LruCache";
|
||||
|
||||
describe("LruCache", () => {
|
||||
it("when creating a cache with negative capacity it should raise an error", () => {
|
||||
expect(() => {
|
||||
new LruCache(-23);
|
||||
}).toThrow("Cache capacity must be at least 1");
|
||||
expect(() => new LruCache(-23)).toThrow("Cache capacity must be at least 1");
|
||||
});
|
||||
|
||||
it("when creating a cache with 0 capacity it should raise an error", () => {
|
||||
expect(() => {
|
||||
new LruCache(0);
|
||||
}).toThrow("Cache capacity must be at least 1");
|
||||
expect(() => new LruCache(0)).toThrow("Cache capacity must be at least 1");
|
||||
});
|
||||
|
||||
describe("when there is a cache with a capacity of 3", () => {
|
||||
@@ -72,7 +69,7 @@ describe("LruCache", () => {
|
||||
});
|
||||
|
||||
it("when an error occurs while setting an item the cache should be cleard", () => {
|
||||
jest.spyOn(logger, "warn");
|
||||
vi.spyOn(logger, "warn");
|
||||
const err = new Error("Something weng wrong :(");
|
||||
|
||||
// @ts-ignore
|
||||
+3
-1
@@ -6,7 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { doesRoomVersionSupport, PreferredRoomVersions } from "../../src/utils/PreferredRoomVersions";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { doesRoomVersionSupport, PreferredRoomVersions } from "./PreferredRoomVersions";
|
||||
|
||||
describe("doesRoomVersionSupport", () => {
|
||||
it("should detect unstable as unsupported", () => {
|
||||
+3
-1
@@ -6,7 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { SnakedObject, snakeToCamel } from "../../../src/utils/SnakedObject";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { SnakedObject, snakeToCamel } from "./SnakedObject";
|
||||
|
||||
describe("snakeToCamel", () => {
|
||||
it("should convert snake_case to camelCase in simple scenarios", () => {
|
||||
+5
-1
@@ -6,7 +6,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { abbreviateUrl, parseUrl, unabbreviateUrl } from "../../../src/utils/UrlUtils";
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { abbreviateUrl, parseUrl, unabbreviateUrl } from "./UrlUtils";
|
||||
|
||||
describe("abbreviateUrl", () => {
|
||||
it("should return empty string if passed falsey", () => {
|
||||
@@ -6,6 +6,8 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { vi, describe, it, expect } from "vitest";
|
||||
|
||||
import {
|
||||
arrayDiff,
|
||||
arrayFastClone,
|
||||
@@ -25,7 +27,7 @@ import {
|
||||
asyncSome,
|
||||
asyncSomeParallel,
|
||||
asyncFilter,
|
||||
} from "../../../src/utils/arrays";
|
||||
} from "./arrays";
|
||||
|
||||
type TestParams = { input: number[]; output: number[] };
|
||||
type TestCase = [string, TestParams];
|
||||
@@ -412,11 +414,11 @@ describe("arrays", () => {
|
||||
|
||||
describe("asyncEvery", () => {
|
||||
it("when called with an empty array, it should return true", async () => {
|
||||
expect(await asyncEvery([], jest.fn().mockResolvedValue(true))).toBe(true);
|
||||
expect(await asyncEvery([], vi.fn().mockResolvedValue(true))).toBe(true);
|
||||
});
|
||||
|
||||
it("when called with some items and the predicate resolves to true for all of them, it should return true", async () => {
|
||||
const predicate = jest.fn().mockResolvedValue(true);
|
||||
const predicate = vi.fn().mockResolvedValue(true);
|
||||
expect(await asyncEvery([1, 2, 3], predicate)).toBe(true);
|
||||
expect(predicate).toHaveBeenCalledTimes(3);
|
||||
expect(predicate).toHaveBeenCalledWith(1);
|
||||
@@ -425,14 +427,14 @@ describe("arrays", () => {
|
||||
});
|
||||
|
||||
it("when called with some items and the predicate resolves to false for all of them, it should return false", async () => {
|
||||
const predicate = jest.fn().mockResolvedValue(false);
|
||||
const predicate = vi.fn().mockResolvedValue(false);
|
||||
expect(await asyncEvery([1, 2, 3], predicate)).toBe(false);
|
||||
expect(predicate).toHaveBeenCalledTimes(1);
|
||||
expect(predicate).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it("when called with some items and the predicate resolves to false for one of them, it should return false", async () => {
|
||||
const predicate = jest.fn().mockResolvedValueOnce(true).mockResolvedValueOnce(false);
|
||||
const predicate = vi.fn().mockResolvedValueOnce(true).mockResolvedValueOnce(false);
|
||||
expect(await asyncEvery([1, 2, 3], predicate)).toBe(false);
|
||||
expect(predicate).toHaveBeenCalledTimes(2);
|
||||
expect(predicate).toHaveBeenCalledWith(1);
|
||||
@@ -442,11 +444,11 @@ describe("arrays", () => {
|
||||
|
||||
describe("asyncSome", () => {
|
||||
it("when called with an empty array, it should return false", async () => {
|
||||
expect(await asyncSome([], jest.fn().mockResolvedValue(true))).toBe(false);
|
||||
expect(await asyncSome([], vi.fn().mockResolvedValue(true))).toBe(false);
|
||||
});
|
||||
|
||||
it("when called with some items and the predicate resolves to false for all of them, it should return false", async () => {
|
||||
const predicate = jest.fn().mockResolvedValue(false);
|
||||
const predicate = vi.fn().mockResolvedValue(false);
|
||||
expect(await asyncSome([1, 2, 3], predicate)).toBe(false);
|
||||
expect(predicate).toHaveBeenCalledTimes(3);
|
||||
expect(predicate).toHaveBeenCalledWith(1);
|
||||
@@ -455,7 +457,7 @@ describe("arrays", () => {
|
||||
});
|
||||
|
||||
it("when called with some items and the predicate resolves to true, it should short-circuit and return true", async () => {
|
||||
const predicate = jest.fn().mockResolvedValueOnce(false).mockResolvedValueOnce(true);
|
||||
const predicate = vi.fn().mockResolvedValueOnce(false).mockResolvedValueOnce(true);
|
||||
expect(await asyncSome([1, 2, 3], predicate)).toBe(true);
|
||||
expect(predicate).toHaveBeenCalledTimes(2);
|
||||
expect(predicate).toHaveBeenCalledWith(1);
|
||||
@@ -465,30 +467,30 @@ describe("arrays", () => {
|
||||
|
||||
describe("asyncSomeParallel", () => {
|
||||
it("when called with an empty array, it should return false", async () => {
|
||||
expect(await asyncSomeParallel([], jest.fn().mockResolvedValue(true))).toBe(false);
|
||||
expect(await asyncSomeParallel([], vi.fn().mockResolvedValue(true))).toBe(false);
|
||||
});
|
||||
|
||||
it("when all the predicates return false", async () => {
|
||||
expect(await asyncSomeParallel([1, 2, 3], jest.fn().mockResolvedValue(false))).toBe(false);
|
||||
expect(await asyncSomeParallel([1, 2, 3], vi.fn().mockResolvedValue(false))).toBe(false);
|
||||
});
|
||||
|
||||
it("when all the predicates return true", async () => {
|
||||
expect(await asyncSomeParallel([1, 2, 3], jest.fn().mockResolvedValue(true))).toBe(true);
|
||||
expect(await asyncSomeParallel([1, 2, 3], vi.fn().mockResolvedValue(true))).toBe(true);
|
||||
});
|
||||
|
||||
it("when one of the predicate return true", async () => {
|
||||
const predicate = jest.fn().mockImplementation((value) => Promise.resolve(value === 2));
|
||||
const predicate = vi.fn().mockImplementation((value) => Promise.resolve(value === 2));
|
||||
expect(await asyncSomeParallel([1, 2, 3], predicate)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("asyncFilter", () => {
|
||||
it("when called with an empty array, it should return an empty array", async () => {
|
||||
expect(await asyncFilter([], jest.fn().mockResolvedValue(true))).toEqual([]);
|
||||
expect(await asyncFilter([], vi.fn().mockResolvedValue(true))).toEqual([]);
|
||||
});
|
||||
|
||||
it("should filter the content", async () => {
|
||||
const predicate = jest.fn().mockImplementation((value) => Promise.resolve(value === 2));
|
||||
const predicate = vi.fn().mockImplementation((value) => Promise.resolve(value === 2));
|
||||
expect(await asyncFilter([1, 2, 3], predicate)).toEqual([2]);
|
||||
});
|
||||
});
|
||||
@@ -6,7 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { textToHtmlRainbow } from "../../../src/utils/colour";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { textToHtmlRainbow } from "./colour";
|
||||
|
||||
describe("textToHtmlRainbow", () => {
|
||||
it("correctly transform text to html without splitting the emoji in two", () => {
|
||||
+4
-3
@@ -6,16 +6,17 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { vi, describe, it, expect, beforeEach, type Mock } from "vitest";
|
||||
import { type ClientEvent, type ClientEventHandlerMap, SyncState } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { createReconnectedListener } from "../../../src/utils/connection";
|
||||
import { createReconnectedListener } from "./connection";
|
||||
|
||||
describe("createReconnectedListener", () => {
|
||||
let reconnectedListener: ClientEventHandlerMap[ClientEvent.Sync];
|
||||
let onReconnect: jest.Mock;
|
||||
let onReconnect: Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
onReconnect = jest.fn();
|
||||
onReconnect = vi.fn();
|
||||
reconnectedListener = createReconnectedListener(onReconnect);
|
||||
});
|
||||
|
||||
@@ -6,7 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { getEnumValues, isEnumValue } from "../../../src/utils/enums";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { getEnumValues, isEnumValue } from "./enums";
|
||||
|
||||
enum TestStringEnum {
|
||||
First = "__first__",
|
||||
+3
-1
@@ -6,7 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { iterableDiff, iterableIntersection } from "../../../src/utils/iterables";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { iterableDiff, iterableIntersection } from "./iterables";
|
||||
|
||||
describe("iterables", () => {
|
||||
describe("iterableIntersection", () => {
|
||||
+3
-1
@@ -5,7 +5,9 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { keepIfSame } from "../../../src/utils/keepIfSame";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { keepIfSame } from "./keepIfSame";
|
||||
|
||||
describe("keepIfSame", () => {
|
||||
it("returns the next value if the current and next values are not deeply equal", () => {
|
||||
@@ -6,6 +6,8 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import {
|
||||
objectClone,
|
||||
objectDiff,
|
||||
@@ -14,7 +16,7 @@ import {
|
||||
objectKeyChanges,
|
||||
objectShallowClone,
|
||||
objectWithOnly,
|
||||
} from "../../../src/utils/objects";
|
||||
} from "./objects";
|
||||
|
||||
describe("objects", () => {
|
||||
describe("objectExcluding", () => {
|
||||
+8
-6
@@ -6,9 +6,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { vi, describe, it, expect, beforeEach } from "vitest";
|
||||
import { type IdTokenClaims } from "oidc-client-ts";
|
||||
import { decodeIdToken } from "matrix-js-sdk/src/matrix";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import {
|
||||
getStoredOidcClientId,
|
||||
@@ -16,13 +18,13 @@ import {
|
||||
getStoredOidcIdTokenClaims,
|
||||
getStoredOidcTokenIssuer,
|
||||
persistOidcAuthenticatedSettings,
|
||||
} from "../../../../src/utils/oidc/persistOidcSettings";
|
||||
} from "./persistOidcSettings";
|
||||
|
||||
jest.mock("matrix-js-sdk/src/matrix");
|
||||
vi.mock("matrix-js-sdk/src/matrix");
|
||||
|
||||
describe("persist OIDC settings", () => {
|
||||
jest.spyOn(Storage.prototype, "getItem");
|
||||
jest.spyOn(Storage.prototype, "setItem");
|
||||
vi.spyOn(localStorage, "getItem");
|
||||
vi.spyOn(localStorage, "setItem");
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
@@ -101,7 +103,7 @@ describe("persist OIDC settings", () => {
|
||||
|
||||
it("should return claims extracted from id_token in localStorage", () => {
|
||||
localStorage.setItem("mx_oidc_id_token", idToken);
|
||||
mocked(decodeIdToken).mockReturnValue(idTokenClaims);
|
||||
vi.mocked(decodeIdToken).mockReturnValue(idTokenClaims);
|
||||
expect(getStoredOidcIdTokenClaims()).toEqual(idTokenClaims);
|
||||
expect(decodeIdToken).toHaveBeenCalledWith(idToken);
|
||||
expect(localStorage.getItem).toHaveBeenCalledWith("mx_oidc_id_token_claims");
|
||||
+3
-1
@@ -5,7 +5,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { getManageDeviceUrl } from "../../../../src/utils/oidc/urls";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { getManageDeviceUrl } from "./urls";
|
||||
|
||||
describe("OIDC urls", () => {
|
||||
const accountManagementEndpoint = "https://auth.com/manage";
|
||||
@@ -5,11 +5,13 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { batch } from "../../../src/utils/promise.ts";
|
||||
import { vi, describe, it, expect, afterEach } from "vitest";
|
||||
|
||||
import { batch } from "./promise.ts";
|
||||
|
||||
describe("promise.ts", () => {
|
||||
describe("batch", () => {
|
||||
afterEach(() => jest.useRealTimers());
|
||||
afterEach(() => vi.useRealTimers());
|
||||
|
||||
it("should batch promises into groups of a given size", async () => {
|
||||
const promises = [() => Promise.resolve(1), () => Promise.resolve(2), () => Promise.resolve(3)];
|
||||
@@ -19,7 +21,7 @@ describe("promise.ts", () => {
|
||||
});
|
||||
|
||||
it("should wait for the current batch to finish to request the next one", async () => {
|
||||
jest.useFakeTimers();
|
||||
vi.useFakeTimers();
|
||||
|
||||
let promise1Called = false;
|
||||
const promise1 = () =>
|
||||
@@ -49,7 +51,7 @@ describe("promise.ts", () => {
|
||||
expect(promise2Called).toBe(true);
|
||||
expect(promise3Called).toBe(false);
|
||||
|
||||
jest.advanceTimersByTime(11);
|
||||
vi.advanceTimersByTime(11);
|
||||
expect(await batchPromise).toEqual([1, 2, 3]);
|
||||
});
|
||||
});
|
||||
@@ -6,7 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { setHasDiff } from "../../../src/utils/sets";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { setHasDiff } from "./sets";
|
||||
|
||||
describe("sets", () => {
|
||||
describe("setHasDiff", () => {
|
||||
+2
-1
@@ -6,10 +6,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { sortBy } from "lodash";
|
||||
import { averageBetweenStrings, DEFAULT_ALPHABET } from "matrix-js-sdk/src/utils";
|
||||
|
||||
import { midPointsBetweenStrings, reorderLexicographically } from "../../../src/utils/stringOrderField";
|
||||
import { midPointsBetweenStrings, reorderLexicographically } from "./stringOrderField";
|
||||
|
||||
const moveLexicographicallyTest = (
|
||||
orders: Array<string | undefined>,
|
||||
+3
-1
@@ -6,7 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { validateNumberInRange } from "../../../../src/utils/validate";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { validateNumberInRange } from "./numberInRange";
|
||||
|
||||
describe("validateNumberInRange", () => {
|
||||
const min = 1;
|
||||
+8
-5
@@ -6,9 +6,12 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import fetchMock from "@fetch-mock/jest";
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { getVectorConfig } from "../../../src/vector/getconfig";
|
||||
import { vi, describe, it, expect, beforeEach, afterAll } from "vitest";
|
||||
import fetchMock from "@fetch-mock/vitest";
|
||||
|
||||
import { getVectorConfig } from "./getconfig";
|
||||
|
||||
describe("getVectorConfig()", () => {
|
||||
const elementDomain = "app.element.io";
|
||||
@@ -27,13 +30,13 @@ describe("getVectorConfig()", () => {
|
||||
});
|
||||
|
||||
// stable value for cachebuster
|
||||
jest.spyOn(Date, "now").mockReturnValue(now);
|
||||
jest.clearAllMocks();
|
||||
vi.spyOn(Date, "now").mockReturnValue(now);
|
||||
vi.clearAllMocks();
|
||||
fetchMock.removeRoutes();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.spyOn(Date, "now").mockRestore();
|
||||
vi.spyOn(Date, "now").mockRestore();
|
||||
});
|
||||
|
||||
it("requests specific config for document domain", async () => {
|
||||
+14
-10
@@ -6,16 +6,20 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { getInitialScreenAfterLogin, init, onNewScreen } from "../../../src/vector/routing";
|
||||
import type MatrixChat from "../../../src/components/structures/MatrixChat.tsx";
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { vi, describe, it, expect, beforeEach, afterAll } from "vitest";
|
||||
|
||||
import { getInitialScreenAfterLogin, init, onNewScreen } from "./routing";
|
||||
import type MatrixChat from "../components/structures/MatrixChat.tsx";
|
||||
|
||||
describe("onNewScreen", () => {
|
||||
it("should replace history if stripping via fields", () => {
|
||||
Object.defineProperty(window, "location", {
|
||||
value: {
|
||||
hash: "#/room/!room:server?via=abc",
|
||||
replace: jest.fn(),
|
||||
assign: jest.fn(),
|
||||
replace: vi.fn(),
|
||||
assign: vi.fn(),
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
@@ -28,8 +32,8 @@ describe("onNewScreen", () => {
|
||||
Object.defineProperty(window, "location", {
|
||||
value: {
|
||||
hash: "#/room/!room1:server?via=abc",
|
||||
replace: jest.fn(),
|
||||
assign: jest.fn(),
|
||||
replace: vi.fn(),
|
||||
assign: vi.fn(),
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
@@ -41,8 +45,8 @@ describe("onNewScreen", () => {
|
||||
|
||||
describe("getInitialScreenAfterLogin", () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(sessionStorage.__proto__, "getItem").mockClear().mockReturnValue(null);
|
||||
jest.spyOn(sessionStorage.__proto__, "setItem").mockClear();
|
||||
vi.spyOn(sessionStorage, "getItem").mockClear().mockReturnValue(null);
|
||||
vi.spyOn(sessionStorage, "setItem").mockClear();
|
||||
});
|
||||
|
||||
const makeMockLocation = (hash = "") => {
|
||||
@@ -65,7 +69,7 @@ describe("getInitialScreenAfterLogin", () => {
|
||||
const screen = {
|
||||
screen: "/room/!test",
|
||||
};
|
||||
jest.spyOn(sessionStorage.__proto__, "getItem").mockReturnValue(JSON.stringify(screen));
|
||||
vi.spyOn(sessionStorage, "getItem").mockReturnValue(JSON.stringify(screen));
|
||||
expect(getInitialScreenAfterLogin(makeMockLocation())).toEqual(screen);
|
||||
});
|
||||
});
|
||||
@@ -111,7 +115,7 @@ describe("init", () => {
|
||||
});
|
||||
|
||||
window.matrixChat = {
|
||||
showScreen: jest.fn(),
|
||||
showScreen: vi.fn(),
|
||||
} as unknown as MatrixChat;
|
||||
|
||||
init();
|
||||
+3
-1
@@ -5,7 +5,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { parseAppUrl, parseQsFromFragment, searchParamsToQueryDict } from "../../../src/vector/url_utils";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
import { parseAppUrl, parseQsFromFragment, searchParamsToQueryDict } from "./url_utils";
|
||||
|
||||
// @ts-ignore
|
||||
const location: Location = {
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { defineProject } from "vitest/config";
|
||||
|
||||
export default defineProject({
|
||||
test: {
|
||||
include: ["src/**/*.test.{ts,tsx}"],
|
||||
environment: "node",
|
||||
pool: "threads",
|
||||
globals: false,
|
||||
setupFiles: ["src/test/setupTests.ts"],
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user