mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
175 lines
5.4 KiB
TypeScript
175 lines
5.4 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
import type { OpenDesignHostUpdaterStatusSnapshot } from '@open-design/host';
|
|
import { installMockOpenDesignHost } from '@open-design/host/testing';
|
|
|
|
import {
|
|
deriveUpdaterModel,
|
|
openUpdaterInstaller,
|
|
quitAfterUpdaterInstallerOpen,
|
|
readUpdaterStatus,
|
|
} from '../../src/lib/updater';
|
|
|
|
function downloadedStatus(overrides: Partial<OpenDesignHostUpdaterStatusSnapshot> = {}): OpenDesignHostUpdaterStatusSnapshot {
|
|
return {
|
|
arch: 'arm64',
|
|
artifact: {
|
|
name: 'Open Design Beta.dmg',
|
|
platformKey: 'macAppleSilicon',
|
|
type: 'dmg',
|
|
url: 'https://fixture.test/Open Design Beta.dmg',
|
|
},
|
|
availableVersion: '1.2.3-beta.4',
|
|
capabilities: {
|
|
canApplyInPlace: false,
|
|
canDownload: true,
|
|
canOpenInstaller: true,
|
|
requiresManualInstall: true,
|
|
},
|
|
channel: 'beta',
|
|
currentVersion: '1.2.3-beta.3',
|
|
downloadPath: '/tmp/open-design-updater/Open Design Beta.dmg',
|
|
enabled: true,
|
|
mode: 'package-launcher',
|
|
platform: 'darwin',
|
|
state: 'downloaded',
|
|
supported: true,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe('web updater model', () => {
|
|
let restoreHost: (() => void) | null = null;
|
|
|
|
afterEach(() => {
|
|
restoreHost?.();
|
|
restoreHost = null;
|
|
});
|
|
|
|
it('treats missing host capabilities as the web environment', () => {
|
|
const model = deriveUpdaterModel(null, { hostAvailable: false });
|
|
expect(model.environment).toBe('web');
|
|
expect(model.shouldPrompt).toBe(false);
|
|
expect(model.shouldShowControl).toBe(false);
|
|
expect(model.canOpenInstaller).toBe(false);
|
|
});
|
|
|
|
it('derives a desktop prompt only after a compatible installer is downloaded', () => {
|
|
const model = deriveUpdaterModel(downloadedStatus(), { hostAvailable: true });
|
|
expect(model.environment).toBe('desktop');
|
|
expect(model.shouldPrompt).toBe(true);
|
|
expect(model.hasDownloadedInstaller).toBe(true);
|
|
expect(model.canOpenInstaller).toBe(true);
|
|
expect(model.shouldShowControl).toBe(true);
|
|
expect(model.promptKey).toContain('1.2.3-beta.4');
|
|
});
|
|
|
|
it('derives left-rail download progress from updater snapshots', () => {
|
|
const model = deriveUpdaterModel(
|
|
downloadedStatus({
|
|
progress: {
|
|
receivedBytes: 25,
|
|
totalBytes: 100,
|
|
},
|
|
state: 'downloading',
|
|
}),
|
|
{ hostAvailable: true },
|
|
);
|
|
expect(model.busy).toBe(true);
|
|
expect(model.shouldShowControl).toBe(true);
|
|
expect(model.downloadProgress).toEqual({
|
|
percent: 25,
|
|
receivedBytes: 25,
|
|
totalBytes: 100,
|
|
});
|
|
});
|
|
|
|
it('keeps the downloaded installer visible while a newer incoming download reports progress', () => {
|
|
const model = deriveUpdaterModel(
|
|
downloadedStatus({
|
|
incoming: {
|
|
arch: 'arm64',
|
|
artifact: {
|
|
name: 'Open Design Beta 1.2.3-beta.5.dmg',
|
|
platformKey: 'macAppleSilicon',
|
|
type: 'dmg',
|
|
url: 'https://fixture.test/Open Design Beta 1.2.3-beta.5.dmg',
|
|
},
|
|
channel: 'beta',
|
|
key: '1.2.3-beta.5-mac-arm64',
|
|
progress: {
|
|
receivedBytes: 64,
|
|
totalBytes: 256,
|
|
},
|
|
startedAt: '2026-05-19T00:00:00.000Z',
|
|
version: '1.2.3-beta.5',
|
|
},
|
|
state: 'downloaded',
|
|
}),
|
|
{ hostAvailable: true },
|
|
);
|
|
|
|
expect(model.busy).toBe(false);
|
|
expect(model.hasDownloadedInstaller).toBe(true);
|
|
expect(model.shouldPrompt).toBe(true);
|
|
expect(model.downloadProgress).toEqual({
|
|
percent: 25,
|
|
receivedBytes: 64,
|
|
totalBytes: 256,
|
|
});
|
|
});
|
|
|
|
it('does not keep prompting after the installer has been opened', () => {
|
|
const model = deriveUpdaterModel(
|
|
downloadedStatus({
|
|
installResult: {
|
|
dryRun: true,
|
|
openedAt: '2026-05-19T00:00:00.000Z',
|
|
path: '/tmp/open-design-updater/Open Design Beta.dmg',
|
|
},
|
|
}),
|
|
{ hostAvailable: true },
|
|
);
|
|
expect(model.installerOpened).toBe(true);
|
|
expect(model.canQuitAfterInstallerOpen).toBe(true);
|
|
expect(model.shouldPrompt).toBe(false);
|
|
});
|
|
|
|
it('routes status, install, and quit requests through host helpers with flexible payloads', async () => {
|
|
const status = downloadedStatus();
|
|
const statusFn = vi.fn(async () => status);
|
|
const install = vi.fn(async () => downloadedStatus({
|
|
installResult: {
|
|
dryRun: true,
|
|
openedAt: '2026-05-19T00:00:00.000Z',
|
|
path: status.downloadPath ?? '/tmp/open-design-updater/Open Design Beta.dmg',
|
|
},
|
|
}));
|
|
const quit = vi.fn(async () => ({ ok: true as const }));
|
|
restoreHost = installMockOpenDesignHost({
|
|
host: {
|
|
updater: {
|
|
install,
|
|
quit,
|
|
status: statusFn,
|
|
},
|
|
},
|
|
});
|
|
|
|
await expect(readUpdaterStatus({ payload: { source: 'test-status' } })).resolves.toMatchObject({
|
|
ok: true,
|
|
model: { shouldPrompt: true },
|
|
});
|
|
await expect(openUpdaterInstaller({ payload: { source: 'test-popup' } })).resolves.toMatchObject({
|
|
ok: true,
|
|
model: { installerOpened: true, shouldPrompt: false },
|
|
});
|
|
await expect(quitAfterUpdaterInstallerOpen({ payload: { source: 'test-quit' } })).resolves.toEqual({
|
|
ok: true,
|
|
});
|
|
|
|
expect(statusFn).toHaveBeenCalledWith({ payload: { source: 'test-status' } });
|
|
expect(install).toHaveBeenCalledWith({ payload: { source: 'test-popup' } });
|
|
expect(quit).toHaveBeenCalledWith({ payload: { source: 'test-quit' } });
|
|
});
|
|
});
|