189 lines
6.8 KiB
TypeScript
189 lines
6.8 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
const electronMocks = vi.hoisted(() => ({
|
|
getVersion: vi.fn(() => '0.9.1'),
|
|
ipcHandle: vi.fn(),
|
|
}));
|
|
|
|
const updaterMocks = vi.hoisted(() => {
|
|
const listeners = new Map<string, Array<(...args: unknown[]) => void>>();
|
|
const autoUpdater = {
|
|
autoDownload: false,
|
|
autoInstallOnAppQuit: true,
|
|
logger: null as unknown,
|
|
channel: 'latest',
|
|
on: vi.fn((event: string, listener: (...args: unknown[]) => void) => {
|
|
const current = listeners.get(event) ?? [];
|
|
current.push(listener);
|
|
listeners.set(event, current);
|
|
return autoUpdater;
|
|
}),
|
|
setFeedURL: vi.fn(),
|
|
checkForUpdates: vi.fn(),
|
|
downloadUpdate: vi.fn(),
|
|
quitAndInstall: vi.fn(),
|
|
};
|
|
return { autoUpdater, listeners };
|
|
});
|
|
|
|
vi.mock('electron', () => ({
|
|
app: {
|
|
getVersion: electronMocks.getVersion,
|
|
isPackaged: true,
|
|
},
|
|
BrowserWindow: vi.fn(),
|
|
ipcMain: { handle: electronMocks.ipcHandle },
|
|
}));
|
|
|
|
vi.mock('electron-updater', () => ({ autoUpdater: updaterMocks.autoUpdater }));
|
|
|
|
vi.mock('@electron/utils/logger', () => ({
|
|
logger: {
|
|
info: vi.fn(),
|
|
warn: vi.fn(),
|
|
error: vi.fn(),
|
|
debug: vi.fn(),
|
|
},
|
|
}));
|
|
|
|
import { AppUpdater, resolveUpdateFeed } from '@electron/main/updater';
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
describe('resolveUpdateFeed', () => {
|
|
it('routes stable Windows x64 updates through Works Square', () => {
|
|
expect(resolveUpdateFeed('0.9.2', 'win32', 'x64')).toEqual({
|
|
channel: 'latest',
|
|
url: 'https://square.nianxx.cn/api/app-updates/windows/x64',
|
|
});
|
|
});
|
|
|
|
it.each(['x64', 'arm64'])('routes stable macOS %s updates through Works Square', (architecture) => {
|
|
expect(resolveUpdateFeed('0.9.2', 'darwin', architecture)).toEqual({
|
|
channel: 'latest',
|
|
url: `https://square.nianxx.cn/api/app-updates/mac/${architecture}`,
|
|
});
|
|
});
|
|
|
|
it('keeps prerelease updates on the existing OSS channel feed', () => {
|
|
expect(resolveUpdateFeed('0.9.3-beta.1', 'darwin', 'arm64')).toEqual({
|
|
channel: 'beta',
|
|
url: 'https://oss.intelli-spectrum.com/beta',
|
|
});
|
|
});
|
|
|
|
it.each([
|
|
['linux', 'x64'],
|
|
['win32', 'arm64'],
|
|
['darwin', 'ia32'],
|
|
])('reports unsupported stable target %s/%s without throwing', (platform, architecture) => {
|
|
expect(resolveUpdateFeed('0.9.2', platform, architecture)).toMatchObject({
|
|
channel: 'latest',
|
|
error: expect.stringContaining('Unsupported update platform'),
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('AppUpdater feed delegation', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
electronMocks.getVersion.mockReturnValue('0.9.1');
|
|
updaterMocks.autoUpdater.channel = 'latest';
|
|
updaterMocks.autoUpdater.checkForUpdates.mockResolvedValue(null);
|
|
});
|
|
|
|
it('delegates stable checks directly to electron-updater without a manifest preflight', async () => {
|
|
const platformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform');
|
|
const architectureDescriptor = Object.getOwnPropertyDescriptor(process, 'arch');
|
|
Object.defineProperty(process, 'platform', { configurable: true, value: 'win32' });
|
|
Object.defineProperty(process, 'arch', { configurable: true, value: 'x64' });
|
|
const fetchSpy = vi.spyOn(globalThis, 'fetch');
|
|
updaterMocks.autoUpdater.checkForUpdates.mockResolvedValue({
|
|
isUpdateAvailable: true,
|
|
updateInfo: { version: '0.9.2' },
|
|
});
|
|
try {
|
|
const updater = new AppUpdater();
|
|
|
|
await expect(updater.checkForUpdates()).resolves.toMatchObject({ version: '0.9.2' });
|
|
|
|
expect(updaterMocks.autoUpdater.setFeedURL).toHaveBeenCalledWith({
|
|
provider: 'generic',
|
|
url: 'https://square.nianxx.cn/api/app-updates/windows/x64',
|
|
useMultipleRangeRequest: false,
|
|
});
|
|
expect(updaterMocks.autoUpdater.setFeedURL).toHaveBeenCalledTimes(1);
|
|
expect(updaterMocks.autoUpdater.checkForUpdates).toHaveBeenCalledTimes(1);
|
|
expect(fetchSpy).not.toHaveBeenCalled();
|
|
expect(updater.getStatus()).toMatchObject({
|
|
status: 'available',
|
|
info: { version: '0.9.2' },
|
|
});
|
|
} finally {
|
|
if (platformDescriptor) Object.defineProperty(process, 'platform', platformDescriptor);
|
|
if (architectureDescriptor) Object.defineProperty(process, 'arch', architectureDescriptor);
|
|
}
|
|
});
|
|
|
|
it('keeps prerelease channels on their existing electron-updater feed', async () => {
|
|
electronMocks.getVersion.mockReturnValue('0.9.2-beta.1');
|
|
updaterMocks.autoUpdater.checkForUpdates.mockResolvedValue({
|
|
isUpdateAvailable: false,
|
|
updateInfo: { version: '0.9.2-beta.1' },
|
|
});
|
|
const updater = new AppUpdater();
|
|
|
|
await updater.checkForUpdates();
|
|
|
|
expect(updaterMocks.autoUpdater.setFeedURL).toHaveBeenCalledWith({
|
|
provider: 'generic',
|
|
url: 'https://oss.intelli-spectrum.com/beta',
|
|
useMultipleRangeRequest: false,
|
|
});
|
|
expect(updaterMocks.autoUpdater.checkForUpdates).toHaveBeenCalledTimes(1);
|
|
expect(updater.getStatus()).toMatchObject({ status: 'not-available' });
|
|
});
|
|
|
|
it('defers unsupported stable target errors until an update check', async () => {
|
|
const platformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform');
|
|
const architectureDescriptor = Object.getOwnPropertyDescriptor(process, 'arch');
|
|
Object.defineProperty(process, 'platform', { configurable: true, value: 'linux' });
|
|
Object.defineProperty(process, 'arch', { configurable: true, value: 'x64' });
|
|
|
|
try {
|
|
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]);
|
|
|
|
expect(updater.getStatus()).toEqual({ status: 'idle' });
|
|
expect(updaterMocks.autoUpdater.setFeedURL).not.toHaveBeenCalled();
|
|
|
|
await expect(updater.checkForUpdates()).rejects.toThrow('Unsupported update platform: linux/x64');
|
|
|
|
expect(updater.getStatus()).toEqual({
|
|
status: 'error',
|
|
error: 'Unsupported update platform: linux/x64',
|
|
info: undefined,
|
|
progress: undefined,
|
|
});
|
|
expect(errorListener).toHaveBeenCalledWith(expect.objectContaining({
|
|
message: 'Unsupported update platform: linux/x64',
|
|
}));
|
|
expect(rendererSend.mock.calls.filter(([channel, status]) => (
|
|
channel === 'update:status-changed' && status?.status === 'error'
|
|
))).toHaveLength(1);
|
|
expect(updaterMocks.autoUpdater.checkForUpdates).not.toHaveBeenCalled();
|
|
} finally {
|
|
if (platformDescriptor) Object.defineProperty(process, 'platform', platformDescriptor);
|
|
if (architectureDescriptor) Object.defineProperty(process, 'arch', architectureDescriptor);
|
|
}
|
|
});
|
|
});
|