import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { clearWorksSquareSession, getValidWorksSquareAccessToken, getWorksSquareSessionSnapshot, storeWorksSquareSession, } from '@electron/services/works-square-session'; describe('works-square-session service', () => { beforeEach(() => { vi.useFakeTimers(); vi.setSystemTime(new Date('2026-07-06T08:00:00.000Z')); clearWorksSquareSession(); }); afterEach(() => { vi.useRealTimers(); clearWorksSquareSession(); }); it('returns the cached access token while it is outside the refresh skew', async () => { storeWorksSquareSession({ accessToken: 'access-token', refreshToken: 'refresh-token', tokenType: 'Bearer', expiresAt: Date.now() + 120_000, }); await expect(getValidWorksSquareAccessToken()).resolves.toBe('access-token'); expect(getWorksSquareSessionSnapshot()).toMatchObject({ accessToken: 'access-token', refreshToken: 'refresh-token', tokenType: 'Bearer', expiresAt: Date.now() + 120_000, }); }); it('refreshes the access token when the cached session is near expiry', async () => { const fetchImpl = vi.fn().mockResolvedValueOnce( new Response(JSON.stringify({ access_token: 'new-access-token', refresh_token: 'new-refresh-token', token_type: 'Bearer', expires_in: 43200, }), { status: 200 }), ); storeWorksSquareSession({ accessToken: 'old-access-token', refreshToken: 'old-refresh-token', tokenType: 'Bearer', expiresAt: Date.now() + 10_000, }); await expect(getValidWorksSquareAccessToken({ fetchImpl })).resolves.toBe('new-access-token'); expect(fetchImpl).toHaveBeenCalledWith( 'https://biz.nianxx.cn/auth/oauth2/token', expect.objectContaining({ method: 'POST', headers: expect.objectContaining({ Authorization: `Basic ${Buffer.from('app:app').toString('base64')}`, 'Content-Type': 'application/x-www-form-urlencoded', }), body: expect.any(URLSearchParams), }), ); const body = fetchImpl.mock.calls[0][1].body as URLSearchParams; expect(String(body)).toBe('grant_type=refresh_token&refresh_token=old-refresh-token'); expect(getWorksSquareSessionSnapshot()).toMatchObject({ accessToken: 'new-access-token', refreshToken: 'new-refresh-token', tokenType: 'Bearer', expiresAt: Date.now() + 43_200_000, }); }); it('returns null and clears the cached access token when refresh fails with 401', async () => { const fetchImpl = vi.fn().mockResolvedValueOnce( new Response(JSON.stringify({ msg: 'invalid refresh token' }), { status: 401 }), ); storeWorksSquareSession({ accessToken: 'old-access-token', refreshToken: 'old-refresh-token', tokenType: 'Bearer', expiresAt: Date.now() + 10_000, }); await expect(getValidWorksSquareAccessToken({ fetchImpl })).resolves.toBeNull(); expect(getWorksSquareSessionSnapshot()).toBeNull(); }); });