统一微信壳桥接目录
新增 miniprogram/shell 承接微信 Page 生命周期与 wx 容器调用 收窄微信页面入口为 shell 页面工厂装配 更新三端 host-bridge/shell 目录门禁与认证 smoke 补充微信 shell 测试与 CommonJS 测试加载工具 同步宿主壳架构文档和项目共享记忆 补齐 api-server 外部生成测试 fixture 更新时间字段
This commit is contained in:
@@ -17,6 +17,16 @@ const expectedWechatHostBridgeFiles = [
|
||||
'wechatHostBridgeWebView.js',
|
||||
'wechatHostBridgeWebView.test.js',
|
||||
];
|
||||
const expectedWechatShellFiles = [
|
||||
'wechatShellPayment.js',
|
||||
'wechatShellPayment.test.js',
|
||||
'wechatShellShareGrid.js',
|
||||
'wechatShellShareGrid.test.js',
|
||||
'wechatShellSubscribeMessage.js',
|
||||
'wechatShellSubscribeMessage.test.js',
|
||||
'wechatShellWebView.js',
|
||||
'wechatShellWebView.test.js',
|
||||
];
|
||||
const expectedMobileHostBridgeFiles = [
|
||||
'mobileHostBridge.test.ts',
|
||||
'mobileHostBridge.ts',
|
||||
@@ -210,15 +220,33 @@ function assertHostBridgeLayerLayout() {
|
||||
'wechat host bridge files',
|
||||
);
|
||||
|
||||
for (const pagePath of [
|
||||
const wechatShellFiles = fs
|
||||
.readdirSync('miniprogram/shell', { withFileTypes: true })
|
||||
.filter((entry) => entry.isFile())
|
||||
.map((entry) => entry.name)
|
||||
.sort();
|
||||
assertSameList(
|
||||
wechatShellFiles,
|
||||
expectedWechatShellFiles,
|
||||
'wechat shell files',
|
||||
);
|
||||
|
||||
const wechatPagePaths = [
|
||||
'miniprogram/pages/web-view/index.js',
|
||||
'miniprogram/pages/wechat-pay/index.js',
|
||||
'miniprogram/pages/share-grid/index.js',
|
||||
'miniprogram/pages/subscribe-message/index.js',
|
||||
]) {
|
||||
];
|
||||
for (const pagePath of wechatPagePaths) {
|
||||
const source = fs.readFileSync(pagePath, 'utf8');
|
||||
if (source.includes("require('./index.shared')")) {
|
||||
throw new Error(`${pagePath} must import from miniprogram/host-bridge`);
|
||||
if (!source.includes("require('../../shell/")) {
|
||||
throw new Error(`${pagePath} must import from miniprogram/shell`);
|
||||
}
|
||||
if (
|
||||
source.includes("require('../../host-bridge/") ||
|
||||
source.includes("require('./index.shared')")
|
||||
) {
|
||||
throw new Error(`${pagePath} must not import bridge logic directly`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,22 +54,27 @@ if (failures.length > 0) {
|
||||
console.log('\n[wechat-miniprogram-auth-smoke] 通过');
|
||||
|
||||
function checkMiniProgramShell() {
|
||||
const shellPath = join(repoRoot, 'miniprogram', 'pages', 'web-view', 'index.js');
|
||||
const shellPath = join(repoRoot, 'miniprogram', 'shell', 'wechatShellWebView.js');
|
||||
const webViewBridgePath = join(repoRoot, 'miniprogram', 'host-bridge', 'wechatHostBridgeWebView.js');
|
||||
const pagePath = join(repoRoot, 'miniprogram', 'pages', 'web-view', 'index.js');
|
||||
const shellTemplatePath = join(repoRoot, 'miniprogram', 'pages', 'web-view', 'index.wxml');
|
||||
const authServiceTestPath = join(repoRoot, 'src', 'services', 'authService.test.ts');
|
||||
|
||||
ensureNeedles(pagePath, ["require('../../shell/wechatShellWebView')"]);
|
||||
ensureNeedles(shellPath, [
|
||||
'/api/auth/wechat/miniprogram-login',
|
||||
'/api/auth/wechat/bind-phone',
|
||||
"'x-client-type': MINI_PROGRAM_CLIENT_TYPE",
|
||||
"'x-client-runtime': MINI_PROGRAM_CLIENT_RUNTIME",
|
||||
'auth_provider',
|
||||
'auth_token',
|
||||
'auth_binding_status',
|
||||
'bindingStatus',
|
||||
'pending_bind_phone',
|
||||
'wechatPhoneCode',
|
||||
]);
|
||||
ensureNeedles(webViewBridgePath, [
|
||||
'auth_provider',
|
||||
'auth_token',
|
||||
'auth_binding_status',
|
||||
]);
|
||||
|
||||
ensureNeedles(shellTemplatePath, ['getPhoneNumber', 'bindgetphonenumber']);
|
||||
|
||||
|
||||
@@ -5,12 +5,17 @@ import vm from 'node:vm';
|
||||
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
const pageScriptPath = join(
|
||||
const shellScriptPath = join(
|
||||
repoRoot,
|
||||
'miniprogram',
|
||||
'pages',
|
||||
'web-view',
|
||||
'index.js',
|
||||
'shell',
|
||||
'wechatShellWebView.js',
|
||||
);
|
||||
const webViewHostBridgePath = join(
|
||||
repoRoot,
|
||||
'miniprogram',
|
||||
'host-bridge',
|
||||
'wechatHostBridgeWebView.js',
|
||||
);
|
||||
|
||||
type MiniProgramPage = {
|
||||
@@ -43,45 +48,28 @@ 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;
|
||||
(globalThis as unknown as { wx: ReturnType<typeof createWxMock> }).wx =
|
||||
wxMock;
|
||||
const webViewBridge = loadCommonJsModule(webViewHostBridgePath, {});
|
||||
const shellModule = loadCommonJsModule(shellScriptPath, {
|
||||
'../config': {
|
||||
API_BASE_URL: 'https://www.genarrative.world/',
|
||||
DEV_API_BASE_URL: 'https://dev.genarrative.world/',
|
||||
DEV_WEB_VIEW_ENTRY_URL: 'https://dev.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,
|
||||
},
|
||||
setTimeout(callback: () => void) {
|
||||
callback();
|
||||
return 1;
|
||||
},
|
||||
require(requestPath: string) {
|
||||
if (requestPath === '../../config') {
|
||||
return {
|
||||
API_BASE_URL: 'https://www.genarrative.world/',
|
||||
DEV_API_BASE_URL: 'https://dev.genarrative.world/',
|
||||
DEV_WEB_VIEW_ENTRY_URL: 'https://dev.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,
|
||||
'../host-bridge/wechatHostBridgeWebView': webViewBridge,
|
||||
}) as {
|
||||
createWechatWebViewPage: () => Record<string, unknown>;
|
||||
};
|
||||
|
||||
vm.runInNewContext(source, sandbox, { filename: pageScriptPath });
|
||||
|
||||
if (!pageConfig) {
|
||||
throw new Error('web-view page did not call Page()');
|
||||
}
|
||||
const pageConfig = shellModule.createWechatWebViewPage();
|
||||
|
||||
const page = {
|
||||
...pageConfig,
|
||||
@@ -94,6 +82,34 @@ function loadWebViewPage(
|
||||
return page;
|
||||
}
|
||||
|
||||
function loadCommonJsModule(
|
||||
filePath: string,
|
||||
requireMap: Record<string, unknown>,
|
||||
) {
|
||||
const source = readFileSync(filePath, 'utf8');
|
||||
const module = { exports: {} as Record<string, unknown> };
|
||||
const sandbox = {
|
||||
console,
|
||||
getCurrentPages: () => [],
|
||||
module,
|
||||
exports: module.exports,
|
||||
setTimeout(callback: () => void) {
|
||||
callback();
|
||||
return 1;
|
||||
},
|
||||
require(requestPath: string) {
|
||||
if (Object.prototype.hasOwnProperty.call(requireMap, requestPath)) {
|
||||
return requireMap[requestPath];
|
||||
}
|
||||
throw new Error(`Unexpected require: ${requestPath}`);
|
||||
},
|
||||
wx: globalThis.wx,
|
||||
};
|
||||
|
||||
vm.runInNewContext(source, sandbox, { filename: filePath });
|
||||
return module.exports;
|
||||
}
|
||||
|
||||
describe('mini-program web-view auth page', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
@@ -264,6 +280,10 @@ describe('mini-program web-view auth page', () => {
|
||||
data: {
|
||||
token: 'jwt-pending-wechat',
|
||||
bindingStatus: 'pending_bind_phone',
|
||||
user: {
|
||||
displayName: '陶泥玩家',
|
||||
publicUserCode: 'SY-12345678',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user