宿主侧故障不再落面板卡片

view/project-development/export/state/useXhsMinitoolExport.ts:refresh 与 buildOnce 遇到 exportUnavailable 不再 setFailure,直接抛给全局错误池上报;persist 同样只上报不落卡片。
tests/xhsMinitoolExport.test.tsx:更新为断言 failure 始终为空、同一个故障只抛一次。
This commit is contained in:
2026-10-06 22:00:23 +08:00
parent 3a4b58e834
commit 26120af5ac
2 changed files with 15 additions and 16 deletions
@@ -241,11 +241,12 @@ export function useXhsMinitoolExport({
throwToErrorPool(String(error), error);
return null;
}
setFailure(structured);
// 宿主侧事实故障:先让面板显示现场,再抛进错误池(策略拒绝等预期拒绝不走这一步)。
if (structured.type === 'exportUnavailable') {
// 宿主侧事实故障:面板不接管(不留失败卡片),直接抛给全局错误池上报;下一次轮询会自然重试。
throwToErrorPool(JSON.stringify(structured), error);
return null;
}
setFailure(structured);
return null;
} finally {
if (isInitialRead) {
@@ -303,12 +304,10 @@ export function useXhsMinitoolExport({
}
if (structured.type === 'formInvalid') setFieldError(structured);
else if (structured.type === 'saveConflict') setConflict(structured);
else {
setFailure(structured);
if (structured.type === 'exportUnavailable') {
throwToErrorPool(JSON.stringify(structured), error);
}
}
else if (structured.type === 'exportUnavailable') {
// 宿主侧事实故障:不落面板,直接抛给全局错误池上报。
throwToErrorPool(JSON.stringify(structured), error);
} else setFailure(structured);
return false;
}
},
@@ -367,10 +366,12 @@ export function useXhsMinitoolExport({
throwToErrorPool(String(error), error);
return;
}
setFailure(structured);
if (structured.type === 'exportUnavailable') {
// 宿主侧事实故障:不落面板,直接抛给全局错误池上报。
throwToErrorPool(JSON.stringify(structured), error);
return;
}
setFailure(structured);
}
}, [projectPath, throwToErrorPool]);
@@ -1017,7 +1017,7 @@ describe('状态 hook', () => {
await expect(result.current.packageAll()).resolves.toBeUndefined();
});
it('宿主侧事实故障先给卡片、再把同一个故障抛一次', async () => {
it('宿主侧事实故障原样抛出进错误池,面板不留卡片', async () => {
const invoke = vi.fn(async (command: string) => {
if (command === 'read_xhs_minitool_export') {
return { form: FORM, hasScript: true };
@@ -1036,18 +1036,16 @@ describe('状态 hook', () => {
);
await waitFor(() => expect(result.current.form).toEqual(FORM));
// 卡片照常给现场,同时原样抛出(真实 WebView 里由全局 handler 结算进错误池)。
// 宿主故障交给全局错误池上报,面板不接管:原样抛出,failure 保持为空。
await act(async () => {
await expect(result.current.packageAll()).rejects.toBeInstanceOf(Error);
});
// 面板留下的就是宿主那个原始错误,用户那句话是渲染时从变体推的。
expect(result.current.failure).toEqual({
type: 'exportUnavailable',
cause: '项目根不可用:找不到目录',
});
expect(result.current.failure).toBeNull();
// 同一个故障只抛一次(轮询会反复读到它,不能让错误池的 count 变成轮询次数)。
await act(async () => {
await expect(result.current.packageAll()).resolves.toBeUndefined();
});
expect(result.current.failure).toBeNull();
});
it('帮我填:先把没保存的输入落盘,再把改注册表这件事交给同一个会话', async () => {