fix: 保留小程序登录上下文
This commit is contained in:
@@ -132,7 +132,37 @@ describe('appPageRoutes', () => {
|
||||
|
||||
expect(window.location.pathname).toBe('/creation/rpg/result');
|
||||
expect(window.location.search).toBe(
|
||||
'?sessionId=session-1&profileId=profile-1&draftId=draft-1&workId=work-1',
|
||||
'?sessionId=session-1&profileId=profile-1&draftId=draft-1&workId=work-1&clientRuntime=wechat_mini_program',
|
||||
);
|
||||
});
|
||||
|
||||
it('preserves mini program runtime context while normalizing app paths', () => {
|
||||
window.history.replaceState(
|
||||
null,
|
||||
'',
|
||||
'/?clientType=mini_program&clientRuntime=wechat_mini_program&miniProgramEnv=trial',
|
||||
);
|
||||
|
||||
pushAppHistoryPath('/');
|
||||
|
||||
expect(window.location.pathname).toBe('/');
|
||||
expect(window.location.search).toBe(
|
||||
'?clientType=mini_program&clientRuntime=wechat_mini_program&miniProgramEnv=trial',
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps mini program runtime context when navigating to explicit query routes', () => {
|
||||
window.history.replaceState(
|
||||
null,
|
||||
'',
|
||||
'/?clientRuntime=wechat_mini_program',
|
||||
);
|
||||
|
||||
pushAppHistoryPath('/works/detail?work=PZ-7A7B18D9');
|
||||
|
||||
expect(window.location.pathname).toBe('/works/detail');
|
||||
expect(window.location.search).toBe(
|
||||
'?work=PZ-7A7B18D9&clientRuntime=wechat_mini_program',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -72,6 +72,12 @@ const ROUTE_STAGE_BY_PATH = new Map(
|
||||
STAGE_ROUTE_ENTRIES.map(([stage, path]) => [path, stage] as const),
|
||||
) as Map<string, SelectionStage>;
|
||||
|
||||
const APP_RUNTIME_CONTEXT_QUERY_KEYS = [
|
||||
'clientType',
|
||||
'clientRuntime',
|
||||
'miniProgramEnv',
|
||||
] as const;
|
||||
|
||||
export function normalizeAppPath(pathname: string) {
|
||||
const trimmedPathname = pathname.trim().toLowerCase();
|
||||
|
||||
@@ -135,13 +141,12 @@ export function isKnownMainAppPagePath(pathname: string) {
|
||||
export function pushAppHistoryPath(path: string) {
|
||||
const nextUrl = new URL(path, window.location.origin);
|
||||
const normalizedPath = normalizeAppPath(nextUrl.pathname);
|
||||
const nextSearch =
|
||||
nextUrl.search ||
|
||||
buildPreservedAppSearch(
|
||||
window.location.pathname,
|
||||
normalizedPath,
|
||||
window.location.search,
|
||||
);
|
||||
const nextSearch = buildPreservedAppSearch(
|
||||
nextUrl.search,
|
||||
window.location.pathname,
|
||||
normalizedPath,
|
||||
window.location.search,
|
||||
);
|
||||
const nextRelativeUrl = `${normalizedPath}${nextSearch}`;
|
||||
const currentRelativeUrl = `${normalizeAppPath(window.location.pathname)}${window.location.search}`;
|
||||
if (currentRelativeUrl === nextRelativeUrl) {
|
||||
@@ -153,16 +158,39 @@ export function pushAppHistoryPath(path: string) {
|
||||
}
|
||||
|
||||
function buildPreservedAppSearch(
|
||||
explicitNextSearch: string,
|
||||
currentPathname: string,
|
||||
normalizedPath: string,
|
||||
search: string,
|
||||
) {
|
||||
const preservedParams = new URLSearchParams(explicitNextSearch);
|
||||
|
||||
if (
|
||||
!isCreationRestorePath(normalizedPath) ||
|
||||
!isSameCreationFlowPath(currentPathname, normalizedPath)
|
||||
!explicitNextSearch &&
|
||||
isCreationRestorePath(normalizedPath) &&
|
||||
isSameCreationFlowPath(currentPathname, normalizedPath)
|
||||
) {
|
||||
return '';
|
||||
const creationParams = new URLSearchParams(
|
||||
buildCreationUrlSearchFromParams(search),
|
||||
);
|
||||
creationParams.forEach((value, key) => {
|
||||
preservedParams.set(key, value);
|
||||
});
|
||||
}
|
||||
|
||||
return buildCreationUrlSearchFromParams(search);
|
||||
const currentParams = new URLSearchParams(search);
|
||||
// 中文注释:小程序 WebView 依赖这些宿主上下文判断登录和充值通道,不能被前端阶段导航清掉。
|
||||
APP_RUNTIME_CONTEXT_QUERY_KEYS.forEach((key) => {
|
||||
if (preservedParams.has(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const value = currentParams.get(key)?.trim();
|
||||
if (value) {
|
||||
preservedParams.set(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
const queryString = preservedParams.toString();
|
||||
return queryString ? `?${queryString}` : '';
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
getCurrentAuthUser,
|
||||
getPublicAuthUserById,
|
||||
liftAuthRiskBlock,
|
||||
isWechatMiniProgramWebViewRuntime,
|
||||
loginWithPhoneCode,
|
||||
logoutAllAuthSessions,
|
||||
redeemRegistrationInviteCode,
|
||||
@@ -80,6 +81,7 @@ function createWindowMock(overrides: Record<string, unknown> = {}) {
|
||||
|
||||
describe('authService', () => {
|
||||
beforeEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
vi.clearAllMocks();
|
||||
vi.stubGlobal('window', createWindowMock());
|
||||
clearStoredAccessToken({ emit: false });
|
||||
@@ -428,6 +430,26 @@ describe('authService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('detects mini program user agent before the WeChat bridge is ready', () => {
|
||||
vi.stubGlobal('navigator', {
|
||||
userAgent:
|
||||
'Mozilla/5.0 iPhone MicroMessenger/8.0.49 NetType/WIFI Language/zh_CN miniProgram',
|
||||
});
|
||||
vi.stubGlobal(
|
||||
'window',
|
||||
createWindowMock({
|
||||
location: {
|
||||
pathname: '/',
|
||||
hash: '',
|
||||
search: '',
|
||||
assign: vi.fn(),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(isWechatMiniProgramWebViewRuntime()).toBe(true);
|
||||
});
|
||||
|
||||
it('waits for an existing WeChat JS SDK script before opening the native auth page', async () => {
|
||||
const navigateTo = vi.fn((options: { url: string; success?: () => void }) => {
|
||||
options.success?.();
|
||||
|
||||
@@ -90,9 +90,15 @@ export function isWechatMiniProgramWebViewRuntime() {
|
||||
}
|
||||
|
||||
const params = new URLSearchParams(window.location.search || '');
|
||||
const userAgent =
|
||||
typeof navigator === 'undefined' ? '' : navigator.userAgent || '';
|
||||
const normalizedUserAgent = userAgent.toLowerCase();
|
||||
|
||||
return (
|
||||
params.get('clientRuntime') === 'wechat_mini_program' ||
|
||||
params.get('clientType') === 'mini_program' ||
|
||||
(normalizedUserAgent.includes('micromessenger') &&
|
||||
normalizedUserAgent.includes('miniprogram')) ||
|
||||
Boolean(window.wx?.miniProgram?.postMessage)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user