Use correct rageshake URL when running in embedded package + tests (#3132)
* Use correct rageshake URL when running in embedded package It was incorrectly trying to use the one from config.json * Refactor to add tests * Empty mock config
This commit is contained in:
@@ -30,7 +30,7 @@ import { PreferencesSettingsTab } from "./PreferencesSettingsTab";
|
|||||||
import { Slider } from "../Slider";
|
import { Slider } from "../Slider";
|
||||||
import { DeviceSelection } from "./DeviceSelection";
|
import { DeviceSelection } from "./DeviceSelection";
|
||||||
import { DeveloperSettingsTab } from "./DeveloperSettingsTab";
|
import { DeveloperSettingsTab } from "./DeveloperSettingsTab";
|
||||||
import { isRageshakeAvailable } from "./submit-rageshake";
|
import { useSubmitRageshake } from "./submit-rageshake";
|
||||||
|
|
||||||
type SettingsTab =
|
type SettingsTab =
|
||||||
| "audio"
|
| "audio"
|
||||||
@@ -71,6 +71,8 @@ export const SettingsModal: FC<Props> = ({
|
|||||||
|
|
||||||
const [showDeveloperSettingsTab] = useSetting(developerMode);
|
const [showDeveloperSettingsTab] = useSetting(developerMode);
|
||||||
|
|
||||||
|
const { available: isRageshakeAvailable } = useSubmitRageshake();
|
||||||
|
|
||||||
const audioTab: Tab<SettingsTab> = {
|
const audioTab: Tab<SettingsTab> = {
|
||||||
key: "audio",
|
key: "audio",
|
||||||
name: t("common.audio"),
|
name: t("common.audio"),
|
||||||
@@ -148,7 +150,7 @@ export const SettingsModal: FC<Props> = ({
|
|||||||
const tabs = [audioTab, videoTab];
|
const tabs = [audioTab, videoTab];
|
||||||
if (widget === null) tabs.push(profileTab);
|
if (widget === null) tabs.push(profileTab);
|
||||||
tabs.push(preferencesTab);
|
tabs.push(preferencesTab);
|
||||||
if (isRageshakeAvailable() || import.meta.env.VITE_PACKAGE === "full") {
|
if (isRageshakeAvailable || import.meta.env.VITE_PACKAGE === "full") {
|
||||||
// for full package we want to show the analytics consent checkbox
|
// for full package we want to show the analytics consent checkbox
|
||||||
// even if rageshake is not available
|
// even if rageshake is not available
|
||||||
tabs.push(feedbackTab);
|
tabs.push(feedbackTab);
|
||||||
|
|||||||
@@ -15,78 +15,12 @@ import {
|
|||||||
beforeEach,
|
beforeEach,
|
||||||
} from "vitest";
|
} from "vitest";
|
||||||
|
|
||||||
import {
|
import { getRageshakeSubmitUrl } from "./submit-rageshake";
|
||||||
getRageshakeSubmitUrl,
|
|
||||||
isRageshakeAvailable,
|
|
||||||
} from "./submit-rageshake";
|
|
||||||
import { getUrlParams } from "../UrlParams";
|
import { getUrlParams } from "../UrlParams";
|
||||||
import { mockConfig } from "../utils/test";
|
import { mockConfig } from "../utils/test";
|
||||||
|
|
||||||
vi.mock("../UrlParams", () => ({ getUrlParams: vi.fn() }));
|
vi.mock("../UrlParams", () => ({ getUrlParams: vi.fn() }));
|
||||||
|
|
||||||
describe("isRageshakeAvailable", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
(getUrlParams as Mock).mockReturnValue({});
|
|
||||||
mockConfig({});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
vi.unstubAllEnvs();
|
|
||||||
vi.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("embedded package", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.stubEnv("VITE_PACKAGE", "embedded");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns false with no rageshakeSubmitUrl URL param", () => {
|
|
||||||
expect(isRageshakeAvailable()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("ignores config value and returns false with no rageshakeSubmitUrl URL param", () => {
|
|
||||||
mockConfig({
|
|
||||||
rageshake: {
|
|
||||||
submit_url: "https://config.example.com.localhost",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(isRageshakeAvailable()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns true with rageshakeSubmitUrl URL param", () => {
|
|
||||||
(getUrlParams as Mock).mockReturnValue({
|
|
||||||
rageshakeSubmitUrl: "https://url.example.com.localhost",
|
|
||||||
});
|
|
||||||
expect(isRageshakeAvailable()).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("full package", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.stubEnv("VITE_PACKAGE", "full");
|
|
||||||
});
|
|
||||||
it("returns false with no config value", () => {
|
|
||||||
expect(isRageshakeAvailable()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("ignores rageshakeSubmitUrl URL param and returns false with no config value", () => {
|
|
||||||
(getUrlParams as Mock).mockReturnValue({
|
|
||||||
rageshakeSubmitUrl: "https://url.example.com.localhost",
|
|
||||||
});
|
|
||||||
expect(isRageshakeAvailable()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns true with config value", () => {
|
|
||||||
mockConfig({
|
|
||||||
rageshake: {
|
|
||||||
submit_url: "https://config.example.com.localhost",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(isRageshakeAvailable()).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("getRageshakeSubmitUrl", () => {
|
describe("getRageshakeSubmitUrl", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
(getUrlParams as Mock).mockReturnValue({});
|
(getUrlParams as Mock).mockReturnValue({});
|
||||||
|
|||||||
@@ -131,11 +131,9 @@ export function getRageshakeSubmitUrl(): string | undefined {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isRageshakeAvailable(): boolean {
|
export function useSubmitRageshake(
|
||||||
return !!getRageshakeSubmitUrl();
|
injectedGetRageshakeSubmitUrl = getRageshakeSubmitUrl,
|
||||||
}
|
): {
|
||||||
|
|
||||||
export function useSubmitRageshake(): {
|
|
||||||
submitRageshake: (opts: RageShakeSubmitOptions) => Promise<void>;
|
submitRageshake: (opts: RageShakeSubmitOptions) => Promise<void>;
|
||||||
sending: boolean;
|
sending: boolean;
|
||||||
sent: boolean;
|
sent: boolean;
|
||||||
@@ -158,7 +156,8 @@ export function useSubmitRageshake(): {
|
|||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
async (opts) => {
|
async (opts) => {
|
||||||
if (!getRageshakeSubmitUrl()) {
|
const submitUrl = injectedGetRageshakeSubmitUrl();
|
||||||
|
if (!submitUrl) {
|
||||||
throw new Error("No rageshake URL is configured");
|
throw new Error("No rageshake URL is configured");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +291,7 @@ export function useSubmitRageshake(): {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await fetch(Config.get().rageshake!.submit_url, {
|
const res = await fetch(submitUrl, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body,
|
body,
|
||||||
});
|
});
|
||||||
@@ -309,7 +308,7 @@ export function useSubmitRageshake(): {
|
|||||||
logger.error(error);
|
logger.error(error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[client, sending],
|
[client, sending, injectedGetRageshakeSubmitUrl],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -317,7 +316,7 @@ export function useSubmitRageshake(): {
|
|||||||
sending,
|
sending,
|
||||||
sent,
|
sent,
|
||||||
error,
|
error,
|
||||||
available: isRageshakeAvailable(),
|
available: !!injectedGetRageshakeSubmitUrl(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
222
src/settings/useSubmitRageshake.test.tsx
Normal file
222
src/settings/useSubmitRageshake.test.tsx
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2025 New Vector Ltd.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
expect,
|
||||||
|
describe,
|
||||||
|
it,
|
||||||
|
vi,
|
||||||
|
beforeEach,
|
||||||
|
afterEach,
|
||||||
|
type Mock,
|
||||||
|
} from "vitest";
|
||||||
|
import { useState, type ReactElement } from "react";
|
||||||
|
import { render, screen, waitFor } from "@testing-library/react";
|
||||||
|
import { type MatrixClient } from "matrix-js-sdk/lib/client";
|
||||||
|
|
||||||
|
import { useSubmitRageshake, getRageshakeSubmitUrl } from "./submit-rageshake";
|
||||||
|
import { ClientContextProvider } from "../ClientContext";
|
||||||
|
import { getUrlParams } from "../UrlParams";
|
||||||
|
import { mockConfig } from "../utils/test";
|
||||||
|
|
||||||
|
vi.mock("../UrlParams", () => ({ getUrlParams: vi.fn() }));
|
||||||
|
|
||||||
|
const TestComponent = ({
|
||||||
|
sendLogs,
|
||||||
|
getRageshakeSubmitUrl,
|
||||||
|
}: {
|
||||||
|
sendLogs: boolean;
|
||||||
|
getRageshakeSubmitUrl: () => string | undefined;
|
||||||
|
}): ReactElement => {
|
||||||
|
const [clickError, setClickError] = useState<Error | null>(null);
|
||||||
|
const { available, sending, sent, submitRageshake, error } =
|
||||||
|
useSubmitRageshake(getRageshakeSubmitUrl);
|
||||||
|
|
||||||
|
const onClick = (): void => {
|
||||||
|
submitRageshake({
|
||||||
|
sendLogs,
|
||||||
|
}).catch((e) => {
|
||||||
|
setClickError(e);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p data-testid="available">{available ? "true" : "false"}</p>
|
||||||
|
<p data-testid="sending">{sending ? "true" : "false"}</p>
|
||||||
|
<p data-testid="sent">{sent ? "true" : "false"}</p>
|
||||||
|
<p data-testid="error">{error?.message}</p>
|
||||||
|
<p data-testid="clickError">{clickError?.message}</p>
|
||||||
|
<button onClick={onClick} data-testid="submit">
|
||||||
|
submit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function renderWithMockClient(
|
||||||
|
getRageshakeSubmitUrl: () => string | undefined,
|
||||||
|
sendLogs: boolean,
|
||||||
|
): void {
|
||||||
|
const client = vi.mocked<MatrixClient>({
|
||||||
|
getUserId: vi.fn().mockReturnValue("@user:localhost"),
|
||||||
|
getUser: vi.fn().mockReturnValue(null),
|
||||||
|
credentials: {
|
||||||
|
userId: "@user:localhost",
|
||||||
|
},
|
||||||
|
getCrypto: vi.fn().mockReturnValue(undefined),
|
||||||
|
} as unknown as MatrixClient);
|
||||||
|
|
||||||
|
render(
|
||||||
|
<ClientContextProvider
|
||||||
|
value={{
|
||||||
|
state: "valid",
|
||||||
|
disconnected: false,
|
||||||
|
supportedFeatures: {
|
||||||
|
reactions: true,
|
||||||
|
thumbnails: true,
|
||||||
|
},
|
||||||
|
setClient: vi.fn(),
|
||||||
|
authenticated: {
|
||||||
|
client,
|
||||||
|
isPasswordlessUser: true,
|
||||||
|
changePassword: vi.fn(),
|
||||||
|
logout: vi.fn(),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TestComponent
|
||||||
|
sendLogs={sendLogs}
|
||||||
|
getRageshakeSubmitUrl={getRageshakeSubmitUrl}
|
||||||
|
/>
|
||||||
|
</ClientContextProvider>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("useSubmitRageshake", () => {
|
||||||
|
describe("available", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
(getUrlParams as Mock).mockReturnValue({});
|
||||||
|
mockConfig({});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.unstubAllEnvs();
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("embedded package", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.stubEnv("VITE_PACKAGE", "embedded");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false with no rageshakeSubmitUrl URL param", () => {
|
||||||
|
renderWithMockClient(getRageshakeSubmitUrl, false);
|
||||||
|
expect(screen.getByTestId("available").textContent).toBe("false");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores config value and returns false with no rageshakeSubmitUrl URL param", () => {
|
||||||
|
mockConfig({
|
||||||
|
rageshake: {
|
||||||
|
submit_url: "https://config.example.com.localhost",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
renderWithMockClient(getRageshakeSubmitUrl, false);
|
||||||
|
expect(screen.getByTestId("available").textContent).toBe("false");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns true with rageshakeSubmitUrl URL param", () => {
|
||||||
|
(getUrlParams as Mock).mockReturnValue({
|
||||||
|
rageshakeSubmitUrl: "https://url.example.com.localhost",
|
||||||
|
});
|
||||||
|
renderWithMockClient(getRageshakeSubmitUrl, false);
|
||||||
|
expect(screen.getByTestId("available").textContent).toBe("true");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("full package", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockConfig({});
|
||||||
|
vi.stubEnv("VITE_PACKAGE", "full");
|
||||||
|
});
|
||||||
|
it("returns false with no config value", () => {
|
||||||
|
renderWithMockClient(getRageshakeSubmitUrl, false);
|
||||||
|
expect(screen.getByTestId("available").textContent).toBe("false");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores rageshakeSubmitUrl URL param and returns false with no config value", () => {
|
||||||
|
(getUrlParams as Mock).mockReturnValue({
|
||||||
|
rageshakeSubmitUrl: "https://url.example.com.localhost",
|
||||||
|
});
|
||||||
|
renderWithMockClient(getRageshakeSubmitUrl, false);
|
||||||
|
expect(screen.getByTestId("available").textContent).toBe("false");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns true with config value", () => {
|
||||||
|
mockConfig({
|
||||||
|
rageshake: {
|
||||||
|
submit_url: "https://config.example.com.localhost",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
renderWithMockClient(getRageshakeSubmitUrl, false);
|
||||||
|
expect(screen.getByTestId("available").textContent).toBe("true");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when rageshake is available", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockConfig({});
|
||||||
|
vi.unstubAllGlobals();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("starts unsent", () => {
|
||||||
|
renderWithMockClient(() => "https://rageshake.localhost/foo", false);
|
||||||
|
expect(screen.getByTestId("sending").textContent).toBe("false");
|
||||||
|
expect(screen.getByTestId("sent").textContent).toBe("false");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("submitRageshake fetches expected URL", async () => {
|
||||||
|
const fetchFn = vi.fn().mockResolvedValue({
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
vi.stubGlobal("fetch", fetchFn);
|
||||||
|
|
||||||
|
renderWithMockClient(() => "https://rageshake.localhost/foo", false);
|
||||||
|
screen.getByTestId("submit").click();
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTestId("sent").textContent).toBe("true");
|
||||||
|
});
|
||||||
|
expect(fetchFn).toHaveBeenCalledExactlyOnceWith(
|
||||||
|
"https://rageshake.localhost/foo",
|
||||||
|
expect.objectContaining({
|
||||||
|
method: "POST",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(screen.getByTestId("clickError").textContent).toBe("");
|
||||||
|
expect(screen.getByTestId("error").textContent).toBe("");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when rageshake is not available", () => {
|
||||||
|
it("starts unsent", () => {
|
||||||
|
renderWithMockClient(() => undefined, false);
|
||||||
|
expect(screen.getByTestId("sending").textContent).toBe("false");
|
||||||
|
expect(screen.getByTestId("sent").textContent).toBe("false");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("submitRageshake throws error", async () => {
|
||||||
|
renderWithMockClient(() => undefined, false);
|
||||||
|
screen.getByTestId("submit").click();
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByTestId("clickError").textContent).toBe(
|
||||||
|
"No rageshake URL is configured",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user