103 lines
6.0 KiB
TypeScript
103 lines
6.0 KiB
TypeScript
import { closeElectronApp, expect, getStableWindow, test } from './fixtures/electron';
|
|
|
|
type WalletFixture = { requests: string[]; credited: boolean };
|
|
type FixtureGlobal = typeof globalThis & { __pointWalletE2E: WalletFixture };
|
|
|
|
test.describe('Permanent point wallet', () => {
|
|
test('hides recharge while retaining account controls and refreshing the balance', async ({ launchElectronApp }, testInfo) => {
|
|
const app = await launchElectronApp({ skipSetup: true });
|
|
try {
|
|
const page = await getStableWindow(app);
|
|
await expect(page.getByTestId('ai-module-selection-page')).toBeVisible();
|
|
const applicationUrl = page.url();
|
|
await page.goto('about:blank');
|
|
await app.evaluate(({ ipcMain }) => {
|
|
const state: WalletFixture = { requests: [], credited: false };
|
|
(globalThis as FixtureGlobal).__pointWalletE2E = state;
|
|
const result = (json: unknown) => ({ ok: true, data: { status: 200, ok: true, json } });
|
|
const points = () => ({
|
|
total: state.credited ? '500.00' : '0.00', used: '0.00', reserved: '0.00',
|
|
total_remaining: state.credited ? '500.00' : '0.00', entitlement_source: 'self',
|
|
family_shared: false, can_recharge: true, shared_available: null, expires_at: null,
|
|
});
|
|
ipcMain.removeHandler('hostapi:fetch');
|
|
ipcMain.handle('hostapi:fetch', async (_event, request: { path?: string; method?: string }) => {
|
|
const path = request.path ?? '';
|
|
const method = (request.method ?? 'GET').toUpperCase();
|
|
state.requests.push(method + ' ' + path);
|
|
if (path === '/api/auth/session/sync') return result({
|
|
success: true, session: {
|
|
accessToken: 'point-wallet-fixture-token', tokenType: 'Bearer',
|
|
expiresAt: Date.now() + 3_600_000, lastActiveAt: Date.now(), canRefresh: false,
|
|
},
|
|
});
|
|
if (path === '/api/auth/me') return result({
|
|
success: true,
|
|
user: { username: 'child-wallet', userId: 'child-wallet-user', tenantId: null, deptId: null, authorities: [] },
|
|
moduleAccess: { programming: true, design: true, robot: true },
|
|
});
|
|
if (path === '/api/works/user/agent-profile') return result({
|
|
success: true, profile: {
|
|
display_name: '小麦', age: null, gender: null, avatar_url: null,
|
|
share_age_with_agents: false, share_gender_with_agents: false, analysis_enabled: true,
|
|
completed: true, version: 1, updated_at: '2026-09-22T00:00:00Z',
|
|
},
|
|
});
|
|
if (path === '/api/works/billing/me') return result({ success: true, data: {
|
|
own_points: points(), points: points(), funding_error: null,
|
|
can_recharge: true, payment_configured: true, signup_bonus: '100.00', points_per_yuan: 50,
|
|
recharge_products: [{
|
|
id: 'product-e2e', name: '词元点数',
|
|
amount_cents: 1000, point_amount: '500.00', currency: 'CNY',
|
|
}],
|
|
} });
|
|
return { ok: false, error: { message: 'Unexpected fixture request: ' + method + ' ' + path } };
|
|
});
|
|
});
|
|
await page.goto(applicationUrl, { waitUntil: 'domcontentloaded' });
|
|
await page.getByTestId('ai-module-option-programming').click();
|
|
await expect(page.getByTestId('main-layout')).toBeVisible();
|
|
await expect(page.getByTestId('sidebar-member-menu-trigger')).toContainText('小麦');
|
|
await page.getByTestId('sidebar-member-menu-trigger').click();
|
|
await expect(page.getByTestId('sidebar-total-token-points')).toHaveText('0 点');
|
|
await expect(page.getByText('点数已用尽,请由家长完成当前账号充值。')).toBeVisible();
|
|
const menu = page.getByTestId('sidebar-account-menu');
|
|
await expect(menu.getByRole('menuitem', { name: '词元点数与充值' })).toHaveCount(0);
|
|
await expect(page.getByTestId('sidebar-point-wallet-open')).toHaveCount(0);
|
|
await expect(page.getByTestId('point-wallet-dialog')).toHaveCount(0);
|
|
await expect(menu.getByRole('menuitem', { name: '个人资料' })).toBeVisible();
|
|
await expect(menu.getByRole('menuitem', { name: '设置' })).toBeVisible();
|
|
await expect(menu.getByRole('menuitem', { name: '退出登录' })).toBeVisible();
|
|
await page.screenshot({ path: testInfo.outputPath('account-menu-recharge-hidden.png') });
|
|
|
|
await page.getByTestId('sidebar-member-menu-trigger').click();
|
|
await app.evaluate(() => { (globalThis as FixtureGlobal).__pointWalletE2E.credited = true; });
|
|
await page.getByTestId('sidebar-member-menu-trigger').click();
|
|
await expect(page.getByTestId('sidebar-total-token-points')).toHaveText('500 点');
|
|
await expect(page.getByText('点数已用尽,请由家长完成当前账号充值。')).toHaveCount(0);
|
|
await expect(page.getByTestId('sidebar-point-wallet-open')).toHaveCount(0);
|
|
|
|
await page.reload({ waitUntil: 'domcontentloaded' });
|
|
await page.getByTestId('sidebar-member-menu-trigger').click();
|
|
await expect(page.getByTestId('sidebar-total-token-points')).toHaveText('500 点');
|
|
await expect(page.getByTestId('sidebar-point-wallet-open')).toHaveCount(0);
|
|
expect(await app.evaluate(() => (globalThis as FixtureGlobal).__pointWalletE2E.requests.filter(
|
|
(request) => request.includes('/api/works/billing/recharge/') || request.includes('/api/works/billing/points/transactions'),
|
|
))).toEqual([]);
|
|
} catch (error) {
|
|
const page = app.windows().at(-1);
|
|
if (page && !page.isClosed()) {
|
|
await page.screenshot({ path: testInfo.outputPath('wallet-failure.png') });
|
|
await testInfo.attach('wallet-failure-dom', { body: await page.locator('body').innerText(), contentType: 'text/plain' });
|
|
}
|
|
await testInfo.attach('wallet-fixture-requests', {
|
|
body: JSON.stringify(await app.evaluate(() => (globalThis as FixtureGlobal).__pointWalletE2E.requests)),
|
|
contentType: 'application/json',
|
|
});
|
|
throw error;
|
|
} finally {
|
|
await closeElectronApp(app);
|
|
}
|
|
});
|
|
});
|