updates.test.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. import { describe, expect, it } from 'vitest';
  2. import { compareVersions, newestBuild, parseAdvertisedRefs, parseManifest, rawFileUrl, sameElectronMajor } from '../src/main/updates';
  3. const sha = (c: string): string => c.repeat(40);
  4. describe('self-update helpers', () => {
  5. it('compares versions numerically', () => {
  6. expect(compareVersions('0.10.0', '0.9.9')).toBeGreaterThan(0);
  7. expect(compareVersions('1.2.3', '1.2.3')).toBe(0);
  8. expect(compareVersions('1.2.3', '1.3.0')).toBeLessThan(0);
  9. expect(() => compareVersions('v1.2.3', '1.0.0')).toThrow();
  10. });
  11. it('parses the refs advertised by git smart HTTP', () => {
  12. const body =
  13. '001e# service=git-upload-pack\n0000' +
  14. `00fa${sha('a')} refs/heads/main\0multi_ack thin-pack agent=git/2.47.3\n` +
  15. `003f${sha('b')} refs/builds/v0.2.0\n` +
  16. `003f${sha('c')} refs/tags/v0.2.0\n0000`;
  17. const refs = parseAdvertisedRefs(body);
  18. expect(refs.get('refs/heads/main')).toBe(sha('a'));
  19. expect(refs.get('refs/builds/v0.2.0')).toBe(sha('b'));
  20. expect(refs.get('refs/tags/v0.2.0')).toBe(sha('c'));
  21. });
  22. it('picks the newest build above the running version', () => {
  23. const refs = new Map([
  24. ['refs/builds/v0.2.0', sha('a')],
  25. ['refs/builds/v0.10.0', sha('b')],
  26. ['refs/builds/vbroken', sha('c')],
  27. ['refs/tags/v9.0.0', sha('d')],
  28. ]);
  29. expect(newestBuild(refs, '0.1.0')).toEqual({ version: '0.10.0', sha: sha('b') });
  30. expect(newestBuild(refs, '0.10.0')).toBeNull();
  31. });
  32. it('rejects unsafe or incomplete manifests', () => {
  33. const file = { path: 'app.asar', size: 3, sha256: 'f'.repeat(64) };
  34. const ok = { version: '0.2.0', electron: '38.8.6', files: [file] };
  35. expect(parseManifest(ok, '0.2.0').files).toHaveLength(1);
  36. expect(() => parseManifest(ok, '0.3.0')).toThrow(/expected 0.3.0/);
  37. expect(() => parseManifest({ ...ok, files: [file, { ...file, path: '../evil.exe' }] }, '0.2.0')).toThrow(/unsafe/);
  38. expect(() => parseManifest({ ...ok, files: [file, { ...file, path: 'C:/evil.exe' }] }, '0.2.0')).toThrow(/unsafe/);
  39. expect(() => parseManifest({ ...ok, files: [{ ...file, path: 'assets/a.png' }] }, '0.2.0')).toThrow(/app.asar/);
  40. });
  41. it('builds raw URLs and compares Electron runtimes', () => {
  42. expect(rawFileUrl('https://git.example/u/r', 'abc', 'app.asar.unpacked/node_modules/@scope/x.node')).toBe(
  43. 'https://git.example/u/r/raw/abc/app.asar.unpacked/node_modules/%40scope/x.node',
  44. );
  45. expect(sameElectronMajor('38.8.6', '38.1.0')).toBe(true);
  46. expect(sameElectronMajor('39.0.0', '38.8.6')).toBe(false);
  47. });
  48. });