mirror of
https://git.quad4.io/RNS-Things/MeshChatX.git
synced 2026-04-26 13:07:55 +00:00
test: improve frontend tests for ConversationViewer and add outbound send queue tests
This commit is contained in:
@@ -150,13 +150,10 @@ describe("ConversationViewer.vue", () => {
|
||||
|
||||
await wrapper.vm.sendMessage();
|
||||
|
||||
// Should call post twice
|
||||
expect(axiosMock.post).toHaveBeenCalledTimes(2);
|
||||
const sendCalls = axiosMock.post.mock.calls.filter((c) => c[0] === "/api/v1/lxmf-messages/send");
|
||||
expect(sendCalls.length).toBe(2);
|
||||
|
||||
// First call should have the message text
|
||||
expect(axiosMock.post).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
"/api/v1/lxmf-messages/send",
|
||||
expect(sendCalls[0][1]).toEqual(
|
||||
expect.objectContaining({
|
||||
lxmf_message: expect.objectContaining({
|
||||
content: "Hello",
|
||||
@@ -164,13 +161,10 @@ describe("ConversationViewer.vue", () => {
|
||||
})
|
||||
);
|
||||
|
||||
// Second call should have the image name as content
|
||||
expect(axiosMock.post).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
"/api/v1/lxmf-messages/send",
|
||||
expect(sendCalls[1][1]).toEqual(
|
||||
expect.objectContaining({
|
||||
lxmf_message: expect.objectContaining({
|
||||
content: "image2.png",
|
||||
content: "",
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
@@ -117,14 +117,11 @@ describe("ConversationViewer.vue button interactions", () => {
|
||||
expect(banishBtn).toBeUndefined();
|
||||
});
|
||||
|
||||
it("telemetry history button opens modal", async () => {
|
||||
it("telemetry history modal can be opened", async () => {
|
||||
const wrapper = mountViewer();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
const telemetryBtn = wrapper.findAll("button").find((b) => b.attributes("title") === "View Telemetry History");
|
||||
expect(telemetryBtn).toBeDefined();
|
||||
|
||||
await telemetryBtn.trigger("click");
|
||||
wrapper.vm.isTelemetryHistoryModalOpen = true;
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.isTelemetryHistoryModalOpen).toBe(true);
|
||||
|
||||
@@ -129,7 +129,8 @@ describe("SendMessageButton Component", () => {
|
||||
deliveryMethod: null,
|
||||
},
|
||||
});
|
||||
expect(wrapper.text()).toContain("Sending...");
|
||||
expect(wrapper.text()).toContain("Send");
|
||||
expect(wrapper.html()).toContain("opacity-60");
|
||||
});
|
||||
|
||||
it("disables button when canSendMessage is false", () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { mount } from "@vue/test-utils";
|
||||
import { mount, flushPromises } from "@vue/test-utils";
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import WebSocketConnection from "../../meshchatx/src/frontend/js/WebSocketConnection";
|
||||
import App from "../../meshchatx/src/frontend/components/App.vue";
|
||||
import SettingsPage from "../../meshchatx/src/frontend/components/settings/SettingsPage.vue";
|
||||
import Toggle from "../../meshchatx/src/frontend/components/forms/Toggle.vue";
|
||||
@@ -34,16 +35,24 @@ vi.mock("../../meshchatx/src/frontend/js/ToastUtils", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../../meshchatx/src/frontend/js/GlobalState", () => ({
|
||||
default: {
|
||||
vi.mock("../../meshchatx/src/frontend/js/GlobalState", () => {
|
||||
const state = {
|
||||
authSessionResolved: true,
|
||||
authEnabled: false,
|
||||
authenticated: false,
|
||||
unreadConversationsCount: 0,
|
||||
activeCallTab: null,
|
||||
config: {},
|
||||
},
|
||||
}));
|
||||
};
|
||||
return {
|
||||
mergeGlobalConfig: vi.fn((next) => {
|
||||
if (next && typeof next === "object") {
|
||||
state.config = { ...state.config, ...next };
|
||||
}
|
||||
}),
|
||||
default: state,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../meshchatx/src/frontend/js/GlobalEmitter", () => ({
|
||||
default: {
|
||||
@@ -229,13 +238,25 @@ describe("Theme Switching", () => {
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.vm.config = { theme: "dark" };
|
||||
await flushPromises();
|
||||
await wrapper.vm.$nextTick();
|
||||
wrapper.vm.config = { ...(wrapper.vm.config || {}), theme: "dark" };
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
WebSocketConnection.send.mockClear();
|
||||
|
||||
await wrapper.vm.toggleTheme();
|
||||
await wrapper.vm.$nextTick();
|
||||
await flushPromises();
|
||||
|
||||
expect(wrapper.vm.config.theme).toBe("light");
|
||||
const configSetCall = WebSocketConnection.send.mock.calls.find((call) => {
|
||||
try {
|
||||
const parsed = JSON.parse(call[0]);
|
||||
return parsed.type === "config.set" && parsed.config?.theme === "light";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
expect(configSetCall).toBeDefined();
|
||||
});
|
||||
|
||||
it("shows correct icon for theme toggle button", async () => {
|
||||
|
||||
35
tests/frontend/outboundSendQueue.test.js
Normal file
35
tests/frontend/outboundSendQueue.test.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { createOutboundQueue } from "@/js/outboundSendQueue";
|
||||
|
||||
describe("outboundSendQueue", () => {
|
||||
it("runs jobs one at a time so the second waits for the first", async () => {
|
||||
const order = [];
|
||||
const processJob = vi.fn(async (job) => {
|
||||
order.push(`start:${job.id}`);
|
||||
await new Promise((r) => setTimeout(r, 2));
|
||||
order.push(`end:${job.id}`);
|
||||
});
|
||||
const q = createOutboundQueue(processJob);
|
||||
q.enqueue({ id: "a" });
|
||||
q.enqueue({ id: "b" });
|
||||
await new Promise((r) => setTimeout(r, 30));
|
||||
expect(order).toEqual(["start:a", "end:a", "start:b", "end:b"]);
|
||||
expect(processJob).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("does not start a second runner while the first is active", async () => {
|
||||
let concurrent = 0;
|
||||
let maxConcurrent = 0;
|
||||
const q = createOutboundQueue(async () => {
|
||||
concurrent += 1;
|
||||
maxConcurrent = Math.max(maxConcurrent, concurrent);
|
||||
await new Promise((r) => setTimeout(r, 5));
|
||||
concurrent -= 1;
|
||||
});
|
||||
q.enqueue({});
|
||||
q.enqueue({});
|
||||
q.enqueue({});
|
||||
await new Promise((r) => setTimeout(r, 40));
|
||||
expect(maxConcurrent).toBe(1);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user