195 lines
5.6 KiB
TypeScript
195 lines
5.6 KiB
TypeScript
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<string, unknown>;
|
|
setData: (patch: Record<string, unknown>) => void;
|
|
onLoad: (query?: Record<string, string>) => Promise<void>;
|
|
onShow: () => void;
|
|
consumePayResult: () => void;
|
|
};
|
|
|
|
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<typeof createWxMock>,
|
|
configOverrides: Record<string, unknown> = {},
|
|
) {
|
|
let pageConfig: Record<string, unknown> | null = null;
|
|
const source = readFileSync(pageScriptPath, 'utf8');
|
|
const sandbox = {
|
|
console,
|
|
getCurrentPages: () => [],
|
|
module: { exports: {} },
|
|
Page(config: Record<string, unknown>) {
|
|
pageConfig = config;
|
|
},
|
|
setTimeout(callback: () => void) {
|
|
callback();
|
|
return 1;
|
|
},
|
|
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<string, unknown>) },
|
|
setData(patch: Record<string, unknown>) {
|
|
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();
|
|
wxMock.login.mockImplementation(({ success }) => {
|
|
success({ code: 'wx-login-code' });
|
|
});
|
|
wxMock.request.mockImplementation(({ success }) => {
|
|
success({
|
|
statusCode: 200,
|
|
data: {
|
|
token: 'jwt-active-wechat',
|
|
bindingStatus: 'active',
|
|
},
|
|
});
|
|
});
|
|
const page = loadWebViewPage(wxMock);
|
|
|
|
await page.onLoad({});
|
|
|
|
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.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#auth_provider=wechat&auth_token=jwt-active-wechat&auth_binding_status=active',
|
|
);
|
|
});
|
|
|
|
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('onShow 二次检查支付结果并写回 web-view hash', () => {
|
|
const wxMock = createWxMock();
|
|
wxMock.getStorageSync.mockImplementation((key) =>
|
|
key === 'genarrative:wechat-pay-result'
|
|
? 'request-1:success:order-1'
|
|
: '',
|
|
);
|
|
const page = loadWebViewPage(wxMock);
|
|
page.data.webViewUrl =
|
|
'https://www.genarrative.world/?clientType=mini_program#tab=profile';
|
|
|
|
page.onShow();
|
|
|
|
expect(wxMock.removeStorageSync).toHaveBeenCalledWith(
|
|
'genarrative:wechat-pay-result',
|
|
);
|
|
expect(page.data.webViewUrl).toBe(
|
|
'https://www.genarrative.world/?clientType=mini_program#tab=profile&wx_pay_result=request-1%3Asuccess%3Aorder-1',
|
|
);
|
|
});
|
|
|
|
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);
|
|
});
|
|
});
|