修复客户端更新诊断与错误展示
This commit is contained in:
@@ -5,6 +5,10 @@ const electronMocks = vi.hoisted(() => ({
|
||||
ipcHandle: vi.fn(),
|
||||
}));
|
||||
|
||||
const loggerMocks = vi.hoisted(() => ({
|
||||
error: vi.fn(),
|
||||
}));
|
||||
|
||||
const updaterMocks = vi.hoisted(() => {
|
||||
const listeners = new Map<string, Array<(...args: unknown[]) => void>>();
|
||||
const autoUpdater = {
|
||||
@@ -41,7 +45,7 @@ vi.mock('@electron/utils/logger', () => ({
|
||||
logger: {
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
error: loggerMocks.error,
|
||||
debug: vi.fn(),
|
||||
},
|
||||
}));
|
||||
@@ -127,6 +131,97 @@ describe('AppUpdater feed delegation', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('reports a concise actionable error when the stable feed has no latest manifest', async () => {
|
||||
const rawError = new Error(
|
||||
'Cannot find channel "latest.yml" update info: HttpError: 404\n' +
|
||||
'GET https://square.nianxx.cn/api/app-updates/windows/x64/latest.yml',
|
||||
);
|
||||
updaterMocks.autoUpdater.checkForUpdates.mockRejectedValue(rawError);
|
||||
const updater = new AppUpdater();
|
||||
const rendererSend = vi.fn();
|
||||
updater.setMainWindow({
|
||||
isDestroyed: () => false,
|
||||
webContents: { send: rendererSend },
|
||||
} as unknown as Parameters<AppUpdater['setMainWindow']>[0]);
|
||||
|
||||
await expect(updater.checkForUpdates()).rejects.toBe(rawError);
|
||||
|
||||
expect(updater.getStatus()).toMatchObject({
|
||||
status: 'error',
|
||||
error: '当前平台的正式更新包尚未发布,请稍后重试或从官网下载最新版',
|
||||
});
|
||||
expect(rendererSend.mock.calls.filter(([channel, status]) => (
|
||||
channel === 'update:status-changed' && status?.status === 'error'
|
||||
))).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('reports one error status when electron-updater emits and rejects the same check error', async () => {
|
||||
const rawError = new Error(
|
||||
'Cannot find channel "latest.yml" update info: HttpError: 404\n' +
|
||||
'GET https://square.nianxx.cn/api/app-updates/windows/x64/latest.yml',
|
||||
);
|
||||
const updater = new AppUpdater();
|
||||
const errorListener = vi.fn();
|
||||
const rendererSend = vi.fn();
|
||||
updater.on('error', errorListener);
|
||||
updater.setMainWindow({
|
||||
isDestroyed: () => false,
|
||||
webContents: { send: rendererSend },
|
||||
} as unknown as Parameters<AppUpdater['setMainWindow']>[0]);
|
||||
let rejectSharedCheck!: (error: Error) => void;
|
||||
const sharedCheck = new Promise<never>((_resolve, reject) => {
|
||||
rejectSharedCheck = reject;
|
||||
});
|
||||
updaterMocks.autoUpdater.checkForUpdates.mockImplementationOnce(() => sharedCheck);
|
||||
updaterMocks.autoUpdater.checkForUpdates.mockImplementationOnce(() => sharedCheck);
|
||||
updaterMocks.autoUpdater.checkForUpdates.mockImplementationOnce(async () => {
|
||||
const updaterErrorListeners = updaterMocks.listeners.get('error') ?? [];
|
||||
updaterErrorListeners.at(-1)?.(rawError);
|
||||
throw rawError;
|
||||
});
|
||||
|
||||
const firstCheck = updater.checkForUpdates();
|
||||
const concurrentCheck = updater.checkForUpdates();
|
||||
const updaterErrorListeners = updaterMocks.listeners.get('error') ?? [];
|
||||
updaterErrorListeners.at(-1)?.(rawError);
|
||||
rejectSharedCheck(rawError);
|
||||
|
||||
await expect(Promise.allSettled([firstCheck, concurrentCheck])).resolves.toEqual([
|
||||
{ status: 'rejected', reason: rawError },
|
||||
{ status: 'rejected', reason: rawError },
|
||||
]);
|
||||
|
||||
expect(rendererSend.mock.calls.filter(([channel, status]) => (
|
||||
channel === 'update:status-changed' && status?.status === 'error'
|
||||
))).toHaveLength(1);
|
||||
expect(errorListener).toHaveBeenCalledOnce();
|
||||
expect(errorListener).toHaveBeenCalledWith(rawError);
|
||||
expect(loggerMocks.error).toHaveBeenCalledWith('[Updater] Check for updates failed:', rawError);
|
||||
|
||||
await expect(updater.checkForUpdates()).rejects.toBe(rawError);
|
||||
|
||||
expect(rendererSend.mock.calls.filter(([channel, status]) => (
|
||||
channel === 'update:status-changed' && status?.status === 'error'
|
||||
))).toHaveLength(2);
|
||||
expect(errorListener).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('reports the same actionable error when the macOS stable feed has no latest manifest', async () => {
|
||||
const rawError = new Error(
|
||||
'Cannot find channel "latest-mac.yml" update info: HttpError: 404\n' +
|
||||
'GET https://square.nianxx.cn/api/app-updates/mac/arm64/latest-mac.yml',
|
||||
);
|
||||
updaterMocks.autoUpdater.checkForUpdates.mockRejectedValue(rawError);
|
||||
const updater = new AppUpdater();
|
||||
|
||||
await expect(updater.checkForUpdates()).rejects.toBe(rawError);
|
||||
|
||||
expect(updater.getStatus()).toMatchObject({
|
||||
status: 'error',
|
||||
error: '当前平台的正式更新包尚未发布,请稍后重试或从官网下载最新版',
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps prerelease channels on their existing electron-updater feed', async () => {
|
||||
electronMocks.getVersion.mockReturnValue('0.9.2-beta.1');
|
||||
updaterMocks.autoUpdater.checkForUpdates.mockResolvedValue({
|
||||
|
||||
Reference in New Issue
Block a user