feat: migrate runtime backend to node server

This commit is contained in:
victo
2026-04-08 16:41:29 +08:00
parent 9d2fc9e4b8
commit a83841ff2d
70 changed files with 8239 additions and 1561 deletions

View File

@@ -0,0 +1,113 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
const { requestJsonMock } = vi.hoisted(() => ({
requestJsonMock: vi.fn(),
}));
import {
clearStoredAccessToken,
clearStoredAutoAuthCredentials,
getStoredAccessToken,
getStoredAutoAuthCredentials,
} from './apiClient';
import {
authEntryWithStoredCredentials,
createAutoAuthCredentials,
ensureAutoAuthUser,
} from './authService';
function createMemoryStorage() {
const values = new Map<string, string>();
return {
getItem(key: string) {
return values.has(key) ? values.get(key)! : null;
},
setItem(key: string, value: string) {
values.set(key, value);
},
removeItem(key: string) {
values.delete(key);
},
clear() {
values.clear();
},
};
}
vi.mock('./apiClient', async () => {
const actual = await vi.importActual<typeof import('./apiClient')>('./apiClient');
return {
...actual,
requestJson: requestJsonMock,
};
});
describe('authService auto auth', () => {
beforeEach(() => {
vi.stubGlobal('window', {
localStorage: createMemoryStorage(),
dispatchEvent: vi.fn(),
});
requestJsonMock.mockReset();
clearStoredAccessToken();
clearStoredAutoAuthCredentials();
});
it('creates credentials that match current username/password constraints', () => {
const credentials = createAutoAuthCredentials();
expect(credentials.username).toMatch(/^guest_[a-z0-9]{12}$/u);
expect(credentials.password).toMatch(/^auto_[a-z0-9]{24}_[a-z0-9]{8}$/u);
expect(credentials.password.length).toBeGreaterThanOrEqual(6);
});
it('stores jwt and auto credentials after auth entry', async () => {
requestJsonMock.mockResolvedValue({
token: 'jwt-token-value',
user: {
id: 'user_1',
username: 'guest_abc123abc123',
},
});
const user = await authEntryWithStoredCredentials({
username: 'guest_abc123abc123',
password: 'auto_secret_password',
});
expect(user.username).toBe('guest_abc123abc123');
expect(getStoredAccessToken()).toBe('jwt-token-value');
expect(getStoredAutoAuthCredentials()).toEqual({
username: 'guest_abc123abc123',
password: 'auto_secret_password',
});
});
it('reuses stored auto credentials before generating a new account', async () => {
window.localStorage.setItem('genarrative.auth.auto-username.v1', 'guest_saveduser01');
window.localStorage.setItem('genarrative.auth.auto-password.v1', 'auto_saved_password');
requestJsonMock.mockResolvedValue({
token: 'jwt-restored',
user: {
id: 'user_saved',
username: 'guest_saveduser01',
},
});
const result = await ensureAutoAuthUser();
expect(result.user.username).toBe('guest_saveduser01');
expect(result.credentials).toEqual({
username: 'guest_saveduser01',
password: 'auto_saved_password',
});
expect(requestJsonMock).toHaveBeenCalledWith(
'/api/auth/entry',
expect.objectContaining({
method: 'POST',
}),
'登录失败',
);
});
});