mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-21 09:38:01 +02:00
Desktop: Seamless-Updates - added tests for autoUpdaterService (#10935)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
This commit is contained in:
parent
7e9c7d7d23
commit
6163364b26
@ -491,6 +491,7 @@ packages/app-desktop/integration-tests/util/test.js
|
||||
packages/app-desktop/integration-tests/util/waitForNextOpenPath.js
|
||||
packages/app-desktop/playwright.config.js
|
||||
packages/app-desktop/plugins/GotoAnything.js
|
||||
packages/app-desktop/services/autoUpdater/AutoUpdaterService.test.js
|
||||
packages/app-desktop/services/autoUpdater/AutoUpdaterService.js
|
||||
packages/app-desktop/services/bridge.js
|
||||
packages/app-desktop/services/commands/stateToWhenClauseContext.js
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -468,6 +468,7 @@ packages/app-desktop/integration-tests/util/test.js
|
||||
packages/app-desktop/integration-tests/util/waitForNextOpenPath.js
|
||||
packages/app-desktop/playwright.config.js
|
||||
packages/app-desktop/plugins/GotoAnything.js
|
||||
packages/app-desktop/services/autoUpdater/AutoUpdaterService.test.js
|
||||
packages/app-desktop/services/autoUpdater/AutoUpdaterService.js
|
||||
packages/app-desktop/services/bridge.js
|
||||
packages/app-desktop/services/commands/stateToWhenClauseContext.js
|
||||
|
@ -0,0 +1,68 @@
|
||||
import { LoggerWrapper } from '@joplin/utils/Logger';
|
||||
import { releases3 } from '../../utils/checkForUpdatesUtilsTestData';
|
||||
import AutoUpdaterService from './AutoUpdaterService';
|
||||
import { BrowserWindow } from 'electron';
|
||||
|
||||
jest.mock('electron', () => ({
|
||||
BrowserWindow: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('electron-updater', () => {
|
||||
const mockAutoUpdater = {
|
||||
setFeedURL: jest.fn(),
|
||||
checkForUpdates: jest.fn(),
|
||||
on: jest.fn(),
|
||||
quitAndInstall: jest.fn(),
|
||||
};
|
||||
return { autoUpdater: mockAutoUpdater };
|
||||
});
|
||||
|
||||
|
||||
describe('AutoUpdaterService', () => {
|
||||
let service: AutoUpdaterService;
|
||||
let mockLogger: LoggerWrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
const mockWindow = new BrowserWindow();
|
||||
mockLogger = { info: jest.fn(), error: jest.fn(), debug: jest.fn(), warn: jest.fn() };
|
||||
service = new AutoUpdaterService(mockWindow, mockLogger, false, true);
|
||||
global.fetch = jest.fn(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve(releases3),
|
||||
}),
|
||||
) as jest.Mock;
|
||||
});
|
||||
|
||||
it('should correctly fetch and process the latest prerelease', async () => {
|
||||
const release = await service.fetchLatestRelease(true);
|
||||
expect(release).toBeDefined();
|
||||
expect(release.tag_name).toBe('v3.1.3');
|
||||
});
|
||||
|
||||
it('should correctly fetch and process the latest release', async () => {
|
||||
const release = await service.fetchLatestRelease(false);
|
||||
expect(release).toBeDefined();
|
||||
expect(release.tag_name).toBe('v3.1.2');
|
||||
});
|
||||
|
||||
it('should return the correct download URL for Windows', async () => {
|
||||
const release = await service.fetchLatestRelease(true);
|
||||
expect(release).toBeDefined();
|
||||
const url = service.getDownloadUrlForPlatform(release, 'win32');
|
||||
expect(url).toBe('https://github.com/laurent22/joplin/releases/download/v3.1.3/latest.yml');
|
||||
});
|
||||
|
||||
it('should return the correct download URL for Mac', async () => {
|
||||
const release = await service.fetchLatestRelease(true);
|
||||
expect(release).toBeDefined();
|
||||
const url = service.getDownloadUrlForPlatform(release, 'darwin');
|
||||
expect(url).toBe('https://github.com/laurent22/joplin/releases/download/v3.1.3/latest-mac.yml');
|
||||
});
|
||||
|
||||
it('should throw an error for Linux', async () => {
|
||||
const release = await service.fetchLatestRelease(true);
|
||||
expect(release).toBeDefined();
|
||||
expect(() => service.getDownloadUrlForPlatform(release, 'linux')).toThrow('The AutoUpdaterService does not support the following platform: linux');
|
||||
});
|
||||
});
|
@ -19,10 +19,16 @@ export enum AutoUpdaterEvents {
|
||||
export const defaultUpdateInterval = 12 * 60 * 60 * 1000;
|
||||
export const initialUpdateStartup = 5 * 1000;
|
||||
const releasesLink = 'https://objects.joplinusercontent.com/r/releases';
|
||||
const supportedPlatformAssets: { [key in string]: string } = {
|
||||
'darwin': 'latest-mac.yml',
|
||||
'win32': 'latest.yml',
|
||||
};
|
||||
|
||||
export interface AutoUpdaterServiceInterface {
|
||||
checkForUpdates(): void;
|
||||
updateApp(): void;
|
||||
fetchLatestRelease(includePreReleases: boolean): Promise<GitHubRelease>;
|
||||
getDownloadUrlForPlatform(release: GitHubRelease, platform: string): string;
|
||||
}
|
||||
|
||||
export default class AutoUpdaterService implements AutoUpdaterServiceInterface {
|
||||
@ -45,7 +51,7 @@ export default class AutoUpdaterService implements AutoUpdaterServiceInterface {
|
||||
|
||||
public checkForUpdates = async (): Promise<void> => {
|
||||
try {
|
||||
await this.fetchLatestRelease();
|
||||
await this.checkForLatestRelease();
|
||||
} catch (error) {
|
||||
this.logger_.error('Failed to check for updates:', error);
|
||||
if (error.message.includes('ERR_CONNECTION_REFUSED')) {
|
||||
@ -58,7 +64,33 @@ export default class AutoUpdaterService implements AutoUpdaterServiceInterface {
|
||||
autoUpdater.quitAndInstall(false, true);
|
||||
};
|
||||
|
||||
private fetchLatestReleases = async (): Promise<GitHubRelease[]> => {
|
||||
public fetchLatestRelease = async (includePreReleases: boolean): Promise<GitHubRelease> => {
|
||||
const releases = await this.fetchReleases(includePreReleases);
|
||||
const release = releases[0];
|
||||
|
||||
if (!release) {
|
||||
throw new Error('No suitable release found');
|
||||
}
|
||||
|
||||
return release;
|
||||
};
|
||||
|
||||
|
||||
public getDownloadUrlForPlatform(release: GitHubRelease, platform: string): string {
|
||||
const assetName: string = supportedPlatformAssets[platform];
|
||||
if (!assetName) {
|
||||
throw new Error(`The AutoUpdaterService does not support the following platform: ${platform}`);
|
||||
}
|
||||
|
||||
const asset: GitHubReleaseAsset = release.assets.find(a => a.name === assetName);
|
||||
if (!asset) {
|
||||
throw new Error('No suitable update asset found for this platform.');
|
||||
}
|
||||
|
||||
return asset.browser_download_url;
|
||||
}
|
||||
|
||||
private fetchReleases = async (includePreReleases: boolean): Promise<GitHubRelease[]> => {
|
||||
const response = await fetch(releasesLink);
|
||||
|
||||
if (!response.ok) {
|
||||
@ -66,48 +98,29 @@ export default class AutoUpdaterService implements AutoUpdaterServiceInterface {
|
||||
throw new Error(`Cannot get latest release info: ${responseText.substr(0, 500)}`);
|
||||
}
|
||||
|
||||
return (await response.json()) as GitHubRelease[];
|
||||
const releases: GitHubRelease[] = await response.json();
|
||||
const sortedReleasesByVersion = releases.sort((a, b) => semver.rcompare(a.tag_name, b.tag_name));
|
||||
const filteredReleases = sortedReleasesByVersion.filter(release => includePreReleases || !release.prerelease);
|
||||
|
||||
return filteredReleases;
|
||||
};
|
||||
|
||||
private fetchLatestRelease = async (): Promise<void> => {
|
||||
private checkForLatestRelease = async (): Promise<void> => {
|
||||
try {
|
||||
const releases = await this.fetchLatestReleases();
|
||||
const release: GitHubRelease = await this.fetchLatestRelease(this.includePreReleases_);
|
||||
|
||||
const sortedReleasesByVersion = releases.sort((a, b) => {
|
||||
return semver.rcompare(a.tag_name, b.tag_name);
|
||||
});
|
||||
const filteredReleases = sortedReleasesByVersion.filter(release => {
|
||||
return this.includePreReleases_ || !release.prerelease;
|
||||
});
|
||||
const release = filteredReleases[0];
|
||||
|
||||
if (release) {
|
||||
let assetUrl = null;
|
||||
|
||||
if (shim.isWindows()) {
|
||||
const asset = release.assets.find((asset: GitHubReleaseAsset) => asset.name === 'latest.yml');
|
||||
if (asset) {
|
||||
assetUrl = asset.browser_download_url.replace('/latest.yml', '');
|
||||
}
|
||||
} else if (shim.isMac()) {
|
||||
const asset = release.assets.find((asset: GitHubReleaseAsset) => asset.name === 'latest-mac.yml');
|
||||
if (asset) {
|
||||
assetUrl = asset.browser_download_url.replace('/latest-mac.yml', '');
|
||||
}
|
||||
}
|
||||
|
||||
if (assetUrl) {
|
||||
autoUpdater.setFeedURL({
|
||||
provider: 'generic',
|
||||
url: assetUrl,
|
||||
});
|
||||
try {
|
||||
let assetUrl = this.getDownloadUrlForPlatform(release, shim.platformName());
|
||||
// electron's autoUpdater appends automatically the platform's yml file to the link so we should remove it
|
||||
assetUrl = assetUrl.substring(0, assetUrl.lastIndexOf('/'));
|
||||
autoUpdater.setFeedURL({ provider: 'generic', url: assetUrl });
|
||||
await autoUpdater.checkForUpdates();
|
||||
} else {
|
||||
this.logger_.error('No suitable update asset found for this platform.');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger_.error(error);
|
||||
this.logger_.error(`Update download url failed: ${error.message}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
this.logger_.error(`Fetching releases failed: ${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user