mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
build: toolchain and dependency upgrades (TypeScript 6, Node 24 CI, Vite 8, Vitest 4, Go/Rust deps) (#1401)
* build(client): upgrade TypeScript to 6.0.3 Staging step toward TypeScript 7 (the native compiler), which needs its 7.1 stable API before typescript-eslint and Stryker's typescript-checker can run on it. TS 6 is the JS-based bridge release that aligns config defaults with 7. Two fallout fixes: - tsconfig.e2e.json: TS 6 defaults "types" to [] instead of every installed @types package, so the Playwright layer's Node globals (process, Buffer) need an explicit "types": ["node"]. - media-visibility.test.ts: TS 6's DOM lib adds scrollMargin to IntersectionObserver, so the mock grows the property. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lw5KEz6gdD816Wxmm4A3Bn * build(server): bump chi to 5.3.2, modernc.org/sqlite to 1.57.0, toolchain to go1.26.7 Go 1.27 deliberately deferred until 1.27.1 lands. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lw5KEz6gdD816Wxmm4A3Bn * build(tauri): bump tokio-tungstenite to 0.30, refresh Cargo.lock In-range lockfile refresh via cargo update; tungstenite 0.29/0.30 changes are client-API-neutral (header handling, server-side handshake hardening). Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lw5KEz6gdD816Wxmm4A3Bn * build(client): upgrade vite 8, vitest 4, jsdom 30, stryker 10 + minors - vite 6 -> 8: Rolldown requires the function form of manualChunks; __dirname -> import.meta.dirname in configs - vitest 3 -> 4: browser provider moved to @vitest/browser-playwright; vi.fn() mocks now need explicit signatures (typed throughout tests); constructor mocks use function impls; restoreAllMocks no longer resets vi.fn state; matchMedia spies replaced with vi.stubGlobal - jsdom 29 -> 30: one internal bookkeeping abort listener per signal, listener-count regression tests adjusted (leak detection retained) - stryker 9 -> 10, @types/node 20 -> 24, eslint/oxlint/livekit-client minors - tsconfigs: explicit "types" now that TS6/vitest4 stop injecting @types/node ambiently; build config keeps Node globals out of src/ Validated: tsc (main/build/e2e), eslint, oxlint, knip, prettier, unit+integration (5196 tests), browser suite, vite build, stryker dry run. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lw5KEz6gdD816Wxmm4A3Bn * ci: move Node 20 (EOL 2026-04-30) to Node 24 LTS The jsdom suite runs on modern Node without --no-experimental-webstorage: tests/setup.ts already replaces the shadowed localStorage with an in-memory shim. Client CLAUDE.md gotcha updated accordingly. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lw5KEz6gdD816Wxmm4A3Bn --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -125,7 +125,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 24
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 24
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||||
|
|
||||||
@@ -270,7 +270,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 24
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||||
|
|
||||||
@@ -329,7 +329,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 24
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||||
|
|
||||||
@@ -371,7 +371,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 24
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||||
|
|
||||||
@@ -463,7 +463,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 24
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 24
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 24
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||||
|
|
||||||
@@ -296,7 +296,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 24
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||||
|
|
||||||
@@ -463,7 +463,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 24
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: Client/tauri-client/package-lock.json
|
cache-dependency-path: Client/tauri-client/package-lock.json
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ Rust backend in `src-tauri/` for native APIs only. LiveKit handles voice/video.
|
|||||||
|
|
||||||
## Gotchas
|
## Gotchas
|
||||||
|
|
||||||
- **On Node 22+ you must run `NODE_OPTIONS=--no-experimental-webstorage npm test`.**
|
- Node's native Web Storage (Node 22+) shadows jsdom's `localStorage`;
|
||||||
Native Web Storage shadows jsdom's `localStorage` and fails ~478 tests that
|
`tests/setup.ts` replaces it with an in-memory shim, so the suite runs on
|
||||||
have nothing to do with your change. That is a local toolchain artifact, not
|
modern Node without `--no-experimental-webstorage`. If storage tests fail
|
||||||
a regression — do not "fix" those failures. CI pins Node 20.
|
en masse, suspect that shim before your change. CI pins Node 24.
|
||||||
- `src/lib/dispatcher.ts` is the single WS-event entry point **into the
|
- `src/lib/dispatcher.ts` is the single WS-event entry point **into the
|
||||||
stores**: server events reach domain stores only through a `ws.on(...)`
|
stores**: server events reach domain stores only through a `ws.on(...)`
|
||||||
subscription registered there. Other modules do register their own
|
subscription registered there. Other modules do register their own
|
||||||
|
|||||||
Generated
+1319
-1840
File diff suppressed because it is too large
Load Diff
@@ -34,24 +34,24 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@playwright/test": "^1",
|
"@playwright/test": "^1",
|
||||||
"@stryker-mutator/api": "^9.6.1",
|
"@stryker-mutator/api": "^10.0.0",
|
||||||
"@stryker-mutator/core": "^9.6.1",
|
"@stryker-mutator/core": "^10.0.0",
|
||||||
"@stryker-mutator/typescript-checker": "^9.6.1",
|
"@stryker-mutator/typescript-checker": "^10.0.0",
|
||||||
"@stryker-mutator/vitest-runner": "^9.6.1",
|
"@stryker-mutator/vitest-runner": "^10.0.0",
|
||||||
"@tauri-apps/cli": "^2",
|
"@tauri-apps/cli": "^2",
|
||||||
"@types/node": "^20.19.43",
|
"@types/node": "^24.13.3",
|
||||||
"@vitest/browser": "^3.2.4",
|
"@vitest/browser-playwright": "^4.1.11",
|
||||||
"@vitest/coverage-v8": "^3",
|
"@vitest/coverage-v8": "^4.1.11",
|
||||||
"eslint": "^10.8.1",
|
"eslint": "^10.9.0",
|
||||||
"fast-check": "^4.9.0",
|
"fast-check": "^4.9.0",
|
||||||
"jsdom": "^29.1.1",
|
"jsdom": "^30.0.1",
|
||||||
"knip": "^6.32.2",
|
"knip": "^6.32.2",
|
||||||
"oxlint": "^1.78.0",
|
"oxlint": "^1.79.0",
|
||||||
"prettier": "^3.9.6",
|
"prettier": "^3.9.6",
|
||||||
"typescript": "^5.7",
|
"typescript": "^6.0.3",
|
||||||
"typescript-eslint": "^8.67.0",
|
"typescript-eslint": "^8.67.0",
|
||||||
"vite": "^6",
|
"vite": "^8.2.2",
|
||||||
"vitest": "^3"
|
"vitest": "^4.1.11"
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"singleQuote": false,
|
"singleQuote": false,
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
"@tauri-apps/plugin-notification": "^2",
|
"@tauri-apps/plugin-notification": "^2",
|
||||||
"@tauri-apps/plugin-opener": "^2.5.3",
|
"@tauri-apps/plugin-opener": "^2.5.3",
|
||||||
"@tauri-apps/plugin-process": "^2.3.1",
|
"@tauri-apps/plugin-process": "^2.3.1",
|
||||||
"livekit-client": "^2.21.0"
|
"livekit-client": "^2.22.0"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"qs": "^6.15.3",
|
"qs": "^6.15.3",
|
||||||
|
|||||||
Generated
+776
-1117
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,7 @@ tauri-plugin-fs = "2"
|
|||||||
tauri-plugin-updater = "2.10"
|
tauri-plugin-updater = "2.10"
|
||||||
tauri-plugin-process = "2"
|
tauri-plugin-process = "2"
|
||||||
url = "2"
|
url = "2"
|
||||||
tokio-tungstenite = { version = "0.28.0", features = ["rustls-tls-webpki-roots"] }
|
tokio-tungstenite = { version = "0.30.0", features = ["rustls-tls-webpki-roots"] }
|
||||||
futures-util = "0.3.32"
|
futures-util = "0.3.32"
|
||||||
tokio = { version = "1", features = ["sync", "net", "io-util", "rt", "macros"] }
|
tokio = { version = "1", features = ["sync", "net", "io-util", "rt", "macros"] }
|
||||||
tokio-rustls = { version = "0.26", default-features = false }
|
tokio-rustls = { version = "0.26", default-features = false }
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ describe("AccessibilityTab — reduced-motion arbitration (OC-0232)", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
matchMediaListeners = new Map();
|
matchMediaListeners = new Map();
|
||||||
|
|
||||||
vi.spyOn(window, "matchMedia").mockImplementation((query: string) => {
|
// jsdom does not implement matchMedia, and vitest 4's spyOn refuses to spy
|
||||||
|
// on undefined, so stub the global instead.
|
||||||
|
vi.stubGlobal("matchMedia", (query: string) => {
|
||||||
const mql = {
|
const mql = {
|
||||||
matches: matchMediaMatches,
|
matches: matchMediaMatches,
|
||||||
media: query,
|
media: query,
|
||||||
@@ -62,6 +64,7 @@ describe("AccessibilityTab — reduced-motion arbitration (OC-0232)", () => {
|
|||||||
document.documentElement.classList.remove("reduced-motion");
|
document.documentElement.classList.remove("reduced-motion");
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
vi.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
|
vi.unstubAllGlobals();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps reduced-motion applied when OS sync is on and the OS still prefers it, even after a manual Reduce Motion toggle is switched off", () => {
|
it("keeps reduced-motion applied when OS sync is on and the OS still prefers it, even after a manual Reduce Motion toggle is switched off", () => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from "vitest";
|
||||||
|
|
||||||
// Mock the Tauri HTTP plugin — vi.hoisted ensures the fn is available when
|
// Mock the Tauri HTTP plugin — vi.hoisted ensures the fn is available when
|
||||||
// vi.mock's factory runs (hoisted above all imports).
|
// vi.mock's factory runs (hoisted above all imports).
|
||||||
@@ -19,7 +19,7 @@ vi.mock("../../src/lib/httpProxy", () => ({
|
|||||||
stopHttpProxy: () => Promise.resolve(),
|
stopHttpProxy: () => Promise.resolve(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
import { createApiClient, ApiClientError } from "../../src/lib/api";
|
import { createApiClient, ApiClientError, type OnUnauthorized } from "../../src/lib/api";
|
||||||
|
|
||||||
function jsonResponse(data: unknown, status = 200): Response {
|
function jsonResponse(data: unknown, status = 200): Response {
|
||||||
return {
|
return {
|
||||||
@@ -54,11 +54,11 @@ function brokenJsonErrorResponse(status: number, statusText: string): Response {
|
|||||||
|
|
||||||
describe("API Client", () => {
|
describe("API Client", () => {
|
||||||
let api: ReturnType<typeof createApiClient>;
|
let api: ReturnType<typeof createApiClient>;
|
||||||
let onUnauthorized: ReturnType<typeof vi.fn>;
|
let onUnauthorized: Mock<OnUnauthorized>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockFetch.mockReset();
|
mockFetch.mockReset();
|
||||||
onUnauthorized = vi.fn();
|
onUnauthorized = vi.fn<OnUnauthorized>();
|
||||||
api = createApiClient({ host: "localhost:8443", token: "test-token" }, onUnauthorized);
|
api = createApiClient({ host: "localhost:8443", token: "test-token" }, onUnauthorized);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
|||||||
|
|
||||||
const { fetchMock, putSpy } = vi.hoisted(() => ({
|
const { fetchMock, putSpy } = vi.hoisted(() => ({
|
||||||
fetchMock: vi.fn<any>(),
|
fetchMock: vi.fn<any>(),
|
||||||
putSpy: vi.fn<any>(),
|
putSpy: vi.fn<(value: string, key: string) => void>(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("@tauri-apps/plugin-http", () => ({
|
vi.mock("@tauri-apps/plugin-http", () => ({
|
||||||
|
|||||||
@@ -279,10 +279,17 @@ describe("AudioPipeline", () => {
|
|||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no worklet")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no worklet")) },
|
||||||
};
|
};
|
||||||
|
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockRoom = {
|
mockRoom = {
|
||||||
@@ -458,7 +465,7 @@ describe("AudioPipeline", () => {
|
|||||||
it("handles AudioContext constructor failure gracefully", () => {
|
it("handles AudioContext constructor failure gracefully", () => {
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"AudioContext",
|
"AudioContext",
|
||||||
vi.fn(() => {
|
vi.fn(function () {
|
||||||
throw new Error("AudioContext not supported");
|
throw new Error("AudioContext not supported");
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@@ -591,10 +598,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no worklet")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no worklet")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation((tracks: unknown) => ({ tracks })),
|
vi.fn(function (tracks: unknown) {
|
||||||
|
return { tracks };
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
return { mockSender };
|
return { mockSender };
|
||||||
}
|
}
|
||||||
@@ -676,7 +690,10 @@ describe("AudioPipeline", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("creates AudioContext with sampleRate 48000", () => {
|
it("creates AudioContext with sampleRate 48000", () => {
|
||||||
const AudioContextSpy = vi.fn().mockReturnValue({
|
const AudioContextSpy = vi.fn(function () {
|
||||||
|
return audioCtxForSpy;
|
||||||
|
});
|
||||||
|
const audioCtxForSpy = {
|
||||||
resume: vi.fn().mockResolvedValue(undefined),
|
resume: vi.fn().mockResolvedValue(undefined),
|
||||||
createMediaStreamSource: vi.fn().mockReturnValue({ connect: vi.fn() }),
|
createMediaStreamSource: vi.fn().mockReturnValue({ connect: vi.fn() }),
|
||||||
createAnalyser: vi.fn().mockReturnValue({
|
createAnalyser: vi.fn().mockReturnValue({
|
||||||
@@ -699,11 +716,13 @@ describe("AudioPipeline", () => {
|
|||||||
close: vi.fn().mockResolvedValue(undefined),
|
close: vi.fn().mockResolvedValue(undefined),
|
||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
});
|
};
|
||||||
vi.stubGlobal("AudioContext", AudioContextSpy);
|
vi.stubGlobal("AudioContext", AudioContextSpy);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const mockRoom = {
|
const mockRoom = {
|
||||||
@@ -749,10 +768,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const mockRoom = {
|
const mockRoom = {
|
||||||
@@ -798,10 +824,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const mockRoom = {
|
const mockRoom = {
|
||||||
@@ -846,10 +879,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const mockRoom = {
|
const mockRoom = {
|
||||||
@@ -911,10 +951,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const mockRoom = {
|
const mockRoom = {
|
||||||
@@ -968,10 +1015,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const mockRoom = {
|
const mockRoom = {
|
||||||
@@ -1046,7 +1100,9 @@ describe("AudioPipeline", () => {
|
|||||||
);
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
pipeline.setRoom(mockRoom);
|
pipeline.setRoom(mockRoom);
|
||||||
@@ -1114,7 +1170,9 @@ describe("AudioPipeline", () => {
|
|||||||
);
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
pipeline.setRoom(mockRoom);
|
pipeline.setRoom(mockRoom);
|
||||||
|
|||||||
@@ -234,10 +234,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -88,10 +88,17 @@ describe("AudioPipeline", () => {
|
|||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no worklet")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no worklet")) },
|
||||||
};
|
};
|
||||||
|
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
@@ -164,10 +171,17 @@ describe("AudioPipeline", () => {
|
|||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no worklet")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no worklet")) },
|
||||||
};
|
};
|
||||||
|
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
@@ -246,10 +260,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
@@ -340,10 +361,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
@@ -412,10 +440,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
@@ -480,10 +515,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
@@ -559,10 +601,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
|
|||||||
@@ -81,19 +81,28 @@ describe("AudioPipeline VAD worklet teardown (OC-0231)", () => {
|
|||||||
|
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"AudioWorkletNode",
|
"AudioWorkletNode",
|
||||||
vi.fn().mockImplementation(() => ({
|
vi.fn(function () {
|
||||||
port: {
|
return {
|
||||||
postMessage: vi.fn(),
|
port: {
|
||||||
onmessage: null as ((event: MessageEvent) => void) | null,
|
postMessage: vi.fn(),
|
||||||
},
|
onmessage: null as ((event: MessageEvent) => void) | null,
|
||||||
connect: vi.fn(),
|
},
|
||||||
disconnect: vi.fn(),
|
connect: vi.fn(),
|
||||||
})),
|
disconnect: vi.fn(),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockRoom = {
|
mockRoom = {
|
||||||
|
|||||||
@@ -123,19 +123,28 @@ describe("AudioPipeline", () => {
|
|||||||
// Mock AudioWorkletNode
|
// Mock AudioWorkletNode
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"AudioWorkletNode",
|
"AudioWorkletNode",
|
||||||
vi.fn().mockImplementation(() => ({
|
vi.fn(function () {
|
||||||
port: {
|
return {
|
||||||
postMessage: vi.fn(),
|
port: {
|
||||||
onmessage: null as ((event: MessageEvent) => void) | null,
|
postMessage: vi.fn(),
|
||||||
},
|
onmessage: null as ((event: MessageEvent) => void) | null,
|
||||||
connect: vi.fn(),
|
},
|
||||||
disconnect: vi.fn(),
|
connect: vi.fn(),
|
||||||
})),
|
disconnect: vi.fn(),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockRoom = {
|
mockRoom = {
|
||||||
@@ -297,10 +306,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
@@ -408,18 +424,27 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockReturnValue(addModulePromise) },
|
audioWorklet: { addModule: vi.fn().mockReturnValue(addModulePromise) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"AudioWorkletNode",
|
"AudioWorkletNode",
|
||||||
vi.fn().mockImplementation(() => ({
|
vi.fn(function () {
|
||||||
port: { postMessage: vi.fn(), onmessage: null },
|
return {
|
||||||
connect: vi.fn(),
|
port: { postMessage: vi.fn(), onmessage: null },
|
||||||
disconnect: vi.fn(),
|
connect: vi.fn(),
|
||||||
})),
|
disconnect: vi.fn(),
|
||||||
|
};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
@@ -493,18 +518,27 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockReturnValue(addModulePromise) },
|
audioWorklet: { addModule: vi.fn().mockReturnValue(addModulePromise) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"AudioWorkletNode",
|
"AudioWorkletNode",
|
||||||
vi.fn().mockImplementation(() => ({
|
vi.fn(function () {
|
||||||
port: { postMessage: vi.fn(), onmessage: null },
|
return {
|
||||||
connect: vi.fn(),
|
port: { postMessage: vi.fn(), onmessage: null },
|
||||||
disconnect: vi.fn(),
|
connect: vi.fn(),
|
||||||
})),
|
disconnect: vi.fn(),
|
||||||
|
};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
@@ -577,18 +611,27 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockResolvedValue(undefined) },
|
audioWorklet: { addModule: vi.fn().mockResolvedValue(undefined) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"AudioWorkletNode",
|
"AudioWorkletNode",
|
||||||
vi.fn().mockImplementation(() => ({
|
vi.fn(function () {
|
||||||
port: { postMessage: vi.fn(), onmessage: null },
|
return {
|
||||||
connect: vi.fn(),
|
port: { postMessage: vi.fn(), onmessage: null },
|
||||||
disconnect: vi.fn(),
|
connect: vi.fn(),
|
||||||
})),
|
disconnect: vi.fn(),
|
||||||
|
};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
@@ -668,18 +711,27 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockResolvedValue(undefined) },
|
audioWorklet: { addModule: vi.fn().mockResolvedValue(undefined) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"AudioWorkletNode",
|
"AudioWorkletNode",
|
||||||
vi.fn().mockImplementation(() => ({
|
vi.fn(function () {
|
||||||
port: { postMessage: postMessageSpy, onmessage: null },
|
return {
|
||||||
connect: vi.fn(),
|
port: { postMessage: postMessageSpy, onmessage: null },
|
||||||
disconnect: vi.fn(),
|
connect: vi.fn(),
|
||||||
})),
|
disconnect: vi.fn(),
|
||||||
|
};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
@@ -747,10 +799,17 @@ describe("AudioPipeline", () => {
|
|||||||
state: "running",
|
state: "running",
|
||||||
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
audioWorklet: { addModule: vi.fn().mockRejectedValue(new Error("no")) },
|
||||||
};
|
};
|
||||||
vi.stubGlobal("AudioContext", vi.fn().mockReturnValue(mockAudioCtx));
|
vi.stubGlobal(
|
||||||
|
"AudioContext",
|
||||||
|
vi.fn(function () {
|
||||||
|
return mockAudioCtx;
|
||||||
|
}),
|
||||||
|
);
|
||||||
vi.stubGlobal(
|
vi.stubGlobal(
|
||||||
"MediaStream",
|
"MediaStream",
|
||||||
vi.fn().mockImplementation(() => ({})),
|
vi.fn(function () {
|
||||||
|
return {};
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
mockLoadPref.mockImplementation((key: string, defaultVal: unknown) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
import { describe, it, expect, beforeEach, afterEach, vi, type Mock } from "vitest";
|
||||||
|
|
||||||
// Mock livekitSession (required by streamPreview). rePinPeerIdentity is hoisted
|
// Mock livekitSession (required by streamPreview). rePinPeerIdentity is hoisted
|
||||||
// so the mock factory can reference it and tests can assert re-pin was invoked.
|
// so the mock factory can reference it and tests can assert re-pin was invoked.
|
||||||
@@ -183,15 +183,15 @@ function setAdminUser(): void {
|
|||||||
describe("ChannelSidebar", () => {
|
describe("ChannelSidebar", () => {
|
||||||
let container: HTMLDivElement;
|
let container: HTMLDivElement;
|
||||||
let sidebar: ReturnType<typeof createChannelSidebar>;
|
let sidebar: ReturnType<typeof createChannelSidebar>;
|
||||||
let onVoiceJoin: ReturnType<typeof vi.fn>;
|
let onVoiceJoin: Mock<(channelId: number) => void>;
|
||||||
let onVoiceLeave: ReturnType<typeof vi.fn>;
|
let onVoiceLeave: Mock<() => void>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
resetStores();
|
resetStores();
|
||||||
container = document.createElement("div");
|
container = document.createElement("div");
|
||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
onVoiceJoin = vi.fn();
|
onVoiceJoin = vi.fn<(channelId: number) => void>();
|
||||||
onVoiceLeave = vi.fn();
|
onVoiceLeave = vi.fn<() => void>();
|
||||||
sidebar = createChannelSidebar({ onVoiceJoin, onVoiceLeave });
|
sidebar = createChannelSidebar({ onVoiceJoin, onVoiceLeave });
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2247,15 +2247,15 @@ describe("ChannelSidebar voice identity badge", () => {
|
|||||||
describe("ChannelSidebar channel feature flags", () => {
|
describe("ChannelSidebar channel feature flags", () => {
|
||||||
let container: HTMLDivElement;
|
let container: HTMLDivElement;
|
||||||
let sidebar: ReturnType<typeof createChannelSidebar>;
|
let sidebar: ReturnType<typeof createChannelSidebar>;
|
||||||
let onVoiceJoin: ReturnType<typeof vi.fn>;
|
let onVoiceJoin: Mock<(channelId: number) => void>;
|
||||||
let onVoiceLeave: ReturnType<typeof vi.fn>;
|
let onVoiceLeave: Mock<() => void>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
resetStores();
|
resetStores();
|
||||||
container = document.createElement("div");
|
container = document.createElement("div");
|
||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
onVoiceJoin = vi.fn();
|
onVoiceJoin = vi.fn<(channelId: number) => void>();
|
||||||
onVoiceLeave = vi.fn();
|
onVoiceLeave = vi.fn<() => void>();
|
||||||
sidebar = createChannelSidebar({ onVoiceJoin, onVoiceLeave });
|
sidebar = createChannelSidebar({ onVoiceJoin, onVoiceLeave });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ describe("CreateChannelModal", () => {
|
|||||||
|
|
||||||
it("disables submit button and shows 'Creating...' while creating", async () => {
|
it("disables submit button and shows 'Creating...' while creating", async () => {
|
||||||
let resolveCreate: (() => void) | undefined;
|
let resolveCreate: (() => void) | undefined;
|
||||||
const onCreate = vi.fn<any>(
|
const onCreate = vi.fn<NonNullable<CreateChannelModalOptions["onCreate"]>>(
|
||||||
() =>
|
() =>
|
||||||
new Promise<void>((resolve) => {
|
new Promise<void>((resolve) => {
|
||||||
resolveCreate = resolve;
|
resolveCreate = resolve;
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ describe("DeleteChannelModal", () => {
|
|||||||
|
|
||||||
it("disables button and shows 'Deleting...' during delete", async () => {
|
it("disables button and shows 'Deleting...' during delete", async () => {
|
||||||
let resolveDelete: (() => void) | undefined;
|
let resolveDelete: (() => void) | undefined;
|
||||||
const onConfirm = vi.fn<any>(
|
const onConfirm = vi.fn<() => Promise<void>>(
|
||||||
() =>
|
() =>
|
||||||
new Promise<void>((resolve) => {
|
new Promise<void>((resolve) => {
|
||||||
resolveDelete = resolve;
|
resolveDelete = resolve;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
* channels for every member of the server.
|
* channels for every member of the server.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { beforeEach, afterEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, afterEach, describe, expect, it, vi, type Mock } from "vitest";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
attachDragHandlers,
|
attachDragHandlers,
|
||||||
@@ -60,7 +60,7 @@ interface Rig {
|
|||||||
container: HTMLElement;
|
container: HTMLElement;
|
||||||
items: Map<number, HTMLElement>;
|
items: Map<number, HTMLElement>;
|
||||||
channels: Channel[];
|
channels: Channel[];
|
||||||
onReorder: ReturnType<typeof vi.fn>;
|
onReorder: Mock<(reorders: readonly ChannelReorderData[]) => void>;
|
||||||
abort: AbortController;
|
abort: AbortController;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ function buildRig(channels: Channel[]): Rig {
|
|||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
|
|
||||||
const items = new Map<number, HTMLElement>();
|
const items = new Map<number, HTMLElement>();
|
||||||
const onReorder = vi.fn();
|
const onReorder = vi.fn<(reorders: readonly ChannelReorderData[]) => void>();
|
||||||
const abort = new AbortController();
|
const abort = new AbortController();
|
||||||
rigAborts.push(abort);
|
rigAborts.push(abort);
|
||||||
|
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ describe("EditChannelModal", () => {
|
|||||||
|
|
||||||
it("disables save button and shows 'Saving...' during save", async () => {
|
it("disables save button and shows 'Saving...' during save", async () => {
|
||||||
let resolveSave: (() => void) | undefined;
|
let resolveSave: (() => void) | undefined;
|
||||||
const onSave = vi.fn<any>(
|
const onSave = vi.fn<(data: EditChannelData) => Promise<void>>(
|
||||||
() =>
|
() =>
|
||||||
new Promise<void>((resolve) => {
|
new Promise<void>((resolve) => {
|
||||||
resolveSave = resolve;
|
resolveSave = resolve;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* how it shares the composer with the @-mention popup).
|
* how it shares the composer with the @-mention popup).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
import { describe, it, expect, beforeEach, afterEach, vi, type Mock } from "vitest";
|
||||||
|
|
||||||
vi.mock("@lib/livekitSession", () => ({
|
vi.mock("@lib/livekitSession", () => ({
|
||||||
leaveVoice: vi.fn(),
|
leaveVoice: vi.fn(),
|
||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
MIN_EMOJI_QUERY,
|
MIN_EMOJI_QUERY,
|
||||||
} from "../../src/components/EmojiAutocomplete";
|
} from "../../src/components/EmojiAutocomplete";
|
||||||
import { createMessageInput } from "../../src/components/MessageInput";
|
import { createMessageInput } from "../../src/components/MessageInput";
|
||||||
|
import type { MessageInputOptions } from "../../src/components/MessageInput";
|
||||||
import { emojiStore, setCustomEmoji, clearCustomEmoji } from "../../src/stores/emoji.store";
|
import { emojiStore, setCustomEmoji, clearCustomEmoji } from "../../src/stores/emoji.store";
|
||||||
import { membersStore } from "../../src/stores/members.store";
|
import { membersStore } from "../../src/stores/members.store";
|
||||||
|
|
||||||
@@ -336,12 +337,12 @@ describe("createEmojiAutocomplete combobox wiring", () => {
|
|||||||
describe("composer :shortcode integration", () => {
|
describe("composer :shortcode integration", () => {
|
||||||
let container: HTMLDivElement;
|
let container: HTMLDivElement;
|
||||||
let input: ReturnType<typeof createMessageInput>;
|
let input: ReturnType<typeof createMessageInput>;
|
||||||
let onSend: ReturnType<typeof vi.fn>;
|
let onSend: Mock<MessageInputOptions["onSend"]>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
container = document.createElement("div");
|
container = document.createElement("div");
|
||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
onSend = vi.fn();
|
onSend = vi.fn<MessageInputOptions["onSend"]>();
|
||||||
input = createMessageInput({
|
input = createMessageInput({
|
||||||
channelId: 1,
|
channelId: 1,
|
||||||
channelName: "general",
|
channelName: "general",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from "vitest";
|
||||||
|
|
||||||
const { mockVoiceGetState } = vi.hoisted(() => ({
|
const { mockVoiceGetState } = vi.hoisted(() => ({
|
||||||
mockVoiceGetState: vi.fn(() => ({ currentChannelId: null as number | null })),
|
mockVoiceGetState: vi.fn(() => ({ currentChannelId: null as number | null })),
|
||||||
@@ -20,18 +20,18 @@ vi.mock("@stores/voice.store", () => ({
|
|||||||
const { attachGlobalKeybinds } = await import("../../src/pages/main-page/GlobalKeybinds");
|
const { attachGlobalKeybinds } = await import("../../src/pages/main-page/GlobalKeybinds");
|
||||||
|
|
||||||
function makeHandlers(): {
|
function makeHandlers(): {
|
||||||
onSearch: ReturnType<typeof vi.fn>;
|
onSearch: Mock<() => void>;
|
||||||
onToggleMute: ReturnType<typeof vi.fn>;
|
onToggleMute: Mock<() => void>;
|
||||||
onToggleDeafen: ReturnType<typeof vi.fn>;
|
onToggleDeafen: Mock<() => void>;
|
||||||
onToggleCamera: ReturnType<typeof vi.fn>;
|
onToggleCamera: Mock<() => void>;
|
||||||
onUploadFile: ReturnType<typeof vi.fn>;
|
onUploadFile: Mock<() => void>;
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
onSearch: vi.fn(),
|
onSearch: vi.fn<() => void>(),
|
||||||
onToggleMute: vi.fn(),
|
onToggleMute: vi.fn<() => void>(),
|
||||||
onToggleDeafen: vi.fn(),
|
onToggleDeafen: vi.fn<() => void>(),
|
||||||
onToggleCamera: vi.fn(),
|
onToggleCamera: vi.fn<() => void>(),
|
||||||
onUploadFile: vi.fn(),
|
onUploadFile: vi.fn<() => void>(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,13 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
|
|||||||
const mockSetKey = vi.hoisted(() => vi.fn());
|
const mockSetKey = vi.hoisted(() => vi.fn());
|
||||||
|
|
||||||
vi.mock("livekit-client", () => ({
|
vi.mock("livekit-client", () => ({
|
||||||
ExternalE2EEKeyProvider: vi.fn(() => ({
|
// vitest 4 mocks honor construct semantics — `new` needs a real function, not an arrow.
|
||||||
setKey: mockSetKey,
|
ExternalE2EEKeyProvider: vi.fn(function () {
|
||||||
getKeys: vi.fn().mockReturnValue([]),
|
return {
|
||||||
})),
|
setKey: mockSetKey,
|
||||||
|
getKeys: vi.fn().mockReturnValue([]),
|
||||||
|
};
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const mockKeyPair = vi.hoisted(() => ({
|
const mockKeyPair = vi.hoisted(() => ({
|
||||||
|
|||||||
@@ -47,7 +47,10 @@ const mockRoom = vi.hoisted(() => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("livekit-client", () => ({
|
vi.mock("livekit-client", () => ({
|
||||||
Room: vi.fn(() => mockRoom),
|
// vitest 4 mocks honor construct semantics — `new` needs a real function, not an arrow.
|
||||||
|
Room: vi.fn(function () {
|
||||||
|
return mockRoom;
|
||||||
|
}),
|
||||||
RoomEvent: {
|
RoomEvent: {
|
||||||
TrackSubscribed: "trackSubscribed",
|
TrackSubscribed: "trackSubscribed",
|
||||||
TrackUnsubscribed: "trackUnsubscribed",
|
TrackUnsubscribed: "trackUnsubscribed",
|
||||||
@@ -77,11 +80,14 @@ vi.mock("livekit-client", () => ({
|
|||||||
h1080fps30: { resolution: { width: 1920, height: 1080 } },
|
h1080fps30: { resolution: { width: 1920, height: 1080 } },
|
||||||
},
|
},
|
||||||
DisconnectReason: { CLIENT_INITIATED: 0 },
|
DisconnectReason: { CLIENT_INITIATED: 0 },
|
||||||
ExternalE2EEKeyProvider: vi.fn(() => ({
|
// vitest 4 mocks honor construct semantics — `new` needs a real function, not an arrow.
|
||||||
setKey: vi.fn(),
|
ExternalE2EEKeyProvider: vi.fn(function () {
|
||||||
getKeys: vi.fn().mockReturnValue([]),
|
return {
|
||||||
removeAllListeners: vi.fn(),
|
setKey: vi.fn(),
|
||||||
})),
|
getKeys: vi.fn().mockReturnValue([]),
|
||||||
|
removeAllListeners: vi.fn(),
|
||||||
|
};
|
||||||
|
}),
|
||||||
createLocalVideoTrack: vi.fn(async () => ({
|
createLocalVideoTrack: vi.fn(async () => ({
|
||||||
kind: "video",
|
kind: "video",
|
||||||
mediaStreamTrack: new MediaStreamTrack(),
|
mediaStreamTrack: new MediaStreamTrack(),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
import { describe, it, expect, vi, beforeEach, type Mock } from "vitest";
|
||||||
|
|
||||||
// clearAuth pulls in voice/livekit/notification teardown; stub it so this test
|
// clearAuth pulls in voice/livekit/notification teardown; stub it so this test
|
||||||
// stays a pure unit test of the best-effort revoke-then-teardown ordering.
|
// stays a pure unit test of the best-effort revoke-then-teardown ordering.
|
||||||
@@ -9,7 +9,7 @@ vi.mock("@stores/auth.store", () => ({
|
|||||||
|
|
||||||
import { logout } from "../../src/lib/logout";
|
import { logout } from "../../src/lib/logout";
|
||||||
|
|
||||||
function makeApi(logoutImpl: () => Promise<void>): { logout: ReturnType<typeof vi.fn> } {
|
function makeApi(logoutImpl: () => Promise<void>): { logout: Mock<() => Promise<void>> } {
|
||||||
return { logout: vi.fn(logoutImpl) };
|
return { logout: vi.fn(logoutImpl) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ describe("LogsTab", () => {
|
|||||||
let controller: AbortController;
|
let controller: AbortController;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.restoreAllMocks();
|
// vitest 4's restoreAllMocks no longer resets vi.fn() state — reset
|
||||||
|
// explicitly so call counts don't accumulate across tests.
|
||||||
|
vi.resetAllMocks();
|
||||||
controller = new AbortController();
|
controller = new AbortController();
|
||||||
mockGetLogBuffer.mockReturnValue([]);
|
mockGetLogBuffer.mockReturnValue([]);
|
||||||
mockAddLogListener.mockReturnValue(() => {});
|
mockAddLogListener.mockReturnValue(() => {});
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ const disconnectMock = vi.fn();
|
|||||||
class MockIntersectionObserver implements IntersectionObserver {
|
class MockIntersectionObserver implements IntersectionObserver {
|
||||||
readonly root: Element | null = null;
|
readonly root: Element | null = null;
|
||||||
readonly rootMargin: string = "0px";
|
readonly rootMargin: string = "0px";
|
||||||
|
readonly scrollMargin: string = "0px";
|
||||||
readonly thresholds: readonly number[] = [0];
|
readonly thresholds: readonly number[] = [0];
|
||||||
constructor(callback: IntersectionObserverCallback) {
|
constructor(callback: IntersectionObserverCallback) {
|
||||||
observerCallback = callback;
|
observerCallback = callback;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* entries, keyboard navigation, and composer integration.
|
* entries, keyboard navigation, and composer integration.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
import { describe, it, expect, beforeEach, afterEach, vi, type Mock } from "vitest";
|
||||||
|
|
||||||
vi.mock("@lib/livekitSession", () => ({
|
vi.mock("@lib/livekitSession", () => ({
|
||||||
leaveVoice: vi.fn(),
|
leaveVoice: vi.fn(),
|
||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
MAX_MENTION_SUGGESTIONS,
|
MAX_MENTION_SUGGESTIONS,
|
||||||
} from "../../src/components/MentionAutocomplete";
|
} from "../../src/components/MentionAutocomplete";
|
||||||
import { createMessageInput } from "../../src/components/MessageInput";
|
import { createMessageInput } from "../../src/components/MessageInput";
|
||||||
|
import type { MessageInputOptions } from "../../src/components/MessageInput";
|
||||||
import { membersStore } from "../../src/stores/members.store";
|
import { membersStore } from "../../src/stores/members.store";
|
||||||
import { authStore } from "../../src/stores/auth.store";
|
import { authStore } from "../../src/stores/auth.store";
|
||||||
import { channelsStore, setRoles } from "../../src/stores/channels.store";
|
import { channelsStore, setRoles } from "../../src/stores/channels.store";
|
||||||
@@ -132,13 +133,13 @@ describe("filterMentionSuggestions", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("createMentionAutocomplete", () => {
|
describe("createMentionAutocomplete", () => {
|
||||||
let onSelect: ReturnType<typeof vi.fn>;
|
let onSelect: Mock<(token: string) => void>;
|
||||||
let onClose: ReturnType<typeof vi.fn>;
|
let onClose: Mock<() => void>;
|
||||||
let popup: ReturnType<typeof createMentionAutocomplete>;
|
let popup: ReturnType<typeof createMentionAutocomplete>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
onSelect = vi.fn();
|
onSelect = vi.fn<(token: string) => void>();
|
||||||
onClose = vi.fn();
|
onClose = vi.fn<() => void>();
|
||||||
popup = createMentionAutocomplete({ onSelect, onClose });
|
popup = createMentionAutocomplete({ onSelect, onClose });
|
||||||
document.body.appendChild(popup.element);
|
document.body.appendChild(popup.element);
|
||||||
});
|
});
|
||||||
@@ -317,12 +318,12 @@ describe("createMentionAutocomplete combobox wiring", () => {
|
|||||||
describe("composer integration", () => {
|
describe("composer integration", () => {
|
||||||
let container: HTMLDivElement;
|
let container: HTMLDivElement;
|
||||||
let input: ReturnType<typeof createMessageInput>;
|
let input: ReturnType<typeof createMessageInput>;
|
||||||
let onSend: ReturnType<typeof vi.fn>;
|
let onSend: Mock<MessageInputOptions["onSend"]>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
container = document.createElement("div");
|
container = document.createElement("div");
|
||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
onSend = vi.fn();
|
onSend = vi.fn<MessageInputOptions["onSend"]>();
|
||||||
input = createMessageInput({
|
input = createMessageInput({
|
||||||
channelId: 1,
|
channelId: 1,
|
||||||
channelName: "general",
|
channelName: "general",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from "vitest";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Mocks
|
// Mocks
|
||||||
@@ -72,11 +72,11 @@ function makeAbort(): { signal: AbortSignal; abort: () => void } {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
describe("createMessageController", () => {
|
describe("createMessageController", () => {
|
||||||
let showError: ReturnType<typeof vi.fn>;
|
let showError: Mock<(msg: string) => void>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
showError = vi.fn();
|
showError = vi.fn<(msg: string) => void>();
|
||||||
mockIsChannelLoaded.mockReturnValue(false);
|
mockIsChannelLoaded.mockReturnValue(false);
|
||||||
mockGetChannelMessages.mockReturnValue([]);
|
mockGetChannelMessages.mockReturnValue([]);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,22 +9,27 @@ describe("syncOsMotionListener", () => {
|
|||||||
matchMediaListeners = new Map();
|
matchMediaListeners = new Map();
|
||||||
matchMediaMatches = false;
|
matchMediaMatches = false;
|
||||||
|
|
||||||
// Mock matchMedia to return a controllable MediaQueryList
|
// Mock matchMedia to return a controllable MediaQueryList. jsdom does not
|
||||||
vi.spyOn(window, "matchMedia").mockImplementation((_query: string) => {
|
// implement matchMedia, and vitest 4's spyOn refuses to spy on undefined,
|
||||||
const mql = {
|
// so stub the global instead.
|
||||||
matches: matchMediaMatches,
|
vi.stubGlobal(
|
||||||
media: _query,
|
"matchMedia",
|
||||||
onchange: null,
|
vi.fn((_query: string) => {
|
||||||
addListener: vi.fn(),
|
const mql = {
|
||||||
removeListener: vi.fn(),
|
matches: matchMediaMatches,
|
||||||
addEventListener: vi.fn((type: string, handler: Function, _opts?: any) => {
|
media: _query,
|
||||||
matchMediaListeners.set(type, handler);
|
onchange: null,
|
||||||
}),
|
addListener: vi.fn(),
|
||||||
removeEventListener: vi.fn(),
|
removeListener: vi.fn(),
|
||||||
dispatchEvent: vi.fn(() => true),
|
addEventListener: vi.fn((type: string, handler: Function, _opts?: any) => {
|
||||||
} as unknown as MediaQueryList;
|
matchMediaListeners.set(type, handler);
|
||||||
return mql;
|
}),
|
||||||
});
|
removeEventListener: vi.fn(),
|
||||||
|
dispatchEvent: vi.fn(() => true),
|
||||||
|
} as unknown as MediaQueryList;
|
||||||
|
return mql;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
// Clean up any leftover class/storage from previous tests
|
// Clean up any leftover class/storage from previous tests
|
||||||
document.documentElement.classList.remove("reduced-motion");
|
document.documentElement.classList.remove("reduced-motion");
|
||||||
@@ -35,6 +40,7 @@ describe("syncOsMotionListener", () => {
|
|||||||
// Disable the listener to clean up internal state
|
// Disable the listener to clean up internal state
|
||||||
syncOsMotionListener(false);
|
syncOsMotionListener(false);
|
||||||
document.documentElement.classList.remove("reduced-motion");
|
document.documentElement.classList.remove("reduced-motion");
|
||||||
|
vi.unstubAllGlobals();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("adds reduced-motion class when OS prefers reduced motion", () => {
|
it("adds reduced-motion class when OS prefers reduced motion", () => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from "vitest";
|
||||||
import { createQuickSwitcher } from "@components/QuickSwitcher";
|
import { createQuickSwitcher } from "@components/QuickSwitcher";
|
||||||
import type { QuickSwitcherOptions } from "@components/QuickSwitcher";
|
import type { QuickSwitcherOptions } from "@components/QuickSwitcher";
|
||||||
import { channelsStore, setChannels } from "@stores/channels.store";
|
import { channelsStore, setChannels } from "@stores/channels.store";
|
||||||
@@ -24,16 +24,16 @@ const testChannels: ReadyChannel[] = [
|
|||||||
describe("QuickSwitcher", () => {
|
describe("QuickSwitcher", () => {
|
||||||
let container: HTMLDivElement;
|
let container: HTMLDivElement;
|
||||||
let switcher: ReturnType<typeof createQuickSwitcher>;
|
let switcher: ReturnType<typeof createQuickSwitcher>;
|
||||||
let onSelectChannel: ReturnType<typeof vi.fn>;
|
let onSelectChannel: Mock<(channelId: number) => void>;
|
||||||
let onClose: ReturnType<typeof vi.fn>;
|
let onClose: Mock<() => void>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
resetStore();
|
resetStore();
|
||||||
setChannels(testChannels);
|
setChannels(testChannels);
|
||||||
container = document.createElement("div");
|
container = document.createElement("div");
|
||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
onSelectChannel = vi.fn();
|
onSelectChannel = vi.fn<(channelId: number) => void>();
|
||||||
onClose = vi.fn();
|
onClose = vi.fn<() => void>();
|
||||||
switcher = createQuickSwitcher({ onSelectChannel, onClose });
|
switcher = createQuickSwitcher({ onSelectChannel, onClose });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -334,8 +334,12 @@ describe("attachReactionTooltip", () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exactly two registrations regardless of chip count: the module's own
|
||||||
|
// guarded listener plus the single internal bookkeeping listener jsdom
|
||||||
|
// registers per signal for `{ signal }`-scoped DOM listeners. A per-chip
|
||||||
|
// leak would register one per chip (50+).
|
||||||
const abortRegistrations = addEventListenerSpy.mock.calls.filter(([type]) => type === "abort");
|
const abortRegistrations = addEventListenerSpy.mock.calls.filter(([type]) => type === "abort");
|
||||||
expect(abortRegistrations).toHaveLength(1);
|
expect(abortRegistrations).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("hides every currently-hovering chip on a signal when it aborts, not just the first attached", () => {
|
it("hides every currently-hovering chip on a signal when it aborts, not just the first attached", () => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from "vitest";
|
||||||
|
|
||||||
const mockRetryMicPermission = vi.fn().mockResolvedValue(undefined);
|
const mockRetryMicPermission = vi.fn().mockResolvedValue(undefined);
|
||||||
vi.mock("@lib/livekitSession", () => ({
|
vi.mock("@lib/livekitSession", () => ({
|
||||||
@@ -101,11 +101,11 @@ describe("Screen Share Button in VoiceWidget", () => {
|
|||||||
let container: HTMLDivElement;
|
let container: HTMLDivElement;
|
||||||
let comp: ReturnType<typeof createVoiceWidget>;
|
let comp: ReturnType<typeof createVoiceWidget>;
|
||||||
let handlers: {
|
let handlers: {
|
||||||
onDisconnect: ReturnType<typeof vi.fn>;
|
onDisconnect: Mock<() => void>;
|
||||||
onMuteToggle: ReturnType<typeof vi.fn>;
|
onMuteToggle: Mock<() => void>;
|
||||||
onDeafenToggle: ReturnType<typeof vi.fn>;
|
onDeafenToggle: Mock<() => void>;
|
||||||
onCameraToggle: ReturnType<typeof vi.fn>;
|
onCameraToggle: Mock<() => void>;
|
||||||
onScreenshareToggle: ReturnType<typeof vi.fn>;
|
onScreenshareToggle: Mock<() => void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -113,11 +113,11 @@ describe("Screen Share Button in VoiceWidget", () => {
|
|||||||
container = document.createElement("div");
|
container = document.createElement("div");
|
||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
handlers = {
|
handlers = {
|
||||||
onDisconnect: vi.fn(),
|
onDisconnect: vi.fn<() => void>(),
|
||||||
onMuteToggle: vi.fn(),
|
onMuteToggle: vi.fn<() => void>(),
|
||||||
onDeafenToggle: vi.fn(),
|
onDeafenToggle: vi.fn<() => void>(),
|
||||||
onCameraToggle: vi.fn(),
|
onCameraToggle: vi.fn<() => void>(),
|
||||||
onScreenshareToggle: vi.fn(),
|
onScreenshareToggle: vi.fn<() => void>(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
* test would sail straight past.
|
* test would sail straight past.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi, type Mock } from "vitest";
|
||||||
import { Track } from "livekit-client";
|
import { Track } from "livekit-client";
|
||||||
import type { LocalTrack, LocalVideoTrack, Room } from "livekit-client";
|
import type { LocalTrack, LocalVideoTrack, Room } from "livekit-client";
|
||||||
import type { WsClient } from "@lib/ws";
|
import type { WsClient } from "@lib/ws";
|
||||||
@@ -114,16 +114,16 @@ function fakeDeps(
|
|||||||
hasWs = true,
|
hasWs = true,
|
||||||
): VideoTrackDeps & {
|
): VideoTrackDeps & {
|
||||||
wsSend: ReturnType<typeof vi.fn>;
|
wsSend: ReturnType<typeof vi.fn>;
|
||||||
onError: ReturnType<typeof vi.fn>;
|
onError: Mock<(message: string) => void>;
|
||||||
reapplyAudioPipeline: ReturnType<typeof vi.fn>;
|
reapplyAudioPipeline: Mock<() => void>;
|
||||||
} {
|
} {
|
||||||
const wsSend = vi.fn();
|
const wsSend = vi.fn();
|
||||||
const ws = hasWs ? ({ send: wsSend } as unknown as WsClient) : null;
|
const ws = hasWs ? ({ send: wsSend } as unknown as WsClient) : null;
|
||||||
return {
|
return {
|
||||||
getRoom: () => room,
|
getRoom: () => room,
|
||||||
getWs: () => ws,
|
getWs: () => ws,
|
||||||
onError: vi.fn(),
|
onError: vi.fn<(message: string) => void>(),
|
||||||
reapplyAudioPipeline: vi.fn(),
|
reapplyAudioPipeline: vi.fn<() => void>(),
|
||||||
wsSend,
|
wsSend,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -361,8 +361,12 @@ describe("streamPreview", () => {
|
|||||||
// A re-render re-attaches the same row to the same sidebar-lifetime signal.
|
// A re-render re-attaches the same row to the same sidebar-lifetime signal.
|
||||||
attachStreamPreview(row1, 1, "Alice", false, true, ac.signal);
|
attachStreamPreview(row1, 1, "Alice", false, true, ac.signal);
|
||||||
|
|
||||||
|
// Exactly two registrations regardless of attach count: the module's own
|
||||||
|
// guarded listener plus the single internal bookkeeping listener jsdom
|
||||||
|
// registers per signal for `{ signal }`-scoped DOM listeners. A
|
||||||
|
// per-attach leak would register one per attach call.
|
||||||
const abortCalls = addSpy.mock.calls.filter(([type]) => type === "abort");
|
const abortCalls = addSpy.mock.calls.filter(([type]) => type === "abort");
|
||||||
expect(abortCalls).toHaveLength(1);
|
expect(abortCalls).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
// v091: a structural re-render (clearChildren + rebuild) detaches the old
|
// v091: a structural re-render (clearChildren + rebuild) detaches the old
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ describe("TOTP Settings", () => {
|
|||||||
// Simulate MainPage's onConfirmTotp: it calls updateUser after API success
|
// Simulate MainPage's onConfirmTotp: it calls updateUser after API success
|
||||||
const options = makeOptions({
|
const options = makeOptions({
|
||||||
onConfirmTotp: vi.fn().mockImplementation(async () => {
|
onConfirmTotp: vi.fn().mockImplementation(async () => {
|
||||||
(updateUser as ReturnType<typeof vi.fn>)({ totp_enabled: true });
|
updateUser({ totp_enabled: true });
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const overlay = createSettingsOverlay(options);
|
const overlay = createSettingsOverlay(options);
|
||||||
@@ -659,7 +659,7 @@ describe("TOTP Settings", () => {
|
|||||||
// Simulate MainPage's onDisableTotp: it calls updateUser after API success
|
// Simulate MainPage's onDisableTotp: it calls updateUser after API success
|
||||||
const options = makeOptions({
|
const options = makeOptions({
|
||||||
onDisableTotp: vi.fn().mockImplementation(async () => {
|
onDisableTotp: vi.fn().mockImplementation(async () => {
|
||||||
(updateUser as ReturnType<typeof vi.fn>)({ totp_enabled: false });
|
updateUser({ totp_enabled: false });
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const overlay = createSettingsOverlay(options);
|
const overlay = createSettingsOverlay(options);
|
||||||
@@ -706,7 +706,7 @@ describe("TOTP Settings", () => {
|
|||||||
const options = makeOptions({
|
const options = makeOptions({
|
||||||
onConfirmTotp: vi.fn().mockImplementation(async () => {
|
onConfirmTotp: vi.fn().mockImplementation(async () => {
|
||||||
// MainPage calls updateUser here — this is the single owner
|
// MainPage calls updateUser here — this is the single owner
|
||||||
(updateUser as ReturnType<typeof vi.fn>)({ totp_enabled: true });
|
updateUser({ totp_enabled: true });
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const overlay = createSettingsOverlay(options);
|
const overlay = createSettingsOverlay(options);
|
||||||
@@ -751,7 +751,7 @@ describe("TOTP Settings", () => {
|
|||||||
mockTotpEnabled = true;
|
mockTotpEnabled = true;
|
||||||
const options = makeOptions({
|
const options = makeOptions({
|
||||||
onDisableTotp: vi.fn().mockImplementation(async () => {
|
onDisableTotp: vi.fn().mockImplementation(async () => {
|
||||||
(updateUser as ReturnType<typeof vi.fn>)({ totp_enabled: false });
|
updateUser({ totp_enabled: false });
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const overlay = createSettingsOverlay(options);
|
const overlay = createSettingsOverlay(options);
|
||||||
|
|||||||
@@ -913,7 +913,12 @@ describe("VoiceAudioTab UI structure", () => {
|
|||||||
addEventListenerSpy.mock.calls.filter(([type]) => type === "abort").length;
|
addEventListenerSpy.mock.calls.filter(([type]) => type === "abort").length;
|
||||||
|
|
||||||
const tab = createVoiceAudioTab(ac.signal);
|
const tab = createVoiceAudioTab(ac.signal);
|
||||||
const afterCreate = abortListenerCount();
|
|
||||||
|
// The first build may add jsdom's single internal bookkeeping listener
|
||||||
|
// for `{ signal }`-scoped DOM listeners; snapshot after it so the
|
||||||
|
// assertion isolates listener growth caused by rebuilds.
|
||||||
|
tab.build();
|
||||||
|
const afterFirstBuild = abortListenerCount();
|
||||||
|
|
||||||
tab.build();
|
tab.build();
|
||||||
tab.build();
|
tab.build();
|
||||||
@@ -922,7 +927,7 @@ describe("VoiceAudioTab UI structure", () => {
|
|||||||
// Rebuilding the tab three times must not add three more permanent
|
// Rebuilding the tab three times must not add three more permanent
|
||||||
// "abort" listeners to the overlay-lifetime signal — only the single
|
// "abort" listeners to the overlay-lifetime signal — only the single
|
||||||
// listener the factory registers once at creation should exist.
|
// listener the factory registers once at creation should exist.
|
||||||
expect(abortListenerCount()).toBe(afterCreate);
|
expect(abortListenerCount()).toBe(afterFirstBuild);
|
||||||
|
|
||||||
ac.abort();
|
ac.abort();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
{
|
{
|
||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"include": [
|
// App code is browser-only: reset the "types": ["node"] the dev config
|
||||||
"src"
|
// needs for unit tests, so Node globals stay unavailable in src/.
|
||||||
],
|
"compilerOptions": {
|
||||||
|
"types": []
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
"exclude": []
|
"exclude": []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,12 @@
|
|||||||
// the app graph. "exclude": [] is required to clear the inherited
|
// the app graph. "exclude": [] is required to clear the inherited
|
||||||
// "tests/e2e" exclusion — same trick tsconfig.build.json uses.
|
// "tests/e2e" exclusion — same trick tsconfig.build.json uses.
|
||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
|
// TypeScript 6 defaults "types" to [] instead of every installed @types
|
||||||
|
// package, so the Node globals (process, Buffer) used by the Playwright
|
||||||
|
// layer must be pulled in explicitly.
|
||||||
|
"compilerOptions": {
|
||||||
|
"types": ["node"]
|
||||||
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"tests/e2e",
|
"tests/e2e",
|
||||||
"playwright.config.ts",
|
"playwright.config.ts",
|
||||||
|
|||||||
@@ -12,6 +12,11 @@
|
|||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
"lib": ["ES2023", "DOM", "DOM.Iterable"],
|
||||||
|
// TypeScript 6 defaults "types" to [] and vitest 4 no longer references
|
||||||
|
// @types/node itself, so the Node globals (node:fs, __dirname) used by
|
||||||
|
// unit tests must be pulled in explicitly. tsconfig.build.json resets
|
||||||
|
// this to [] so app code cannot use Node globals.
|
||||||
|
"types": ["node"],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@lib/*": ["./src/lib/*"],
|
"@lib/*": ["./src/lib/*"],
|
||||||
"@stores/*": ["./src/stores/*"],
|
"@stores/*": ["./src/stores/*"],
|
||||||
|
|||||||
@@ -20,20 +20,22 @@ export default defineConfig({
|
|||||||
cssCodeSplit: false,
|
cssCodeSplit: false,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
manualChunks: {
|
// Keep the ~1.3 MB LiveKit SDK in its own chunk, out of the entry.
|
||||||
// Keep the ~1.3 MB LiveKit SDK in its own chunk, out of the entry.
|
// Rolldown (Vite 8) only supports the function form of manualChunks.
|
||||||
livekit: ["livekit-client"],
|
manualChunks(id) {
|
||||||
|
if (id.includes("node_modules/livekit-client/")) return "livekit";
|
||||||
|
return undefined;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@lib": resolve(__dirname, "src/lib"),
|
"@lib": resolve(import.meta.dirname, "src/lib"),
|
||||||
"@stores": resolve(__dirname, "src/stores"),
|
"@stores": resolve(import.meta.dirname, "src/stores"),
|
||||||
"@components": resolve(__dirname, "src/components"),
|
"@components": resolve(import.meta.dirname, "src/components"),
|
||||||
"@pages": resolve(__dirname, "src/pages"),
|
"@pages": resolve(import.meta.dirname, "src/pages"),
|
||||||
"@styles": resolve(__dirname, "src/styles"),
|
"@styles": resolve(import.meta.dirname, "src/styles"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
clearScreen: false,
|
clearScreen: false,
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
import { defineConfig } from "vitest/config";
|
import { defineConfig } from "vitest/config";
|
||||||
|
import { playwright } from "@vitest/browser-playwright";
|
||||||
import { resolve } from "path";
|
import { resolve } from "path";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@lib": resolve(__dirname, "src/lib"),
|
"@lib": resolve(import.meta.dirname, "src/lib"),
|
||||||
"@stores": resolve(__dirname, "src/stores"),
|
"@stores": resolve(import.meta.dirname, "src/stores"),
|
||||||
"@components": resolve(__dirname, "src/components"),
|
"@components": resolve(import.meta.dirname, "src/components"),
|
||||||
"@pages": resolve(__dirname, "src/pages"),
|
"@pages": resolve(import.meta.dirname, "src/pages"),
|
||||||
"@styles": resolve(__dirname, "src/styles"),
|
"@styles": resolve(import.meta.dirname, "src/styles"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
browser: {
|
browser: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
provider: "playwright",
|
provider: playwright(),
|
||||||
instances: [{ browser: "chromium" }],
|
instances: [{ browser: "chromium" }],
|
||||||
},
|
},
|
||||||
include: ["tests/browser/**/*.test.ts"],
|
include: ["tests/browser/**/*.test.ts"],
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import { resolve } from "path";
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@lib": resolve(__dirname, "src/lib"),
|
"@lib": resolve(import.meta.dirname, "src/lib"),
|
||||||
"@stores": resolve(__dirname, "src/stores"),
|
"@stores": resolve(import.meta.dirname, "src/stores"),
|
||||||
"@components": resolve(__dirname, "src/components"),
|
"@components": resolve(import.meta.dirname, "src/components"),
|
||||||
"@pages": resolve(__dirname, "src/pages"),
|
"@pages": resolve(import.meta.dirname, "src/pages"),
|
||||||
"@styles": resolve(__dirname, "src/styles"),
|
"@styles": resolve(import.meta.dirname, "src/styles"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
|
|||||||
+3
-3
@@ -2,7 +2,7 @@ module github.com/owncord/server
|
|||||||
|
|
||||||
go 1.26
|
go 1.26
|
||||||
|
|
||||||
toolchain go1.26.6
|
toolchain go1.26.7
|
||||||
|
|
||||||
require (
|
require (
|
||||||
aead.dev/minisign v0.3.0
|
aead.dev/minisign v0.3.0
|
||||||
@@ -10,7 +10,7 @@ require (
|
|||||||
github.com/coder/websocket v1.8.15
|
github.com/coder/websocket v1.8.15
|
||||||
github.com/corazawaf/coraza-coreruleset/v4 v4.25.0
|
github.com/corazawaf/coraza-coreruleset/v4 v4.25.0
|
||||||
github.com/corazawaf/coraza/v3 v3.7.0
|
github.com/corazawaf/coraza/v3 v3.7.0
|
||||||
github.com/go-chi/chi/v5 v5.3.1
|
github.com/go-chi/chi/v5 v5.3.2
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/knadh/koanf/parsers/yaml v1.1.1
|
github.com/knadh/koanf/parsers/yaml v1.1.1
|
||||||
github.com/knadh/koanf/providers/env v1.1.0
|
github.com/knadh/koanf/providers/env v1.1.0
|
||||||
@@ -38,7 +38,7 @@ require (
|
|||||||
golang.org/x/sync v0.22.0
|
golang.org/x/sync v0.22.0
|
||||||
google.golang.org/protobuf v1.36.12
|
google.golang.org/protobuf v1.36.12
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
modernc.org/sqlite v1.56.0
|
modernc.org/sqlite v1.57.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
+4
-4
@@ -72,8 +72,8 @@ github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx5
|
|||||||
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||||
github.com/gammazero/deque v1.2.1 h1:9fnQVFCCZ9/NOc7ccTNqzoKd1tCWOqeI05/lPqFPMGQ=
|
github.com/gammazero/deque v1.2.1 h1:9fnQVFCCZ9/NOc7ccTNqzoKd1tCWOqeI05/lPqFPMGQ=
|
||||||
github.com/gammazero/deque v1.2.1/go.mod h1:5nSFkzVm+afG9+gy0VIowlqVAW4N8zNcMne+CMQVD2g=
|
github.com/gammazero/deque v1.2.1/go.mod h1:5nSFkzVm+afG9+gy0VIowlqVAW4N8zNcMne+CMQVD2g=
|
||||||
github.com/go-chi/chi/v5 v5.3.1 h1:3j4HZLGZQ3JpMCrPJF/Jl3mYJfWLKBfNJ6quurUGCf8=
|
github.com/go-chi/chi/v5 v5.3.2 h1:5YQkICvTCSZ25hoRsyJazN0scjzKGiu4VAUc7H1o1nY=
|
||||||
github.com/go-chi/chi/v5 v5.3.1/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
|
github.com/go-chi/chi/v5 v5.3.2/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
|
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
|
||||||
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
@@ -375,8 +375,8 @@ modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg=
|
|||||||
modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||||
modernc.org/sqlite v1.56.0 h1:/D8e2RfFqoy/Zc6PuC76U28zFwmI/sYx1Kjm4yEn9e0=
|
modernc.org/sqlite v1.57.0 h1:qNQP6xnx5M0ISNtlnxoOX0+cD5bJ0/gr9aMmndFczzg=
|
||||||
modernc.org/sqlite v1.56.0/go.mod h1:yCJ2cmAaIkHQ25oXWrF8H4O1lIfPYPR26yCEDj2P3pQ=
|
modernc.org/sqlite v1.57.0/go.mod h1:yCJ2cmAaIkHQ25oXWrF8H4O1lIfPYPR26yCEDj2P3pQ=
|
||||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
|||||||
Reference in New Issue
Block a user