- Add `ConnectivityIssue.vue` component for displaying server connection issues. - Implement polling logic with retry intervals to check server health. - Update i18n with new connectivity issue messages. - Add unit tests to cover connectivity failure and recovery scenarios. - Update test suite for breadth of coverage, including router contract and timer cleanup.
114 lines
3.2 KiB
JavaScript
114 lines
3.2 KiB
JavaScript
// @vitest-environment jsdom
|
|
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { enableAutoUnmount } from "@vue/test-utils";
|
|
import { mountWithApp } from "./helpers/mountWithApp.js";
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
pingApiServer: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("@/services/apiHealth.js", () => ({
|
|
pingApiServer: mocks.pingApiServer,
|
|
}));
|
|
|
|
import ConnectivityIssue from "@/views/errors/ConnectivityIssue.vue";
|
|
|
|
enableAutoUnmount(afterEach);
|
|
|
|
const messages = {
|
|
en: {
|
|
connectivity: {
|
|
title: "Connectivity issue",
|
|
subtitle: "Check your connection",
|
|
description: "Waiting for the server",
|
|
retry_in: "Retrying in {seconds} seconds",
|
|
retry_now: "Retrying now",
|
|
retry: "Retry",
|
|
footer: "Contact support",
|
|
},
|
|
},
|
|
};
|
|
|
|
const mountConnectivityIssue = () =>
|
|
mountWithApp(ConnectivityIssue, {
|
|
messages,
|
|
slots: {
|
|
default: '<div data-testid="app-content">App content</div>',
|
|
},
|
|
global: {
|
|
stubs: {
|
|
BIcon: true,
|
|
},
|
|
},
|
|
});
|
|
|
|
const flushPromises = async () => {
|
|
await Promise.resolve();
|
|
await Promise.resolve();
|
|
};
|
|
|
|
describe("ConnectivityIssue", () => {
|
|
beforeEach(() => {
|
|
mocks.pingApiServer.mockReset();
|
|
vi.spyOn(console, "error").mockImplementation(() => {});
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("shows content after a healthy ping without continuing to poll", async () => {
|
|
vi.useFakeTimers();
|
|
mocks.pingApiServer.mockResolvedValue({ ok: true, status: 200, error: null });
|
|
|
|
const wrapper = mountConnectivityIssue();
|
|
await flushPromises();
|
|
|
|
expect(wrapper.find('[data-testid="app-content"]').exists()).toBe(true);
|
|
expect(wrapper.find('[data-testid="connectivity-issue"]').exists()).toBe(false);
|
|
|
|
await vi.advanceTimersByTimeAsync(20_000);
|
|
|
|
expect(mocks.pingApiServer).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("retries after a failed ping and stops retrying once the API is healthy", async () => {
|
|
vi.useFakeTimers();
|
|
mocks.pingApiServer
|
|
.mockResolvedValueOnce({ ok: false, status: 500, error: null })
|
|
.mockResolvedValueOnce({ ok: true, status: 200, error: null });
|
|
|
|
const wrapper = mountConnectivityIssue();
|
|
await flushPromises();
|
|
|
|
expect(wrapper.find('[data-testid="connectivity-issue"]').exists()).toBe(true);
|
|
expect(wrapper.find('[data-testid="app-content"]').exists()).toBe(false);
|
|
|
|
await vi.advanceTimersByTimeAsync(5_000);
|
|
await flushPromises();
|
|
|
|
expect(mocks.pingApiServer).toHaveBeenCalledTimes(2);
|
|
expect(wrapper.find('[data-testid="app-content"]').exists()).toBe(true);
|
|
expect(wrapper.find('[data-testid="connectivity-issue"]').exists()).toBe(false);
|
|
|
|
await vi.advanceTimersByTimeAsync(10_000);
|
|
|
|
expect(mocks.pingApiServer).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it("clears pending retry work when unmounted", async () => {
|
|
vi.useFakeTimers();
|
|
mocks.pingApiServer.mockResolvedValue({ ok: false, status: 500, error: null });
|
|
|
|
const wrapper = mountConnectivityIssue();
|
|
await flushPromises();
|
|
|
|
wrapper.unmount();
|
|
await vi.advanceTimersByTimeAsync(5_000);
|
|
|
|
expect(mocks.pingApiServer).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|