test(ui): i corrected UI Testing
This commit is contained in:
@@ -0,0 +1,29 @@
|
|||||||
|
name: UI - Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["**"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ui
|
||||||
|
steps:
|
||||||
|
- name: Checkout source code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Bun
|
||||||
|
uses: oven-sh/setup-bun@v2
|
||||||
|
with:
|
||||||
|
bun-version: "1.3.11"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: bun install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Run unit tests
|
||||||
|
run: bun run test:unit -- --run
|
||||||
|
env:
|
||||||
|
PUBLIC_API_URL: "https://api.example.com"
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { expect, test } from "bun:test";
|
||||||
|
|
||||||
|
// UI unit tests use Vitest, not Bun's native test runner.
|
||||||
|
// Run them with: bun run test:unit -- --run
|
||||||
|
//
|
||||||
|
// This placeholder ensures `bun test` exits 0 rather than failing with "No tests found".
|
||||||
|
test("UI tests use Vitest - run with: bun run test:unit -- --run", () => {
|
||||||
|
expect(true).toBe(true);
|
||||||
|
});
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# The UI project uses Vitest (via `bun run test:unit`) for unit tests, not Bun's native test runner.
|
||||||
|
# Bun's runner lacks support for vi.hoisted, SvelteKit virtual modules ($env, $app), and jsdom.
|
||||||
|
#
|
||||||
|
# To run tests:
|
||||||
|
# Unit tests: bun run test:unit -- --run
|
||||||
|
# E2E tests: bun run test:e2e
|
||||||
|
# All tests: bun run test
|
||||||
|
#
|
||||||
|
# This configuration points Bun's test discovery at an isolated directory so that
|
||||||
|
# `bun test` does not erroneously pick up Vitest-formatted spec files.
|
||||||
|
[test]
|
||||||
|
root = ".bun-tests"
|
||||||
@@ -10,7 +10,7 @@ const { mockApi } = vi.hoisted(() => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("../axios", () => ({
|
vi.mock("$lib/optima-api/axios", () => ({
|
||||||
default: mockApi,
|
default: mockApi,
|
||||||
api: mockApi,
|
api: mockApi,
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const { mockApi } = vi.hoisted(() => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("../axios", () => ({
|
vi.mock("$lib/optima-api/axios", () => ({
|
||||||
default: mockApi,
|
default: mockApi,
|
||||||
api: mockApi,
|
api: mockApi,
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
const { mockRedirect, mockAxiosPost, mockIo, mockApi } = vi.hoisted(() => ({
|
const { mockRedirect, mockAxiosPost, mockApi } = vi.hoisted(() => ({
|
||||||
mockRedirect: vi.fn(),
|
mockRedirect: vi.fn(),
|
||||||
mockAxiosPost: vi.fn(),
|
mockAxiosPost: vi.fn(),
|
||||||
mockIo: vi.fn(),
|
|
||||||
mockApi: {
|
mockApi: {
|
||||||
get: vi.fn(),
|
get: vi.fn(),
|
||||||
post: vi.fn(),
|
post: vi.fn(),
|
||||||
@@ -27,13 +26,13 @@ vi.mock("axios", () => ({
|
|||||||
post: mockAxiosPost,
|
post: mockAxiosPost,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("../axios", () => ({
|
vi.mock("$lib/optima-api/axios", () => ({
|
||||||
default: mockApi,
|
default: mockApi,
|
||||||
api: mockApi,
|
api: mockApi,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("socket.io-client", () => ({
|
vi.mock("socket.io-client", () => ({
|
||||||
io: mockIo,
|
io: vi.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
import { user } from "./user";
|
import { user } from "./user";
|
||||||
@@ -128,45 +127,38 @@ describe("user module", () => {
|
|||||||
expect(result).toBe(fakeRedirect);
|
expect(result).toBe(fakeRedirect);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("awaitAuthCallback resolves when socket event delivers tokens", async () => {
|
it("awaitAuthCallback resolves when polling returns 200 with tokens", async () => {
|
||||||
const handlers: Record<string, (payload?: any) => void> = {};
|
const mockFetch = vi
|
||||||
const disconnect = vi.fn();
|
.fn()
|
||||||
|
.mockResolvedValueOnce({
|
||||||
mockIo.mockReturnValueOnce({
|
status: 202,
|
||||||
on: vi.fn((event: string, callback: (payload?: any) => void) => {
|
})
|
||||||
handlers[event] = callback;
|
.mockResolvedValueOnce({
|
||||||
|
status: 200,
|
||||||
|
json: vi.fn().mockResolvedValue({
|
||||||
|
data: { accessToken: "access", refreshToken: "refresh" },
|
||||||
}),
|
}),
|
||||||
disconnect,
|
});
|
||||||
|
vi.stubGlobal("fetch", mockFetch);
|
||||||
|
|
||||||
|
const result = await user.awaitAuthCallback("cb-key");
|
||||||
|
|
||||||
|
expect(result).toEqual({ accessToken: "access", refreshToken: "refresh" });
|
||||||
|
expect(mockFetch).toHaveBeenCalledWith(
|
||||||
|
"https://api.example.com/v1/auth/callback/cb-key"
|
||||||
|
);
|
||||||
|
|
||||||
|
vi.unstubAllGlobals();
|
||||||
});
|
});
|
||||||
|
|
||||||
const promise = user.awaitAuthCallback("cb-key");
|
it("awaitAuthCallback rejects when polling returns unexpected status", async () => {
|
||||||
|
const mockFetch = vi.fn().mockResolvedValue({ status: 500 });
|
||||||
|
vi.stubGlobal("fetch", mockFetch);
|
||||||
|
|
||||||
handlers["auth:login:callback:cb-key"]?.({
|
await expect(user.awaitAuthCallback("cb-key")).rejects.toThrow(
|
||||||
accessToken: "access",
|
"Unexpected status 500"
|
||||||
refreshToken: "refresh",
|
);
|
||||||
});
|
|
||||||
|
|
||||||
await expect(promise).resolves.toEqual({
|
vi.unstubAllGlobals();
|
||||||
accessToken: "access",
|
|
||||||
refreshToken: "refresh",
|
|
||||||
});
|
|
||||||
expect(disconnect).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("awaitAuthCallback rejects on connect_error", async () => {
|
|
||||||
const handlers: Record<string, (payload?: any) => void> = {};
|
|
||||||
|
|
||||||
mockIo.mockReturnValueOnce({
|
|
||||||
on: vi.fn((event: string, callback: (payload?: any) => void) => {
|
|
||||||
handlers[event] = callback;
|
|
||||||
}),
|
|
||||||
disconnect: vi.fn(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const promise = user.awaitAuthCallback("cb-key");
|
|
||||||
|
|
||||||
handlers.connect_error?.(new Error("socket failed"));
|
|
||||||
|
|
||||||
await expect(promise).rejects.toThrow("socket failed");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Actions, redirect } from "@sveltejs/kit";
|
import { Actions, redirect } from "@sveltejs/kit";
|
||||||
import { optima } from "$lib";
|
import { optima } from "$lib";
|
||||||
import { INTERNAL_API_URL } from "$env/static/private";
|
|
||||||
|
|
||||||
export const actions: Actions = {
|
export const actions: Actions = {
|
||||||
login: async (event) => {
|
login: async (event) => {
|
||||||
@@ -8,7 +7,6 @@ export const actions: Actions = {
|
|||||||
|
|
||||||
const tokens = await optima.user.awaitAuthCallback(
|
const tokens = await optima.user.awaitAuthCallback(
|
||||||
data.get("callbackKey") as string,
|
data.get("callbackKey") as string,
|
||||||
INTERNAL_API_URL,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
event.cookies.set("accessToken", tokens.accessToken, {
|
event.cookies.set("accessToken", tokens.accessToken, {
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ describe("admin/users +page.server.ts", () => {
|
|||||||
return {
|
return {
|
||||||
get: (key: string) => entries[key] ?? null,
|
get: (key: string) => entries[key] ?? null,
|
||||||
getAll: (key: string) => (entries[key] ? [entries[key]] : []),
|
getAll: (key: string) => (entries[key] ? [entries[key]] : []),
|
||||||
|
has: (key: string) => key in entries,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const { mockOptima, mockCheckPermissions, mockHandleApiError } = vi.hoisted(
|
|||||||
sales: {
|
sales: {
|
||||||
fetchOne: vi.fn(),
|
fetchOne: vi.fn(),
|
||||||
fetchWorkflowStatus: vi.fn(),
|
fetchWorkflowStatus: vi.fn(),
|
||||||
|
fetchOpportunityTypes: vi.fn(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mockCheckPermissions: vi.fn(),
|
mockCheckPermissions: vi.fn(),
|
||||||
@@ -34,6 +35,7 @@ describe("sales/opportunity/[id] +page.server.ts load", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
vi.spyOn(console, "error").mockImplementation(() => {});
|
vi.spyOn(console, "error").mockImplementation(() => {});
|
||||||
|
mockOptima.sales.fetchOpportunityTypes.mockResolvedValue({ data: [] });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns empty data when no token", async () => {
|
it("returns empty data when no token", async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user