1
0
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:
Alice 2024-09-02 14:24:19 +03:00 committed by GitHub
parent 7e9c7d7d23
commit 6163364b26
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 1351 additions and 38 deletions

View File

@ -491,6 +491,7 @@ packages/app-desktop/integration-tests/util/test.js
packages/app-desktop/integration-tests/util/waitForNextOpenPath.js packages/app-desktop/integration-tests/util/waitForNextOpenPath.js
packages/app-desktop/playwright.config.js packages/app-desktop/playwright.config.js
packages/app-desktop/plugins/GotoAnything.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/autoUpdater/AutoUpdaterService.js
packages/app-desktop/services/bridge.js packages/app-desktop/services/bridge.js
packages/app-desktop/services/commands/stateToWhenClauseContext.js packages/app-desktop/services/commands/stateToWhenClauseContext.js

1
.gitignore vendored
View File

@ -468,6 +468,7 @@ packages/app-desktop/integration-tests/util/test.js
packages/app-desktop/integration-tests/util/waitForNextOpenPath.js packages/app-desktop/integration-tests/util/waitForNextOpenPath.js
packages/app-desktop/playwright.config.js packages/app-desktop/playwright.config.js
packages/app-desktop/plugins/GotoAnything.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/autoUpdater/AutoUpdaterService.js
packages/app-desktop/services/bridge.js packages/app-desktop/services/bridge.js
packages/app-desktop/services/commands/stateToWhenClauseContext.js packages/app-desktop/services/commands/stateToWhenClauseContext.js

View File

@ -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');
});
});

View File

@ -19,10 +19,16 @@ export enum AutoUpdaterEvents {
export const defaultUpdateInterval = 12 * 60 * 60 * 1000; export const defaultUpdateInterval = 12 * 60 * 60 * 1000;
export const initialUpdateStartup = 5 * 1000; export const initialUpdateStartup = 5 * 1000;
const releasesLink = 'https://objects.joplinusercontent.com/r/releases'; const releasesLink = 'https://objects.joplinusercontent.com/r/releases';
const supportedPlatformAssets: { [key in string]: string } = {
'darwin': 'latest-mac.yml',
'win32': 'latest.yml',
};
export interface AutoUpdaterServiceInterface { export interface AutoUpdaterServiceInterface {
checkForUpdates(): void; checkForUpdates(): void;
updateApp(): void; updateApp(): void;
fetchLatestRelease(includePreReleases: boolean): Promise<GitHubRelease>;
getDownloadUrlForPlatform(release: GitHubRelease, platform: string): string;
} }
export default class AutoUpdaterService implements AutoUpdaterServiceInterface { export default class AutoUpdaterService implements AutoUpdaterServiceInterface {
@ -45,7 +51,7 @@ export default class AutoUpdaterService implements AutoUpdaterServiceInterface {
public checkForUpdates = async (): Promise<void> => { public checkForUpdates = async (): Promise<void> => {
try { try {
await this.fetchLatestRelease(); await this.checkForLatestRelease();
} catch (error) { } catch (error) {
this.logger_.error('Failed to check for updates:', error); this.logger_.error('Failed to check for updates:', error);
if (error.message.includes('ERR_CONNECTION_REFUSED')) { if (error.message.includes('ERR_CONNECTION_REFUSED')) {
@ -58,7 +64,33 @@ export default class AutoUpdaterService implements AutoUpdaterServiceInterface {
autoUpdater.quitAndInstall(false, true); 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); const response = await fetch(releasesLink);
if (!response.ok) { 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)}`); 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 { try {
const releases = await this.fetchLatestReleases(); const release: GitHubRelease = await this.fetchLatestRelease(this.includePreReleases_);
const sortedReleasesByVersion = releases.sort((a, b) => { try {
return semver.rcompare(a.tag_name, b.tag_name); 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
const filteredReleases = sortedReleasesByVersion.filter(release => { assetUrl = assetUrl.substring(0, assetUrl.lastIndexOf('/'));
return this.includePreReleases_ || !release.prerelease; autoUpdater.setFeedURL({ provider: 'generic', url: assetUrl });
});
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,
});
await autoUpdater.checkForUpdates(); await autoUpdater.checkForUpdates();
} else {
this.logger_.error('No suitable update asset found for this platform.');
}
}
} catch (error) { } 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