Makelore 2.0 initial clean snapshot
This commit is contained in:
91
tests/unit/works-square-session.test.ts
Normal file
91
tests/unit/works-square-session.test.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
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();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user