test(platform): verify client propagation

This commit is contained in:
Saravana Achu Mac 2026-05-05 09:33:10 -07:00
parent 3503ac86ad
commit efa20979fc
4 changed files with 198 additions and 0 deletions

View File

@ -0,0 +1,47 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { API_CONFIG } from './config';
import { getApiClient } from './client';
const { getAccessTokenMock } = vi.hoisted(() => ({
getAccessTokenMock: vi.fn(),
}));
const fetchMock = vi.fn();
vi.mock('./auth', () => ({
getAuthClient: () => ({
getAccessToken: getAccessTokenMock,
}),
}));
function jsonResponse(data: unknown, status = 200) {
return {
ok: status >= 200 && status < 300,
status,
statusText: status === 200 ? 'OK' : 'Error',
json: () => Promise.resolve(data),
};
}
describe('mobile API client', () => {
beforeEach(() => {
fetchMock.mockReset();
getAccessTokenMock.mockReset();
vi.stubGlobal('fetch', fetchMock);
});
it('propagates product identity, auth token, and request id through the shared API client', async () => {
getAccessTokenMock.mockReturnValue('mobile-token');
fetchMock.mockResolvedValue(jsonResponse({ ok: true }));
await getApiClient().fetch('/workspaces');
const [, init] = fetchMock.mock.calls[0] as [string, RequestInit];
const headers = init.headers as Record<string, string>;
expect(headers['x-product-id']).toBe(API_CONFIG.productId);
expect(headers.Authorization).toBe('Bearer mobile-token');
expect(headers['x-request-id']).toBeTruthy();
});
});

View File

@ -0,0 +1,46 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { API_CONFIG, PRODUCT_ID } from '../api/config';
const { createPlatformClientMock, getMock, getAccessTokenMock } = vi.hoisted(() => ({
createPlatformClientMock: vi.fn(),
getMock: vi.fn(),
getAccessTokenMock: vi.fn(),
}));
vi.mock('@bytelyst/platform-client', () => ({
createPlatformClient: createPlatformClientMock,
}));
vi.mock('./auth-helpers', () => ({
getAccessToken: getAccessTokenMock,
}));
import { getUserSettings } from './platform-api';
describe('mobile platform API wrapper', () => {
beforeEach(() => {
createPlatformClientMock.mockReset();
getMock.mockReset();
getAccessTokenMock.mockReset();
getAccessTokenMock.mockReturnValue('mobile-platform-token');
getMock.mockResolvedValue({ theme: 'dark' });
createPlatformClientMock.mockReturnValue({
get: getMock,
put: vi.fn(),
del: vi.fn(),
});
});
it('configures the shared platform client with product identity and auth token access', async () => {
await getUserSettings();
expect(createPlatformClientMock).toHaveBeenCalledWith({
baseUrl: API_CONFIG.platformBaseUrl,
productId: PRODUCT_ID,
getAccessToken: getAccessTokenMock,
});
expect(createPlatformClientMock.mock.calls[0][0].getAccessToken()).toBe('mobile-platform-token');
expect(getMock).toHaveBeenCalledWith('/settings');
});
});

View File

@ -0,0 +1,59 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createNotesApiClient, getAccessToken } from "@/lib/api-helpers";
import { PRODUCT_ID } from "@/lib/product-config";
const fetchMock = vi.fn();
const storage = new Map<string, string>();
const localStorageMock = {
getItem: vi.fn((key: string) => storage.get(key) ?? null),
setItem: vi.fn((key: string, value: string) => {
storage.set(key, value);
}),
clear: vi.fn(() => {
storage.clear();
}),
};
function jsonResponse(data: unknown, status = 200) {
return {
ok: status >= 200 && status < 300,
status,
statusText: status === 200 ? "OK" : "Error",
json: () => Promise.resolve(data),
};
}
describe("api-helpers", () => {
beforeEach(() => {
fetchMock.mockReset();
vi.stubGlobal("fetch", fetchMock);
storage.clear();
Object.defineProperty(window, "localStorage", {
configurable: true,
value: localStorageMock,
});
vi.stubGlobal("localStorage", localStorageMock);
});
it("reads the product-scoped access token from localStorage", () => {
localStorage.setItem(`${PRODUCT_ID}_access_token`, "web-token");
expect(getAccessToken()).toBe("web-token");
});
it("propagates product identity, auth token, and request id through the shared API client", async () => {
localStorage.setItem(`${PRODUCT_ID}_access_token`, "web-token");
fetchMock.mockResolvedValue(jsonResponse({ ok: true }));
const api = createNotesApiClient();
await api.fetch("/workspaces");
const [, init] = fetchMock.mock.calls[0] as [string, RequestInit];
const headers = init.headers as Record<string, string>;
expect(headers["x-product-id"]).toBe(PRODUCT_ID);
expect(headers.Authorization).toBe("Bearer web-token");
expect(headers["x-request-id"]).toBeTruthy();
});
});

View File

@ -0,0 +1,46 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { PLATFORM_SERVICE_URL, PRODUCT_ID } from "@/lib/product-config";
const { createPlatformClientMock, getMock, getAccessTokenMock } = vi.hoisted(() => ({
createPlatformClientMock: vi.fn(),
getMock: vi.fn(),
getAccessTokenMock: vi.fn(),
}));
vi.mock("@bytelyst/platform-client", () => ({
createPlatformClient: createPlatformClientMock,
}));
vi.mock("@/lib/api-helpers", () => ({
getAccessToken: getAccessTokenMock,
}));
import { getUserSettings } from "@/lib/platform";
describe("platform client wrapper", () => {
beforeEach(() => {
createPlatformClientMock.mockReset();
getMock.mockReset();
getAccessTokenMock.mockReset();
getAccessTokenMock.mockReturnValue("web-platform-token");
getMock.mockResolvedValue({ theme: "dark" });
createPlatformClientMock.mockReturnValue({
get: getMock,
put: vi.fn(),
del: vi.fn(),
});
});
it("configures the shared platform client with product identity and auth token access", async () => {
await getUserSettings();
expect(createPlatformClientMock).toHaveBeenCalledWith({
baseUrl: PLATFORM_SERVICE_URL,
productId: PRODUCT_ID,
getAccessToken: getAccessTokenMock,
});
expect(createPlatformClientMock.mock.calls[0][0].getAccessToken()).toBe("web-platform-token");
expect(getMock).toHaveBeenCalledWith("/settings");
});
});