mirror of
https://github.com/vector-im/element-call.git
synced 2026-04-06 07:20:25 +00:00
Merge branch 'livekit' into toger5/federated-room-joins
Signed-off-by: Timo K <toger5@hotmail.de>
This commit is contained in:
4
.github/workflows/publish.yaml
vendored
4
.github/workflows/publish.yaml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Log in to container registry
|
||||
uses: docker/login-action@3d58c274f17dffee475a5520cbe67f0a882c4dbb
|
||||
uses: docker/login-action@83a00bc1ab5ded6580f31df1c49e6aaa932d840d
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
tar --numeric-owner --transform "s/dist/element-call-${TARBALL_VERSION}/" -cvzf element-call-${TARBALL_VERSION}.tar.gz dist
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@4c0ff1c489dca52fedb26375d7d8fe7bd9233f19
|
||||
uses: actions/upload-artifact@ef09cdac3e2d3e60d8ccadda691f4f1cec5035cb
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
|
||||
8
.github/workflows/test.yaml
vendored
8
.github/workflows/test.yaml
vendored
@@ -1,11 +1,11 @@
|
||||
name: Run jest tests
|
||||
name: Run unit tests
|
||||
on:
|
||||
pull_request: {}
|
||||
push:
|
||||
branches: [livekit, full-mesh]
|
||||
jobs:
|
||||
jest:
|
||||
name: Run jest tests
|
||||
vitest:
|
||||
name: Run vitest tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
cache: "yarn"
|
||||
- name: Install dependencies
|
||||
run: "yarn install"
|
||||
- name: Jest
|
||||
- name: Vitest
|
||||
run: "yarn run test"
|
||||
- name: Upload to codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
|
||||
44
package.json
44
package.json
@@ -13,13 +13,14 @@
|
||||
"lint:types": "tsc",
|
||||
"i18n": "node_modules/i18next-parser/bin/cli.js",
|
||||
"i18n:check": "node_modules/i18next-parser/bin/cli.js --fail-on-warnings --fail-on-update",
|
||||
"test": "jest",
|
||||
"test": "vitest",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"backend": "docker-compose -f backend-docker-compose.yml up"
|
||||
},
|
||||
"dependencies": {
|
||||
"@juggle/resize-observer": "^3.3.1",
|
||||
"@livekit/components-core": "^0.8.0",
|
||||
"@livekit/components-react": "^1.1.0",
|
||||
"@livekit/components-core": "^0.9.0",
|
||||
"@livekit/components-react": "^2.0.0",
|
||||
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz",
|
||||
"@opentelemetry/api": "^1.4.0",
|
||||
"@opentelemetry/context-zone": "^1.9.1",
|
||||
@@ -59,7 +60,7 @@
|
||||
"i18next": "^23.0.0",
|
||||
"i18next-browser-languagedetector": "^7.0.0",
|
||||
"i18next-http-backend": "^2.0.0",
|
||||
"livekit-client": "1.15.12",
|
||||
"livekit-client": "^2.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#99600e87f193508ad56325baf2bb134110f3905a",
|
||||
"matrix-widget-api": "^1.3.1",
|
||||
@@ -88,21 +89,19 @@
|
||||
"@react-spring/rafz": "^9.7.3",
|
||||
"@react-types/dialog": "^3.5.5",
|
||||
"@sentry/vite-plugin": "^2.0.0",
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.5.1",
|
||||
"@types/content-type": "^1.1.5",
|
||||
"@types/dom-screen-wake-lock": "^1.0.1",
|
||||
"@types/dompurify": "^3.0.2",
|
||||
"@types/grecaptcha": "^3.0.4",
|
||||
"@types/jest": "^29.5.5",
|
||||
"@types/node": "^20.0.0",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/request": "^2.48.8",
|
||||
"@types/sdp-transform": "^2.4.5",
|
||||
"@types/uuid": "9",
|
||||
"@typescript-eslint/eslint-plugin": "^6.1.0",
|
||||
"@typescript-eslint/parser": "^6.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
||||
"@typescript-eslint/parser": "^7.0.0",
|
||||
"babel-loader": "^9.0.0",
|
||||
"babel-plugin-transform-vite-meta-env": "^1.0.3",
|
||||
"eslint": "^8.14.0",
|
||||
@@ -116,37 +115,14 @@
|
||||
"eslint-plugin-react-hooks": "^4.5.0",
|
||||
"eslint-plugin-unicorn": "^51.0.0",
|
||||
"i18next-parser": "^8.0.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^29.2.2",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"jest-mock": "^29.5.0",
|
||||
"jsdom": "^24.0.0",
|
||||
"prettier": "^3.0.0",
|
||||
"sass": "^1.42.1",
|
||||
"typescript": "^5.1.6",
|
||||
"typescript-eslint-language-service": "^5.0.5",
|
||||
"vite": "^5.0.0",
|
||||
"vite-plugin-html-template": "^1.1.0",
|
||||
"vite-plugin-svgr": "^4.0.0"
|
||||
},
|
||||
"jest": {
|
||||
"testEnvironment": "./test/environment.ts",
|
||||
"testMatch": [
|
||||
"<rootDir>/test/**/*-test.[jt]s?(x)"
|
||||
],
|
||||
"transformIgnorePatterns": [
|
||||
"/node_modules/(?!d3)+$",
|
||||
"/node_modules/(?!internmap)+$"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"\\.css$": "identity-obj-proxy",
|
||||
"\\.svg\\?react$": "<rootDir>/test/mocks/svgr.ts",
|
||||
"^\\./IndexedDBWorker\\?worker$": "<rootDir>/test/mocks/workerMock.ts",
|
||||
"^\\./olm$": "<rootDir>/test/mocks/olmMock.ts"
|
||||
},
|
||||
"collectCoverage": true,
|
||||
"coverageReporters": [
|
||||
"text",
|
||||
"cobertura"
|
||||
]
|
||||
"vite-plugin-svgr": "^4.0.0",
|
||||
"vitest": "^1.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
"unmute_microphone_button_label": "Unmute microphone",
|
||||
"version": "Version: {{version}}",
|
||||
"video_tile": {
|
||||
"change_fit_contain": "Crop to fit",
|
||||
"change_fit_contain": "Fit to frame",
|
||||
"exit_full_screen": "Exit full screen",
|
||||
"full_screen": "Full screen",
|
||||
"mute_for_me": "Mute for me",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"enabled": false
|
||||
}
|
||||
],
|
||||
"semanticCommits": "disabled",
|
||||
"ignoreDeps": [
|
||||
"@react-aria/button",
|
||||
"@react-aria/focus",
|
||||
|
||||
@@ -59,5 +59,4 @@ export const defaultLiveKitOptions: RoomOptions = {
|
||||
stopLocalTrackOnUnpublish: true,
|
||||
reconnectPolicy: new DefaultReconnectPolicy(),
|
||||
disconnectOnPageLeave: true,
|
||||
expWebAudioMix: false,
|
||||
};
|
||||
|
||||
@@ -61,7 +61,9 @@ async function doConnect(
|
||||
// doesn't publish it until you unmute. We want to publish it from the start so we're
|
||||
// always capturing audio: it helps keep bluetooth headsets in the right mode and
|
||||
// mobile browsers to know we're doing a call.
|
||||
if (livekitRoom!.localParticipant.getTrack(Track.Source.Microphone)) {
|
||||
if (
|
||||
livekitRoom!.localParticipant.getTrackPublication(Track.Source.Microphone)
|
||||
) {
|
||||
logger.warn(
|
||||
"Pre-creating audio track but participant already appears to have an microphone track: this shouldn't happen!",
|
||||
);
|
||||
@@ -90,7 +92,9 @@ async function doConnect(
|
||||
if (!audioEnabled) await preCreatedAudioTrack?.mute();
|
||||
|
||||
// check again having awaited for the track to create
|
||||
if (livekitRoom!.localParticipant.getTrack(Track.Source.Microphone)) {
|
||||
if (
|
||||
livekitRoom!.localParticipant.getTrackPublication(Track.Source.Microphone)
|
||||
) {
|
||||
logger.warn(
|
||||
"Pre-created audio track but participant already appears to have an microphone track: this shouldn't happen!",
|
||||
);
|
||||
@@ -174,7 +178,7 @@ export function useECConnectionState(
|
||||
|
||||
const doFocusSwitch = useCallback(async (): Promise<void> => {
|
||||
const screenshareTracks: MediaStreamTrack[] = [];
|
||||
for (const t of livekitRoom!.localParticipant.videoTracks.values()) {
|
||||
for (const t of livekitRoom!.localParticipant.videoTrackPublications.values()) {
|
||||
if (t.track && t.source == Track.Source.ScreenShare) {
|
||||
const newTrack = t.track.mediaStreamTrack.clone();
|
||||
newTrack.enabled = true;
|
||||
|
||||
@@ -291,7 +291,7 @@ export function useLiveKit(
|
||||
room.options.audioCaptureDefaults?.deviceId === "default"
|
||||
) {
|
||||
const activeMicTrack = Array.from(
|
||||
room.localParticipant.audioTracks.values(),
|
||||
room.localParticipant.audioTrackPublications.values(),
|
||||
).find((d) => d.source === Track.Source.Microphone)?.track;
|
||||
|
||||
const defaultDevice = device.available.find(
|
||||
@@ -313,7 +313,7 @@ export function useLiveKit(
|
||||
// Note that room.switchActiveDevice() won't work: Livekit will ignore it because
|
||||
// the deviceId hasn't changed (was & still is default).
|
||||
room.localParticipant
|
||||
.getTrack(Track.Source.Microphone)
|
||||
.getTrackPublication(Track.Source.Microphone)
|
||||
?.audioTrack?.restartTrack();
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -188,17 +188,9 @@ export async function initClient(
|
||||
await client.store.startup();
|
||||
}
|
||||
|
||||
if (client.initCrypto) {
|
||||
await client.initCrypto();
|
||||
client.setGlobalErrorOnUnknownDevices(false);
|
||||
}
|
||||
|
||||
await client.startClient({
|
||||
// dirty hack to reduce chance of gappy syncs
|
||||
// should be fixed by spotting gaps and backpaginating
|
||||
initialSyncLimit: 50,
|
||||
});
|
||||
|
||||
await client.initCrypto();
|
||||
client.setGlobalErrorOnUnknownDevices(false);
|
||||
await client.startClient();
|
||||
await waitForSync(client);
|
||||
|
||||
return client;
|
||||
|
||||
@@ -41,6 +41,8 @@ export const RoomAuthView: FC = () => {
|
||||
// @ts-ignore
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
const data = new FormData(e.target);
|
||||
const dataForDisplayName = data.get("displayName");
|
||||
const displayName =
|
||||
|
||||
@@ -56,7 +56,7 @@ function observeTrackReference(
|
||||
observeParticipantMedia(participant).pipe(
|
||||
map(() => ({
|
||||
participant,
|
||||
publication: participant.getTrack(source),
|
||||
publication: participant.getTrackPublication(source),
|
||||
source,
|
||||
})),
|
||||
distinctUntilKeyChanged("publication"),
|
||||
|
||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { vi } from "vitest";
|
||||
import { screen, render } from "@testing-library/react";
|
||||
import { Toast } from "../src/Toast";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
@@ -35,7 +36,7 @@ test("Toast renders", () => {
|
||||
});
|
||||
|
||||
test("Toast dismisses when clicked", async () => {
|
||||
const onDismiss = jest.fn();
|
||||
const onDismiss = vi.fn();
|
||||
render(
|
||||
<Toast open={true} onDismiss={onDismiss}>
|
||||
Hello world!
|
||||
@@ -47,13 +48,13 @@ test("Toast dismisses when clicked", async () => {
|
||||
|
||||
test("Toast dismisses itself after the specified timeout", async () => {
|
||||
withFakeTimers(() => {
|
||||
const onDismiss = jest.fn();
|
||||
const onDismiss = vi.fn();
|
||||
render(
|
||||
<Toast open={true} onDismiss={onDismiss} autoDismiss={2000}>
|
||||
Hello world!
|
||||
</Toast>,
|
||||
);
|
||||
jest.advanceTimersByTime(2000);
|
||||
vi.advanceTimersByTime(2000);
|
||||
expect(onDismiss).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { mocked } from "jest-mock";
|
||||
import { vi } from "vitest";
|
||||
|
||||
import { getRoomIdentifierFromUrl } from "../src/UrlParams";
|
||||
import { Config } from "../src/config/Config";
|
||||
@@ -24,11 +24,11 @@ const ROOM_ID = "!d45f138fsd";
|
||||
const ORIGIN = "https://call.element.io";
|
||||
const HOMESERVER = "call.ems.host";
|
||||
|
||||
jest.mock("../src/config/Config");
|
||||
vi.mock("../src/config/Config");
|
||||
|
||||
describe("UrlParams", () => {
|
||||
beforeAll(() => {
|
||||
mocked(Config.defaultServerName).mockReturnValue("call.ems.host");
|
||||
vi.mocked(Config.defaultServerName).mockReturnValue("call.ems.host");
|
||||
});
|
||||
|
||||
describe("handles URL with /room/", () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`Toast renders 1`] = `
|
||||
<button
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { TextEncoder } from "util";
|
||||
import JSDOMEnvironment_, {
|
||||
TestEnvironment as TestEnvironment_,
|
||||
} from "jest-environment-jsdom";
|
||||
import { JestEnvironmentConfig, EnvironmentContext } from "@jest/environment";
|
||||
|
||||
// This is a patched version of jsdom that adds TextEncoder, as a workaround for
|
||||
// https://github.com/jsdom/jsdom/issues/2524
|
||||
// Once that issue is resolved, this custom environment file can be deleted
|
||||
export default class JSDOMEnvironment extends JSDOMEnvironment_ {
|
||||
constructor(config: JestEnvironmentConfig, context: EnvironmentContext) {
|
||||
super(config, context);
|
||||
this.global.TextEncoder ??= TextEncoder;
|
||||
}
|
||||
}
|
||||
|
||||
export const TestEnvironment =
|
||||
TestEnvironment_ === JSDOMEnvironment_ ? JSDOMEnvironment : TestEnvironment_;
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = { loadOlm: jest.fn(async () => {}) };
|
||||
@@ -1,3 +0,0 @@
|
||||
// Mock file for SVG imports
|
||||
const ReactComponent = "svg";
|
||||
export default ReactComponent;
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = jest.fn();
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { Mocked, mocked } from "jest-mock";
|
||||
import { vi, Mocked } from "vitest";
|
||||
import { RoomState } from "matrix-js-sdk/src/models/room-state";
|
||||
import { PosthogAnalytics } from "../../src/analytics/PosthogAnalytics";
|
||||
import { checkForParallelCalls } from "../../src/room/checkForParallelCalls";
|
||||
@@ -23,10 +23,10 @@ import { withFakeTimers } from "../utils";
|
||||
const withMockedPosthog = (
|
||||
continuation: (posthog: Mocked<PosthogAnalytics>) => void,
|
||||
) => {
|
||||
const posthog = mocked({
|
||||
trackEvent: jest.fn(),
|
||||
const posthog = vi.mocked({
|
||||
trackEvent: vi.fn(),
|
||||
} as unknown as PosthogAnalytics);
|
||||
const instanceSpy = jest
|
||||
const instanceSpy = vi
|
||||
.spyOn(PosthogAnalytics, "instance", "get")
|
||||
.mockReturnValue(posthog);
|
||||
try {
|
||||
|
||||
@@ -13,12 +13,13 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import { vi } from "vitest";
|
||||
|
||||
export function withFakeTimers(continuation: () => void): void {
|
||||
jest.useFakeTimers();
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
continuation();
|
||||
} finally {
|
||||
jest.useRealTimers();
|
||||
vi.useRealTimers();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,23 @@
|
||||
"experimentalDecorators": true,
|
||||
"esModuleInterop": true,
|
||||
"noUnusedLocals": true,
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "bundler",
|
||||
"declaration": true,
|
||||
"resolveJsonModule": true,
|
||||
"paths": {
|
||||
// These imports within @livekit/components-core and
|
||||
// @livekit/components-react are broken under the "bundler" module
|
||||
// resolution mode, so we need to resolve them manually
|
||||
"livekit-client/dist/src/room/Room": [
|
||||
"./node_modules/livekit-client/dist/src/room/Room.d.ts"
|
||||
],
|
||||
"livekit-client/dist/src/room/participant/Participant": [
|
||||
"./node_modules/livekit-client/dist/src/room/participant/Participant.d.ts"
|
||||
],
|
||||
"livekit-client/dist/src/proto/livekit_models_pb": [
|
||||
"./node_modules/livekit-client/dist/src/proto/livekit_models_pb.d.ts"
|
||||
]
|
||||
},
|
||||
|
||||
// TODO: Enable the following options later.
|
||||
// "forceConsistentCasingInFileNames": true,
|
||||
@@ -29,6 +43,7 @@
|
||||
},
|
||||
"include": [
|
||||
"./node_modules/matrix-js-sdk/src/@types/*.d.ts",
|
||||
"./node_modules/vitest/globals.d.ts",
|
||||
"./src/**/*.ts",
|
||||
"./src/**/*.tsx",
|
||||
"./test/**/*.ts",
|
||||
|
||||
24
vitest.config.js
Normal file
24
vitest.config.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { defineConfig, mergeConfig } from "vitest/config";
|
||||
import viteConfig from "./vite.config";
|
||||
|
||||
export default defineConfig((configEnv) =>
|
||||
mergeConfig(
|
||||
viteConfig(configEnv),
|
||||
defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
environment: "jsdom",
|
||||
css: {
|
||||
modules: {
|
||||
classNameStrategy: "non-scoped",
|
||||
},
|
||||
},
|
||||
include: ["test/**/*-test.[jt]s?(x)"],
|
||||
coverage: {
|
||||
reporter: ["text", "html"],
|
||||
exclude: ["node_modules/"],
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
);
|
||||
Reference in New Issue
Block a user