import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import vm from 'node:vm'; import { beforeEach, describe, expect, test, vi } from 'vitest'; const repoRoot = process.cwd(); const pageScriptPath = join( repoRoot, 'miniprogram', 'pages', 'web-view', 'index.js', ); type MiniProgramPage = { data: Record; setData: (patch: Record) => void; onLoad: (query?: Record) => Promise; }; function createWxMock() { return { getStorageSync: vi.fn(() => ''), getSystemInfoSync: vi.fn(() => ({ platform: 'ios' })), login: vi.fn(), navigateBack: vi.fn(), removeStorageSync: vi.fn(), request: vi.fn(), setStorageSync: vi.fn(), }; } function loadWebViewPage( wxMock: ReturnType, configOverrides: Record = {}, ) { let pageConfig: Record | null = null; const source = readFileSync(pageScriptPath, 'utf8'); const sandbox = { console, getCurrentPages: () => [], module: { exports: {} }, Page(config: Record) { pageConfig = config; }, require(requestPath: string) { if (requestPath === '../../config') { return { API_BASE_URL: 'https://www.genarrative.world/', MINI_PROGRAM_APP_ID: 'wx-test-app', MINI_PROGRAM_ENV: 'release', WEB_VIEW_ENTRY_URL: 'https://www.genarrative.world/', WEB_VIEW_SOURCE_QUERY: { clientType: 'mini_program', clientRuntime: 'wechat_mini_program', }, ...configOverrides, }; } throw new Error(`Unexpected require: ${requestPath}`); }, wx: wxMock, }; vm.runInNewContext(source, sandbox, { filename: pageScriptPath }); if (!pageConfig) { throw new Error('web-view page did not call Page()'); } const page = { ...pageConfig, data: { ...(pageConfig.data as Record) }, setData(patch: Record) { Object.assign(this.data, patch); }, } as MiniProgramPage; return page; } describe('mini-program web-view auth page', () => { beforeEach(() => { vi.clearAllMocks(); }); test('默认进入时直接打开 web-view,不触发微信登录请求', async () => { const wxMock = createWxMock(); const page = loadWebViewPage(wxMock); await page.onLoad({}); expect(wxMock.login).not.toHaveBeenCalled(); expect(wxMock.request).not.toHaveBeenCalled(); expect(page.data.loading).toBe(false); expect(page.data.phoneBindingRequired).toBe(false); expect(page.data.webViewUrl).toBe( 'https://www.genarrative.world/?clientType=mini_program&clientRuntime=wechat_mini_program', ); }); test('默认匿名进入 web-view 不依赖 API_BASE_URL 配置', async () => { const wxMock = createWxMock(); const page = loadWebViewPage(wxMock, { API_BASE_URL: '', }); await page.onLoad({}); expect(wxMock.login).not.toHaveBeenCalled(); expect(wxMock.request).not.toHaveBeenCalled(); expect(page.data.errorMessage).toBe(''); expect(page.data.webViewUrl).toBe( 'https://www.genarrative.world/?clientType=mini_program&clientRuntime=wechat_mini_program', ); }); test('H5 请求登录时才启动微信小程序登录并进入手机号授权态', async () => { const wxMock = createWxMock(); wxMock.login.mockImplementation(({ success }) => { success({ code: 'wx-login-code' }); }); wxMock.request.mockImplementation(({ success }) => { success({ statusCode: 200, data: { token: 'jwt-pending-wechat', bindingStatus: 'pending_bind_phone', }, }); }); const page = loadWebViewPage(wxMock); await page.onLoad({ authAction: 'login', returnTo: 'previous' }); expect(wxMock.login).toHaveBeenCalledTimes(1); expect(wxMock.request).toHaveBeenCalledWith( expect.objectContaining({ url: 'https://www.genarrative.world/api/auth/wechat/miniprogram-login', method: 'POST', data: { code: 'wx-login-code' }, }), ); expect(page.data.webViewUrl).toBe(''); expect(page.data.loading).toBe(false); expect(page.data.phoneBindingRequired).toBe(true); }); });