@q9labsai/chalk-react-native 4.1.11 → 4.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/android.js +4 -2
- package/dist/{chunk-MMBE2BVK.js → chunk-4NLA35HE.js} +649 -407
- package/dist/{chunk-LZ67SXGB.js → chunk-MK6OO4V7.js} +6 -0
- package/dist/client.js +1 -1
- package/dist/components/Entrance.d.ts.map +1 -1
- package/dist/components/logo/Logo.d.ts +11 -0
- package/dist/components/logo/Logo.d.ts.map +1 -0
- package/dist/components/native-space-view/SpaceTopBar.android.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/ios-pad.js +4 -2
- package/dist/ios-phone.js +4 -2
- package/dist/ios.js +4 -2
- package/dist/macos.js +4 -2
- package/package.json +4 -4
- package/src/callkit/callkit.test.ts +12 -10
- package/src/components/Entrance.tsx +2 -1
- package/src/components/logo/Logo.tsx +309 -0
- package/src/components/native-space-view/SpaceTopBar.android.tsx +2 -1
- package/src/index.ts +2 -0
- package/src/space-client/create-native-space-client.ts +8 -0
- package/dist/components/LogoElements.d.ts +0 -6
- package/dist/components/LogoElements.d.ts.map +0 -1
- package/dist/test-support/test-renderer.d.ts +0 -20
- package/dist/test-support/test-renderer.d.ts.map +0 -1
- package/src/android/connection-service.test.ts +0 -114
- package/src/callkit/resolve-space-callkit-options.test.ts +0 -68
- package/src/client.test.ts +0 -12
- package/src/clipboard.test.ts +0 -79
- package/src/components/Chalk.test.tsx +0 -223
- package/src/components/EmbeddedWhiteboard.test.tsx +0 -92
- package/src/components/Entrance.test.tsx +0 -19
- package/src/components/EntranceView.android.test.tsx +0 -100
- package/src/components/EntranceView.ios-pad.test.tsx +0 -160
- package/src/components/EntranceView.ios-phone.test.tsx +0 -137
- package/src/components/EntranceView.test.tsx +0 -15
- package/src/components/LogoElements.test.tsx +0 -60
- package/src/components/LogoElements.tsx +0 -119
- package/src/components/ReactionPicker.test.tsx +0 -19
- package/src/components/RtcVideoView.test.tsx +0 -12
- package/src/components/SpaceView.android.test.tsx +0 -11
- package/src/components/SpaceView.ios-pad.test.tsx +0 -11
- package/src/components/SpaceView.ios-phone.test.tsx +0 -11
- package/src/components/SpaceView.macos.test.tsx +0 -11
- package/src/components/SpaceView.shared.test.tsx +0 -116
- package/src/components/SpaceView.test.tsx +0 -15
- package/src/components/android-connection-service-controller.test.ts +0 -80
- package/src/components/episode-diagnostic-render-observer.test.ts +0 -24
- package/src/components/native-animation-controller.test.ts +0 -47
- package/src/components/native-chat.test.ts +0 -22
- package/src/components/native-entrance/entrance-controller-store.test.ts +0 -75
- package/src/components/native-media-visibility.test.ts +0 -77
- package/src/components/native-space-callkit-controller.test.ts +0 -62
- package/src/components/native-space-view/AppearanceSettings.test.tsx +0 -56
- package/src/components/native-space-view/ParticipantActionSheet.test.tsx +0 -18
- package/src/components/native-space-view/SettingsSheet.test.tsx +0 -17
- package/src/components/native-space-view/SpaceActionMenu.test.tsx +0 -126
- package/src/components/native-space-view/SpaceBottomDock.android.test.tsx +0 -61
- package/src/components/native-space-view/SpaceChatSheet.test.tsx +0 -18
- package/src/components/native-space-view/SpaceMoreSheet.test.tsx +0 -15
- package/src/components/native-space-view/SpacePanelSheet.test.tsx +0 -15
- package/src/components/native-space-view/SpacePeopleSheet.test.tsx +0 -13
- package/src/components/native-space-view/SpaceSurfacePrimitives.test.tsx +0 -12
- package/src/components/native-space-view/SpaceTopBar.android.test.tsx +0 -43
- package/src/components/native-space-view/SpaceWhiteboardSurface.test.tsx +0 -85
- package/src/components/native-space-view/diagnostics.test.ts +0 -31
- package/src/components/native-space-view/format-space-duration.test.ts +0 -13
- package/src/components/native-space-view/native-space-grid-keys.test.ts +0 -11
- package/src/components/native-space-view/native-space-page-store.test.ts +0 -23
- package/src/components/native-space-view/space-chat-attachments.test.ts +0 -33
- package/src/components/native-space-view/space-progressive-surface-helpers.test.ts +0 -24
- package/src/components/native-space-view/useSpaceViewController.contract.test.ts +0 -10
- package/src/components/native-space-view/useSpaceViewController.test.ts +0 -106
- package/src/components/native-space-view/useSpaceViewDerived.test.ts +0 -58
- package/src/components/native-space-view/useSpaceViewPanels.controlled.test.ts +0 -40
- package/src/components/native-space-view/useSpaceViewPanels.test.ts +0 -73
- package/src/components/space-lifecycle.test.ts +0 -19
- package/src/context/space-client-context.test.tsx +0 -10
- package/src/diagnostics.test.ts +0 -29
- package/src/hooks/entrance-preview-store.test.ts +0 -79
- package/src/hooks/space-hooks.test.ts +0 -76
- package/src/hooks/useLayout.test.ts +0 -16
- package/src/invites.test.ts +0 -51
- package/src/public-surface.test.ts +0 -26
- package/src/runtime.test.ts +0 -83
- package/src/space-client/cloudflare-rtk-native.test.ts +0 -118
- package/src/space-client/create-native-space-client.test.ts +0 -300
- package/src/telemetry.test.ts +0 -143
- package/src/test-support/test-renderer.test.ts +0 -9
- package/src/test-support/test-renderer.ts +0 -28
- package/src/ui/appearance.test.ts +0 -61
- package/src/ui/native-appearance-context.controlled.test.tsx +0 -41
- package/src/ui/native-appearance-context.test.tsx +0 -14
- package/src/ui/native-theme.test.ts +0 -34
- package/src/ui/native-theme.test.tsx +0 -14
- package/src/ui/participant-avatar.test.ts +0 -29
- package/src/ui/theme-tokens.test.ts +0 -14
- package/src/ui/theme.test.ts +0 -36
- package/src/utils/build-chalk-invite-link.test.ts +0 -12
- package/src/utils/ios-simulator.test.ts +0 -96
- package/src/utils/native-space-layout.test.ts +0 -170
- package/src/whiteboard/embedded-whiteboard-assets.test.ts +0 -31
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { describe, expect, it, vi } from "vitest";
|
|
3
|
-
|
|
4
|
-
vi.mock("react-native", () => ({
|
|
5
|
-
Alert: { alert: vi.fn() },
|
|
6
|
-
FlatList: "FlatList",
|
|
7
|
-
Modal: "Modal",
|
|
8
|
-
Pressable: "Pressable",
|
|
9
|
-
ScrollView: "ScrollView",
|
|
10
|
-
StyleSheet: { create: <T,>(styles: T) => styles },
|
|
11
|
-
Text: "Text",
|
|
12
|
-
TextInput: "TextInput",
|
|
13
|
-
View: "View",
|
|
14
|
-
}));
|
|
15
|
-
vi.mock("../../ui/native-theme", () => ({
|
|
16
|
-
useNativeTheme: () => ({ colors: { background: "#0a0a0b", border: "#1c1c1f", card: "#141418", error: "#ef4444", foreground: "#fbffff", mutedForeground: "#71717a", placeholder: "#71717a", primary: "#1bb6a6", primaryForeground: "#ffffff" } }),
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
|
-
import { selectSpaceReaction, SpaceActionMenu } from "./SpaceActionMenu";
|
|
20
|
-
|
|
21
|
-
const source = readFileSync(new URL("./SpaceActionMenu.tsx", import.meta.url), "utf8");
|
|
22
|
-
|
|
23
|
-
describe("SpaceActionMenu", () => {
|
|
24
|
-
it("shows only capability-backed actions and closes after a layout selection", () => {
|
|
25
|
-
const setActionsOpen = vi.fn();
|
|
26
|
-
const setLayout = vi.fn();
|
|
27
|
-
const controller = actionController({
|
|
28
|
-
canInvite: true,
|
|
29
|
-
canParticipants: false,
|
|
30
|
-
canChat: true,
|
|
31
|
-
canScreenShare: false,
|
|
32
|
-
canHandRaise: true,
|
|
33
|
-
canWhiteboard: false,
|
|
34
|
-
canReactions: false,
|
|
35
|
-
canSettings: true,
|
|
36
|
-
setActionsOpen,
|
|
37
|
-
layout: { layout: "grid", setLayout },
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const tree = SpaceActionMenu({ controller });
|
|
41
|
-
const labels = findText(tree);
|
|
42
|
-
|
|
43
|
-
expect(labels).toEqual(expect.arrayContaining(["Invite participants", "Chat", "Raise hand", "Settings", "Grid layout (selected)", "Focus layout", "Presentation layout"]));
|
|
44
|
-
expect(labels).not.toContain("Participants");
|
|
45
|
-
expect(labels).not.toContain("Open whiteboard");
|
|
46
|
-
|
|
47
|
-
const presentation = findElements(tree, "Pressable").find((element) => findText(element).length === 1 && findText(element).includes("Presentation layout"));
|
|
48
|
-
const onPress = presentation?.props?.onPress;
|
|
49
|
-
if (typeof onPress === "function") onPress();
|
|
50
|
-
expect(setLayout).toHaveBeenCalledWith("presentation");
|
|
51
|
-
expect(setActionsOpen).toHaveBeenCalledWith(false);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("routes reaction selection through the controller", () => {
|
|
55
|
-
const sendReaction = vi.fn();
|
|
56
|
-
|
|
57
|
-
selectSpaceReaction({ sendReaction } as never, "🎉");
|
|
58
|
-
|
|
59
|
-
expect(sendReaction).toHaveBeenCalledWith("🎉");
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("shows diagnostics only when its open handler is provided", () => {
|
|
63
|
-
const setActionsOpen = vi.fn();
|
|
64
|
-
const onOpenDiagnostics = vi.fn();
|
|
65
|
-
const controller = actionController({ setActionsOpen });
|
|
66
|
-
|
|
67
|
-
expect(findText(SpaceActionMenu({ controller }))).not.toContain("Diagnostics");
|
|
68
|
-
|
|
69
|
-
const tree = SpaceActionMenu({ controller, onOpenDiagnostics });
|
|
70
|
-
const diagnostics = findElements(tree, "Pressable").find((element) => findText(element).length === 1 && findText(element).includes("Diagnostics"));
|
|
71
|
-
const onPress = diagnostics?.props?.onPress;
|
|
72
|
-
if (typeof onPress === "function") onPress();
|
|
73
|
-
|
|
74
|
-
expect(setActionsOpen).toHaveBeenCalledWith(false);
|
|
75
|
-
expect(onOpenDiagnostics).toHaveBeenCalledTimes(1);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("leaves chat and settings panel ownership to canonical mounted sheets", () => {
|
|
79
|
-
expect(source).not.toContain("ChatPanel");
|
|
80
|
-
expect(source).not.toContain("<SpacePanel");
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it("does not invent a role catalog for customer-defined participant roles", () => {
|
|
84
|
-
expect(source).not.toContain("Set collaborator role");
|
|
85
|
-
expect(source).not.toContain("Set observer role");
|
|
86
|
-
expect(source).not.toContain("setParticipantRole");
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
function actionController(overrides: Record<string, unknown>): never {
|
|
91
|
-
return {
|
|
92
|
-
actionsOpen: true,
|
|
93
|
-
canHandRaise: false,
|
|
94
|
-
canInvite: false,
|
|
95
|
-
canParticipants: false,
|
|
96
|
-
canChat: false,
|
|
97
|
-
canScreenShare: false,
|
|
98
|
-
canWhiteboard: false,
|
|
99
|
-
canReactions: false,
|
|
100
|
-
canSettings: false,
|
|
101
|
-
handRaised: false,
|
|
102
|
-
screenShare: { isLocalSharing: false },
|
|
103
|
-
whiteboard: { isOpen: false, toggle: vi.fn() },
|
|
104
|
-
layout: { layout: "grid", setLayout: vi.fn() },
|
|
105
|
-
handleLeave: vi.fn(),
|
|
106
|
-
openPanel: vi.fn(),
|
|
107
|
-
setActionsOpen: vi.fn(),
|
|
108
|
-
setReactionPickerOpen: vi.fn(),
|
|
109
|
-
...overrides,
|
|
110
|
-
} as never;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function findElements(value: unknown, type: string): { readonly props?: Record<string, unknown> }[] {
|
|
114
|
-
if (Array.isArray(value)) return value.flatMap((child) => findElements(child, type));
|
|
115
|
-
if (!value || typeof value !== "object") return [];
|
|
116
|
-
const element = value as { readonly type?: unknown; readonly props?: Record<string, unknown> };
|
|
117
|
-
const own = element.type === type ? [element] : [];
|
|
118
|
-
return [...own, ...findElements(element.props?.children, type)];
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function findText(value: unknown): string[] {
|
|
122
|
-
if (typeof value === "string") return [value];
|
|
123
|
-
if (Array.isArray(value)) return value.flatMap(findText);
|
|
124
|
-
if (!value || typeof value !== "object") return [];
|
|
125
|
-
return findText((value as { readonly props?: { readonly children?: unknown } }).props?.children);
|
|
126
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
vi.mock("@hugeicons/core-free-icons/dist/esm/CallEnd01Icon", () => ({ default: "CallEnd01Icon" }));
|
|
4
|
-
vi.mock("@hugeicons/core-free-icons/dist/esm/Chat01Icon", () => ({ default: "Chat01Icon" }));
|
|
5
|
-
vi.mock("@hugeicons/core-free-icons/dist/esm/Mic01Icon", () => ({ default: "Mic01Icon" }));
|
|
6
|
-
vi.mock("@hugeicons/core-free-icons/dist/esm/MicOff01Icon", () => ({ default: "MicOff01Icon" }));
|
|
7
|
-
vi.mock("@hugeicons/core-free-icons/dist/esm/MoreHorizontalIcon", () => ({ default: "MoreHorizontalIcon" }));
|
|
8
|
-
vi.mock("@hugeicons/core-free-icons/dist/esm/Video01Icon", () => ({ default: "Video01Icon" }));
|
|
9
|
-
vi.mock("@hugeicons/core-free-icons/dist/esm/VideoOffIcon", () => ({ default: "VideoOffIcon" }));
|
|
10
|
-
vi.mock("@hugeicons/react-native", () => ({ HugeiconsIcon: "HugeiconsIcon" }));
|
|
11
|
-
vi.mock("react-native", () => ({
|
|
12
|
-
Platform: { OS: "android" },
|
|
13
|
-
Pressable: "Pressable",
|
|
14
|
-
StyleSheet: { create: <T,>(styles: T) => styles },
|
|
15
|
-
Text: "Text",
|
|
16
|
-
View: "View",
|
|
17
|
-
}));
|
|
18
|
-
vi.mock("../../ui/native-theme", () => ({
|
|
19
|
-
useNativeTheme: () => ({ colors: { controlsBackground: "#141418", darkCanvas: "#0a0a0b", error: "#ef4444", onDark: "#fbffff", primary: "#1bb6a6", primaryForeground: "#ffffff", border: "#1c1c1f" } }),
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
import { SpaceBottomDockAndroid } from "./SpaceBottomDock.android";
|
|
23
|
-
|
|
24
|
-
describe("SpaceBottomDockAndroid", () => {
|
|
25
|
-
it("disables both media controls on unsupported simulator media and caps unread badges", () => {
|
|
26
|
-
const onToggleAudio = vi.fn();
|
|
27
|
-
const onToggleVideo = vi.fn();
|
|
28
|
-
const tree = SpaceBottomDockAndroid({
|
|
29
|
-
simulatorMediaDisabled: true,
|
|
30
|
-
isMuted: false,
|
|
31
|
-
isCameraOff: true,
|
|
32
|
-
unreadChatCount: 12,
|
|
33
|
-
onToggleAudio,
|
|
34
|
-
onToggleVideo,
|
|
35
|
-
onOpenChat: vi.fn(),
|
|
36
|
-
onOpenMore: vi.fn(),
|
|
37
|
-
onLeave: vi.fn(),
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const buttons = findElements(tree, "Pressable");
|
|
41
|
-
expect(buttons).toHaveLength(5);
|
|
42
|
-
expect(buttons[0]).toMatchObject({ props: { disabled: true, onPress: onToggleAudio } });
|
|
43
|
-
expect(buttons[1]).toMatchObject({ props: { disabled: true, onPress: onToggleVideo } });
|
|
44
|
-
expect(findText(tree)).toContain("9+");
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
function findElements(value: unknown, type: string): { readonly props?: Record<string, unknown> }[] {
|
|
49
|
-
if (Array.isArray(value)) return value.flatMap((child) => findElements(child, type));
|
|
50
|
-
if (!value || typeof value !== "object") return [];
|
|
51
|
-
const element = value as { readonly type?: unknown; readonly props?: Record<string, unknown> };
|
|
52
|
-
const own = element.type === type ? [element] : [];
|
|
53
|
-
return [...own, ...findElements(element.props?.children, type)];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function findText(value: unknown): string[] {
|
|
57
|
-
if (typeof value === "string") return [value];
|
|
58
|
-
if (Array.isArray(value)) return value.flatMap(findText);
|
|
59
|
-
if (!value || typeof value !== "object") return [];
|
|
60
|
-
return findText((value as { readonly props?: { readonly children?: unknown } }).props?.children);
|
|
61
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
|
|
4
|
-
const source = readFileSync(new URL("./SpaceChatSheet.tsx", import.meta.url), "utf8");
|
|
5
|
-
|
|
6
|
-
describe("SpaceChatSheet", () => {
|
|
7
|
-
it("keeps attachment, retry, and accessible composition flows", () => {
|
|
8
|
-
expect(source).toContain('accessibilityLabel="Attach file"');
|
|
9
|
-
expect(source).toContain("controller.chatAttachments.map");
|
|
10
|
-
expect(source).toContain("controller.removeChatAttachment(index)");
|
|
11
|
-
expect(source).toContain("chatAttachmentUploading");
|
|
12
|
-
expect(source).toContain("chatAttachmentError");
|
|
13
|
-
expect(source).toContain("!controller.chatDraft.trim() && controller.chatAttachments.length === 0");
|
|
14
|
-
expect(source).toContain('accessibilityLabel="Send message"');
|
|
15
|
-
expect(source).toContain("retryMessage(message.clientMessageId)");
|
|
16
|
-
expect(source).toContain('accessibilityRole="link"');
|
|
17
|
-
});
|
|
18
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
|
|
4
|
-
const source = readFileSync(new URL("./SpaceMoreSheet.tsx", import.meta.url), "utf8");
|
|
5
|
-
|
|
6
|
-
describe("SpaceMoreSheet", () => {
|
|
7
|
-
it("progressively discloses Board, People, Chat, Settings, and Leave", () => {
|
|
8
|
-
for (const label of ['label: controller.whiteboard.isOpen ? "Close Board" : "Board"', 'label: "People"', 'label: "Chat"', 'label: "Settings"', ">Leave<"]) {
|
|
9
|
-
expect(source).toContain(label);
|
|
10
|
-
}
|
|
11
|
-
expect(source).toContain("StyleSheet.absoluteFillObject");
|
|
12
|
-
expect(source).not.toContain("marginBottom: 94");
|
|
13
|
-
expect(source).not.toContain("bottom: 94");
|
|
14
|
-
});
|
|
15
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
|
|
4
|
-
const source = readFileSync(new URL("./SpacePanelSheet.tsx", import.meta.url), "utf8");
|
|
5
|
-
|
|
6
|
-
describe("SpacePanelSheet", () => {
|
|
7
|
-
it("switches between Chat and People while covering the dock", () => {
|
|
8
|
-
expect(source).toContain('controller.panel === "chat"');
|
|
9
|
-
expect(source).toContain("<SpaceChatSheet");
|
|
10
|
-
expect(source).toContain("<SpacePeopleSheet");
|
|
11
|
-
expect(source).toContain("StyleSheet.absoluteFillObject");
|
|
12
|
-
expect(source).not.toContain("marginBottom: 94");
|
|
13
|
-
expect(source).not.toContain("bottom: 94");
|
|
14
|
-
});
|
|
15
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
|
|
4
|
-
const source = readFileSync(new URL("./SpacePeopleSheet.tsx", import.meta.url), "utf8");
|
|
5
|
-
|
|
6
|
-
describe("SpacePeopleSheet", () => {
|
|
7
|
-
it("keeps Entrance admission and Participant action controls", () => {
|
|
8
|
-
expect(source).toContain(">At the Entrance<");
|
|
9
|
-
expect(source).toContain("controller.admitParticipant");
|
|
10
|
-
expect(source).toContain("controller.denyAdmission");
|
|
11
|
-
expect(source).toContain("accessibilityLabel={`Actions for ${participant.displayName}`}");
|
|
12
|
-
});
|
|
13
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
|
|
4
|
-
const source = readFileSync(new URL("./SpaceSurfacePrimitives.tsx", import.meta.url), "utf8");
|
|
5
|
-
|
|
6
|
-
describe("Space surface primitives", () => {
|
|
7
|
-
it("keeps accessible close targets and flat deterministic avatars", () => {
|
|
8
|
-
expect(source).toContain('accessibilityRole="button"');
|
|
9
|
-
expect(source).toContain("getParticipantInitials(name)");
|
|
10
|
-
expect(source).toContain("getParticipantColor(name)");
|
|
11
|
-
});
|
|
12
|
-
});
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
vi.mock("@hugeicons/core-free-icons/dist/esm/UserGroupIcon", () => ({ default: "UserGroupIcon" }));
|
|
4
|
-
vi.mock("@hugeicons/react-native", () => ({ HugeiconsIcon: "HugeiconsIcon" }));
|
|
5
|
-
vi.mock("react-native", () => ({
|
|
6
|
-
Image: "Image",
|
|
7
|
-
Platform: { OS: "android" },
|
|
8
|
-
StyleSheet: { create: <T,>(styles: T) => styles },
|
|
9
|
-
Text: "Text",
|
|
10
|
-
View: "View",
|
|
11
|
-
}));
|
|
12
|
-
vi.mock("../../ui/native-theme", () => ({
|
|
13
|
-
useNativeTheme: () => ({ colors: { darkCanvas: "#0a0a0b", border: "#1c1c1f", foreground: "#fbffff", mutedForeground: "#71717a", success: "#22c55e", surface: "#141418" } }),
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
import { SpaceTopBarAndroid } from "./SpaceTopBar.android";
|
|
17
|
-
|
|
18
|
-
describe("SpaceTopBarAndroid", () => {
|
|
19
|
-
it("keeps the space identity, elapsed duration, and participant count visible", () => {
|
|
20
|
-
const tree = SpaceTopBarAndroid({ spaceName: "Design space", participantCount: 4, formattedDuration: "1:02", logoUrl: "https://cdn.example.test/logo.png" });
|
|
21
|
-
|
|
22
|
-
const images = findElements(tree, "Image");
|
|
23
|
-
expect(images).toHaveLength(1);
|
|
24
|
-
expect(images[0]).toMatchObject({ props: { accessibilityLabel: "Chalk", source: { uri: "https://cdn.example.test/logo.png" } } });
|
|
25
|
-
expect(findText(tree)).toEqual(expect.arrayContaining(["Design space", "1:02", "4"]));
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
function findElements(value: unknown, type: string): { readonly props?: Record<string, unknown> }[] {
|
|
30
|
-
if (Array.isArray(value)) return value.flatMap((child) => findElements(child, type));
|
|
31
|
-
if (!value || typeof value !== "object") return [];
|
|
32
|
-
const element = value as { readonly type?: unknown; readonly props?: Record<string, unknown> };
|
|
33
|
-
const own = element.type === type ? [element] : [];
|
|
34
|
-
return [...own, ...findElements(element.props?.children, type)];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function findText(value: unknown): string[] {
|
|
38
|
-
if (typeof value === "string") return [value];
|
|
39
|
-
if (typeof value === "number") return [String(value)];
|
|
40
|
-
if (Array.isArray(value)) return value.flatMap(findText);
|
|
41
|
-
if (!value || typeof value !== "object") return [];
|
|
42
|
-
return findText((value as { readonly props?: { readonly children?: unknown } }).props?.children);
|
|
43
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const nativeTheme = vi.hoisted(() => ({ colorScheme: "light" as "light" | "dark" }));
|
|
4
|
-
|
|
5
|
-
vi.mock("react", () => ({
|
|
6
|
-
useCallback: <T,>(callback: T) => callback,
|
|
7
|
-
}));
|
|
8
|
-
vi.mock("react-native", () => ({
|
|
9
|
-
StyleSheet: { create: <Styles,>(styles: Styles) => styles },
|
|
10
|
-
}));
|
|
11
|
-
vi.mock("../../ui/native-theme", () => ({
|
|
12
|
-
useNativeTheme: () => nativeTheme,
|
|
13
|
-
}));
|
|
14
|
-
vi.mock("../EmbeddedWhiteboard", () => ({
|
|
15
|
-
EmbeddedWhiteboard: "EmbeddedWhiteboard",
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
import type { SpaceWhiteboardState } from "./useSpaceViewPanels";
|
|
19
|
-
import { forwardNativeSpaceWhiteboardFailure, forwardNativeSpaceWhiteboardMetric, shouldRenderNativeSpaceWhiteboard, SpaceWhiteboardSurface } from "./SpaceWhiteboardSurface";
|
|
20
|
-
|
|
21
|
-
describe("SpaceWhiteboardSurface", () => {
|
|
22
|
-
it("renders only for an open canonical whiteboard transport", () => {
|
|
23
|
-
expect(shouldRenderNativeSpaceWhiteboard(controller({ isOpen: false, transport: null }))).toBe(false);
|
|
24
|
-
expect(shouldRenderNativeSpaceWhiteboard(controller({ isOpen: true, transport: null }))).toBe(false);
|
|
25
|
-
expect(
|
|
26
|
-
shouldRenderNativeSpaceWhiteboard(
|
|
27
|
-
controller({
|
|
28
|
-
isOpen: true,
|
|
29
|
-
transport: {} as NonNullable<SpaceWhiteboardState["transport"]>,
|
|
30
|
-
}),
|
|
31
|
-
),
|
|
32
|
-
).toBe(true);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("forwards renderer metrics in production runtimes", () => {
|
|
36
|
-
const onMetric = vi.fn();
|
|
37
|
-
const metric = { name: "whiteboard.frame.delay_ms", value: 17 };
|
|
38
|
-
|
|
39
|
-
forwardNativeSpaceWhiteboardMetric(metric, onMetric);
|
|
40
|
-
|
|
41
|
-
expect(onMetric).toHaveBeenCalledWith(metric);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it("forwards renderer failures without relying on development logging", () => {
|
|
45
|
-
const onMetric = vi.fn();
|
|
46
|
-
forwardNativeSpaceWhiteboardFailure({ code: "renderer_load_failed", recoverable: true }, onMetric);
|
|
47
|
-
expect(onMetric).toHaveBeenCalledWith({
|
|
48
|
-
name: "whiteboard.renderer.failure",
|
|
49
|
-
value: 1,
|
|
50
|
-
attributes: { code: "renderer_load_failed", recoverable: true },
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const element = SpaceWhiteboardSurface({ whiteboard: controller({ isOpen: true, transport: {} as NonNullable<SpaceWhiteboardState["transport"]>, onMetric }) });
|
|
54
|
-
element?.props.onError({ code: "renderer_stopped", message: "renderer stopped", recoverable: true });
|
|
55
|
-
expect(onMetric).toHaveBeenCalledTimes(2);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it("passes the active NativeTheme color scheme to the embedded renderer", () => {
|
|
59
|
-
nativeTheme.colorScheme = "light";
|
|
60
|
-
const lightElement = SpaceWhiteboardSurface({ whiteboard: controller({ isOpen: true, transport: {} as NonNullable<SpaceWhiteboardState["transport"]> }) });
|
|
61
|
-
expect(lightElement).toMatchObject({ props: { theme: "light" } });
|
|
62
|
-
|
|
63
|
-
nativeTheme.colorScheme = "dark";
|
|
64
|
-
const darkElement = SpaceWhiteboardSurface({ whiteboard: controller({ isOpen: true, transport: {} as NonNullable<SpaceWhiteboardState["transport"]> }) });
|
|
65
|
-
expect(darkElement).toMatchObject({ props: { theme: "dark" } });
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
function controller(overrides: Partial<SpaceWhiteboardState>): SpaceWhiteboardState {
|
|
70
|
-
return {
|
|
71
|
-
isOpen: false,
|
|
72
|
-
canDraw: false,
|
|
73
|
-
canClear: false,
|
|
74
|
-
elements: [],
|
|
75
|
-
openParticipants: [],
|
|
76
|
-
transport: null,
|
|
77
|
-
journeyId: "journey-test",
|
|
78
|
-
open: vi.fn(),
|
|
79
|
-
close: vi.fn(),
|
|
80
|
-
toggle: vi.fn(),
|
|
81
|
-
requestSync: vi.fn(),
|
|
82
|
-
clear: vi.fn(),
|
|
83
|
-
...overrides,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { buildSpaceViewDiagnosticsSnapshot } from "./diagnostics";
|
|
4
|
-
|
|
5
|
-
describe("buildSpaceViewDiagnosticsSnapshot", () => {
|
|
6
|
-
it("surfaces canonical feature and moderation availability", () => {
|
|
7
|
-
const snapshot = buildSpaceViewDiagnosticsSnapshot({
|
|
8
|
-
featureFlags: {
|
|
9
|
-
chat: true,
|
|
10
|
-
participants: true,
|
|
11
|
-
screenShare: false,
|
|
12
|
-
reactions: true,
|
|
13
|
-
handRaise: true,
|
|
14
|
-
whiteboard: true,
|
|
15
|
-
},
|
|
16
|
-
canEndEpisode: false,
|
|
17
|
-
participantCount: 2,
|
|
18
|
-
raisedHandCount: 0,
|
|
19
|
-
unreadChatCount: 0,
|
|
20
|
-
isScreenShareActive: false,
|
|
21
|
-
isLocalScreenSharing: false,
|
|
22
|
-
screenShareSharerParticipantId: null,
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
expect(snapshot.actionAvailability.screenShare).toMatchObject({
|
|
26
|
-
enabled: false,
|
|
27
|
-
reason: "feature-disabled",
|
|
28
|
-
});
|
|
29
|
-
expect(snapshot.actionAvailability.moderation.reason).toBe("capability-unavailable");
|
|
30
|
-
});
|
|
31
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { formatSpaceDuration } from "./format-space-duration";
|
|
4
|
-
|
|
5
|
-
describe("formatSpaceDuration", () => {
|
|
6
|
-
it.each([
|
|
7
|
-
[0, "0:00"],
|
|
8
|
-
[59, "0:59"],
|
|
9
|
-
[125, "2:05"],
|
|
10
|
-
])("formats %s elapsed seconds", (secondsElapsed, expected) => {
|
|
11
|
-
expect(formatSpaceDuration(secondsElapsed)).toBe(expected);
|
|
12
|
-
});
|
|
13
|
-
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { nativeSpaceGridKey } from "./native-space-grid-keys";
|
|
4
|
-
|
|
5
|
-
describe("nativeSpaceGridKey", () => {
|
|
6
|
-
it("changes when the ordered participant ids change and identifies an empty page", () => {
|
|
7
|
-
expect(nativeSpaceGridKey("page", [{ id: "participant-a" }, { id: "participant-b" }] as never)).toBe("page-participant-a|participant-b");
|
|
8
|
-
expect(nativeSpaceGridKey("page", [{ id: "participant-b" }, { id: "participant-a" }] as never)).toBe("page-participant-b|participant-a");
|
|
9
|
-
expect(nativeSpaceGridKey("page", [])).toBe("page-empty");
|
|
10
|
-
});
|
|
11
|
-
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { createSpacePageStore } from "./native-space-page-store";
|
|
3
|
-
|
|
4
|
-
describe("createSpacePageStore", () => {
|
|
5
|
-
it("keeps a non-negative page and notifies subscribers when it changes", () => {
|
|
6
|
-
const store = createSpacePageStore();
|
|
7
|
-
const listener = vi.fn();
|
|
8
|
-
const unsubscribe = store.subscribe(listener);
|
|
9
|
-
|
|
10
|
-
store.setPage(2);
|
|
11
|
-
store.setPage(2);
|
|
12
|
-
store.clampToPageCount(1);
|
|
13
|
-
|
|
14
|
-
expect(store.getSnapshot()).toBe(0);
|
|
15
|
-
expect(listener).toHaveBeenCalledTimes(2);
|
|
16
|
-
|
|
17
|
-
unsubscribe();
|
|
18
|
-
store.setPage(3);
|
|
19
|
-
|
|
20
|
-
expect(store.getSnapshot()).toBe(3);
|
|
21
|
-
expect(listener).toHaveBeenCalledTimes(2);
|
|
22
|
-
});
|
|
23
|
-
});
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { CHALK_CHAT_ATTACHMENT_LIMITS } from "@q9labsai/chalk-client";
|
|
2
|
-
import { describe, expect, it, vi } from "vitest";
|
|
3
|
-
|
|
4
|
-
import { normalizeChatFileDrafts, uploadAndSendNativeChatAttachments } from "./space-chat-attachments";
|
|
5
|
-
|
|
6
|
-
describe("native Space chat attachments", () => {
|
|
7
|
-
it("accepts lazy file readers and enforces the client bounds", () => {
|
|
8
|
-
const result = normalizeChatFileDrafts([
|
|
9
|
-
{ name: "note.txt", type: "text/plain", size: 5, arrayBuffer: async () => new TextEncoder().encode("hello").buffer },
|
|
10
|
-
{ fileName: "image.png", mimeType: "image/png", bytes: new Uint8Array([1, 2]).buffer },
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
expect(result.error).toBeNull();
|
|
14
|
-
expect(result.files.map((file) => file.fileName)).toEqual(["note.txt", "image.png"]);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it("rejects unsupported types and excess staged files before upload", () => {
|
|
18
|
-
expect(normalizeChatFileDrafts([{ name: "script.js", type: "application/javascript", size: 1, arrayBuffer: async () => new ArrayBuffer(1) }])).toMatchObject({ files: [], error: "This file type is not supported in Space chat." });
|
|
19
|
-
const files = Array.from({ length: CHALK_CHAT_ATTACHMENT_LIMITS.maximumPerMessage + 1 }, (_, index) => ({ name: `note-${index}.txt`, type: "text/plain", size: 1, arrayBuffer: async () => new ArrayBuffer(1) }));
|
|
20
|
-
expect(normalizeChatFileDrafts(files)).toMatchObject({ files: [], error: `You can attach up to ${CHALK_CHAT_ATTACHMENT_LIMITS.maximumPerMessage} files per message.` });
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it("uploads every staged file before sending an attachment-only message", async () => {
|
|
24
|
-
const files = normalizeChatFileDrafts([{ name: "note.txt", type: "text/plain", size: 1, arrayBuffer: async () => new ArrayBuffer(1) }]).files;
|
|
25
|
-
const upload = vi.fn(async () => ({ attachmentId: "note.txt", fileName: "note.txt", mimeType: "text/plain" as const, byteLength: 1 }));
|
|
26
|
-
const send = vi.fn(async () => undefined);
|
|
27
|
-
|
|
28
|
-
await uploadAndSendNativeChatAttachments(files, "", upload, send);
|
|
29
|
-
|
|
30
|
-
expect(upload).toHaveBeenCalledOnce();
|
|
31
|
-
expect(send).toHaveBeenCalledWith({ text: "", attachments: [{ attachmentId: "note.txt", fileName: "note.txt", mimeType: "text/plain", byteLength: 1 }] });
|
|
32
|
-
});
|
|
33
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { buildParticipantActionDescriptors, formatChatTimestamp } from "./space-progressive-surface-helpers";
|
|
4
|
-
|
|
5
|
-
describe("space progressive surface helpers", () => {
|
|
6
|
-
it("only exposes capability-backed Participant actions", () => {
|
|
7
|
-
const actions = buildParticipantActionDescriptors({
|
|
8
|
-
canMuteParticipants: true,
|
|
9
|
-
canRequestMedia: false,
|
|
10
|
-
canStopParticipantCamera: false,
|
|
11
|
-
canStopParticipantScreenShare: false,
|
|
12
|
-
canRemoveParticipants: true,
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
expect(actions.map((action) => action.label)).toEqual(["Mute microphone", "Remove Participant"]);
|
|
16
|
-
expect(actions.at(-1)?.destructive).toBe(true);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it("formats valid chat timestamps and ignores empty metadata", () => {
|
|
20
|
-
expect(formatChatTimestamp(0)).toBe("");
|
|
21
|
-
expect(formatChatTimestamp(Number.NaN)).toBe("");
|
|
22
|
-
expect(formatChatTimestamp(Date.UTC(2026, 7, 4, 12, 34))).toMatch(/\d{1,2}:34/);
|
|
23
|
-
});
|
|
24
|
-
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
|
|
3
|
-
import type { SpaceViewControllerContractCheck } from "./useSpaceViewController.contract";
|
|
4
|
-
|
|
5
|
-
describe("useSpaceViewController contract", () => {
|
|
6
|
-
it("keeps the bidirectional return-shape assertion compiled", () => {
|
|
7
|
-
const contractCheck: SpaceViewControllerContractCheck = true;
|
|
8
|
-
expect(contractCheck).toBe(true);
|
|
9
|
-
});
|
|
10
|
-
});
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
|
|
3
|
-
const directClient = vi.hoisted(() => ({
|
|
4
|
-
chat: { files: { url: vi.fn(() => "https://example.test/file") }, loadOlder: vi.fn(async () => ({ status: "loaded" })), markRead: vi.fn(async () => null), send: vi.fn(async () => ({})) },
|
|
5
|
-
media: {
|
|
6
|
-
acceptRequest: vi.fn(async () => undefined),
|
|
7
|
-
declineRequest: vi.fn(async () => undefined),
|
|
8
|
-
setCameraEnabled: vi.fn(async () => undefined),
|
|
9
|
-
setMicrophoneEnabled: vi.fn(async () => undefined),
|
|
10
|
-
setScreenShareEnabled: vi.fn(async () => undefined),
|
|
11
|
-
},
|
|
12
|
-
participants: {
|
|
13
|
-
admit: vi.fn(async () => undefined),
|
|
14
|
-
assignRole: vi.fn(async () => undefined),
|
|
15
|
-
deny: vi.fn(async () => undefined),
|
|
16
|
-
lowerHand: vi.fn(async () => undefined),
|
|
17
|
-
mute: vi.fn(async () => undefined),
|
|
18
|
-
raiseHand: vi.fn(async () => undefined),
|
|
19
|
-
remove: vi.fn(async () => undefined),
|
|
20
|
-
renameSelf: vi.fn(async () => undefined),
|
|
21
|
-
requestMedia: vi.fn(async () => ({ status: "delivered" })),
|
|
22
|
-
stopScreenShare: vi.fn(async () => undefined),
|
|
23
|
-
stopVideo: vi.fn(async () => undefined),
|
|
24
|
-
},
|
|
25
|
-
reactions: { send: vi.fn(async () => ({})) },
|
|
26
|
-
whiteboard: { transport: vi.fn(() => null) },
|
|
27
|
-
}));
|
|
28
|
-
|
|
29
|
-
vi.mock("react", () => ({
|
|
30
|
-
useCallback: <T>(callback: T) => callback,
|
|
31
|
-
useEffect: () => undefined,
|
|
32
|
-
useMemo: <T>(factory: () => T) => factory(),
|
|
33
|
-
useState: <T>(initial: T): readonly [T, (next: T) => void] => [initial, vi.fn()],
|
|
34
|
-
}));
|
|
35
|
-
vi.mock("react-native", () => ({ Alert: { alert: vi.fn() }, Linking: { openURL: vi.fn(async () => undefined) } }));
|
|
36
|
-
vi.mock("../../context/space-client-context", () => ({ useSpaceClient: () => directClient }));
|
|
37
|
-
vi.mock("../../hooks/space-hooks", () => ({
|
|
38
|
-
useSelf: () => ({ participantId: "self", displayName: "Taylor", handRaised: false, can: (capability: string) => capability !== "endEpisode" }),
|
|
39
|
-
useParticipants: () => ({
|
|
40
|
-
roster: [
|
|
41
|
-
{
|
|
42
|
-
participantId: "self",
|
|
43
|
-
displayName: "Taylor",
|
|
44
|
-
role: "collaborator",
|
|
45
|
-
eligibleRoles: [],
|
|
46
|
-
capabilities: [],
|
|
47
|
-
handRaised: false,
|
|
48
|
-
media: { microphone: "active", camera: "active", screenShare: "inactive" },
|
|
49
|
-
presence: { state: "connected", speaking: false, activeSpeaker: false },
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
admissionQueue: [],
|
|
53
|
-
}),
|
|
54
|
-
useMedia: () => ({
|
|
55
|
-
local: {
|
|
56
|
-
microphone: { state: "enabled", track: null },
|
|
57
|
-
camera: { state: "enabled", track: null },
|
|
58
|
-
screen: { state: "disabled", track: null },
|
|
59
|
-
},
|
|
60
|
-
screenShare: { state: "disabled", track: null },
|
|
61
|
-
remote: [],
|
|
62
|
-
incomingRequests: [],
|
|
63
|
-
}),
|
|
64
|
-
useChat: () => ({ status: "ready", messages: [], pendingSends: [], readReceipts: [], unreadCount: 0, pagination: { cursor: null, hasOlder: false, historyTruncated: false } }),
|
|
65
|
-
useReactions: () => ({ active: [] }),
|
|
66
|
-
useWhiteboard: () => ({ engine: { status: "ready", sceneId: null, revision: null, error: null } }),
|
|
67
|
-
}));
|
|
68
|
-
vi.mock("../../utils/ios-simulator", () => ({ isIosSimulator: () => false }));
|
|
69
|
-
vi.mock("./useSpaceViewPanels", () => ({
|
|
70
|
-
useSpaceViewPanels: () => ({
|
|
71
|
-
layout: { layout: "grid" },
|
|
72
|
-
panel: null,
|
|
73
|
-
secondsElapsed: 5,
|
|
74
|
-
formattedDuration: "0:05",
|
|
75
|
-
actionsOpen: false,
|
|
76
|
-
reactionPickerOpen: false,
|
|
77
|
-
whiteboard: { isOpen: false, canDraw: true, canClear: false, elements: [], openParticipants: [], transport: null },
|
|
78
|
-
handleLeave: vi.fn(),
|
|
79
|
-
openPanel: vi.fn(),
|
|
80
|
-
closePanel: vi.fn(),
|
|
81
|
-
handleInviteParticipants: vi.fn(),
|
|
82
|
-
}),
|
|
83
|
-
}));
|
|
84
|
-
vi.mock("./useSpaceViewDerived", () => ({ useSpaceViewDerived: () => ({ isStageMode: false, gridPages: [], allParticipants: [] }) }));
|
|
85
|
-
|
|
86
|
-
import { useSpaceViewController } from "./useSpaceViewController";
|
|
87
|
-
|
|
88
|
-
describe("useSpaceViewController", () => {
|
|
89
|
-
it("binds native Space actions directly to the canonical SpaceClient", async () => {
|
|
90
|
-
const controller = useSpaceViewController({ spaceName: "Design review", onLeave: vi.fn() });
|
|
91
|
-
|
|
92
|
-
expect(controller.participants.localParticipant?.displayName).toBe("Taylor");
|
|
93
|
-
expect(controller.chat.isEnabled).toBe(true);
|
|
94
|
-
expect(controller.canSettings).toBe(true);
|
|
95
|
-
expect(controller.canInvite).toBe(false);
|
|
96
|
-
controller.toggleAudio();
|
|
97
|
-
controller.sendReaction("🎉");
|
|
98
|
-
controller.requestStartParticipantCamera("participant-2");
|
|
99
|
-
|
|
100
|
-
await vi.waitFor(() => {
|
|
101
|
-
expect(directClient.media.setMicrophoneEnabled).toHaveBeenCalledWith(false);
|
|
102
|
-
expect(directClient.reactions.send).toHaveBeenCalledWith("🎉");
|
|
103
|
-
expect(directClient.participants.requestMedia).toHaveBeenCalledWith("participant-2", "camera");
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
});
|