Skip to content

Commit

Permalink
test: improve coverage (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
erickzhao authored Jun 17, 2024
1 parent dfe5236 commit 03e27e5
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 24 deletions.
20 changes: 18 additions & 2 deletions jest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,43 @@ const templateApp = async (
export default async () => {
await fs.remove(appsDir);
await fs.mkdirp(appsDir);
await templateApp('Asar.app', 'arm64', async (appPath) => {
await templateApp('Arm64Asar.app', 'arm64', async (appPath) => {
await fs.copy(
path.resolve(asarsDir, 'app.asar'),
path.resolve(appPath, 'Contents', 'Resources', 'app.asar'),
);
});

// contains `extra-file.txt`
await templateApp('Arm64AsarExtraFile.app', 'arm64', async (appPath) => {
await fs.copy(
path.resolve(asarsDir, 'app2.asar'),
path.resolve(appPath, 'Contents', 'Resources', 'app.asar'),
);
});

await templateApp('X64Asar.app', 'x64', async (appPath) => {
await fs.copy(
path.resolve(asarsDir, 'app.asar'),
path.resolve(appPath, 'Contents', 'Resources', 'app.asar'),
);
});

await templateApp('NoAsar.app', 'arm64', async (appPath) => {
await templateApp('Arm64NoAsar.app', 'arm64', async (appPath) => {
await fs.copy(
path.resolve(asarsDir, 'app'),
path.resolve(appPath, 'Contents', 'Resources', 'app'),
);
});

// contains `extra-file.txt`
await templateApp('Arm64NoAsarExtraFile.app', 'arm64', async (appPath) => {
await fs.copy(
path.resolve(asarsDir, 'app2'),
path.resolve(appPath, 'Contents', 'Resources', 'app'),
);
});

await templateApp('X64NoAsar.app', 'x64', async (appPath) => {
await fs.copy(
path.resolve(asarsDir, 'app'),
Expand Down
6 changes: 4 additions & 2 deletions test/asar-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ const appsPath = path.resolve(__dirname, 'fixtures', 'apps');
describe('asar-utils', () => {
describe('detectAsarMode', () => {
it('should correctly detect an asar enabled app', async () => {
expect(await detectAsarMode(path.resolve(appsPath, 'Asar.app'))).toBe(AsarMode.HAS_ASAR);
expect(await detectAsarMode(path.resolve(appsPath, 'Arm64Asar.app'))).toBe(AsarMode.HAS_ASAR);
});

it('should correctly detect an app without an asar', async () => {
expect(await detectAsarMode(path.resolve(appsPath, 'NoAsar.app'))).toBe(AsarMode.NO_ASAR);
expect(await detectAsarMode(path.resolve(appsPath, 'Arm64NoAsar.app'))).toBe(
AsarMode.NO_ASAR,
);
});
});

Expand Down
4 changes: 2 additions & 2 deletions test/file-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ describe('file-utils', () => {
let noAsarFiles: AppFile[];

beforeAll(async () => {
asarFiles = await getAllAppFiles(path.resolve(appsPath, 'Asar.app'));
noAsarFiles = await getAllAppFiles(path.resolve(appsPath, 'NoAsar.app'));
asarFiles = await getAllAppFiles(path.resolve(appsPath, 'Arm64Asar.app'));
noAsarFiles = await getAllAppFiles(path.resolve(appsPath, 'Arm64NoAsar.app'));
});

it('should correctly identify plist files', async () => {
Expand Down
Binary file added test/fixtures/asars/app2.asar
Binary file not shown.
1 change: 1 addition & 0 deletions test/fixtures/asars/app2/extra-file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
erick was here!
2 changes: 2 additions & 0 deletions test/fixtures/asars/app2/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
console.log('I am an app.asar', process.arch);
process.exit(0);
4 changes: 4 additions & 0 deletions test/fixtures/asars/app2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "app",
"main": "index.js"
}
157 changes: 139 additions & 18 deletions test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { spawn } from '@malept/cross-spawn-promise';
import * as fs from 'fs-extra';
import * as path from 'path';

import { makeUniversalApp } from '../src/index';
import { makeUniversalApp } from '../dist/cjs/index';

const appsPath = path.resolve(__dirname, 'fixtures', 'apps');
const appsOutPath = path.resolve(__dirname, 'fixtures', 'apps', 'out');

async function ensureUniversal(app: string) {
const exe = path.resolve(app, 'Contents', 'MacOS', 'Electron');
Expand All @@ -14,27 +15,147 @@ async function ensureUniversal(app: string) {
expect(result2).toContain('x64');
}

// See `jest.setup.ts` for app fixture setup process
describe('makeUniversalApp', () => {
it('should correctly merge two identical asars', async () => {
const out = path.resolve(appsPath, 'MergedAsar.app');
await makeUniversalApp({
x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
arm64AppPath: path.resolve(appsPath, 'Asar.app'),
outAppPath: out,
afterEach(async () => {
await fs.emptyDir(appsOutPath);
});

it('throws an error if asar is only detected in one arch', async () => {
const out = path.resolve(appsOutPath, 'Error.app');
await expect(
makeUniversalApp({
x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
arm64AppPath: path.resolve(appsPath, 'Arm64NoAsar.app'),
outAppPath: out,
}),
).rejects.toThrow(
'Both the x64 and arm64 versions of your application need to have been built with the same asar settings (enabled vs disabled)',
);
});

it.todo('works for lipo binary resources');

describe('force', () => {
it('throws an error if `out` bundle already exists and `force` is `false`', async () => {
const out = path.resolve(appsOutPath, 'Error.app');
await fs.mkdirp(out);
await expect(
makeUniversalApp({
x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
arm64AppPath: path.resolve(appsPath, 'Arm64Asar.app'),
outAppPath: out,
}),
).rejects.toThrow(/The out path ".*" already exists and force is not set to true/);
});
await ensureUniversal(out);
// Only a single asar as they were identical
expect(
(await fs.readdir(path.resolve(out, 'Contents', 'Resources'))).filter((p) =>
p.endsWith('asar'),
),
).toEqual(['app.asar']);
}, 60000);

it('packages successfully if `out` bundle already exists and `force` is `true`', async () => {
const out = path.resolve(appsOutPath, 'Error.app');
await fs.mkdirp(out);
await makeUniversalApp({
x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
arm64AppPath: path.resolve(appsPath, 'Arm64Asar.app'),
outAppPath: out,
force: true,
});
await ensureUniversal(out);
// Only a single asar as they were identical
expect(
(await fs.readdir(path.resolve(out, 'Contents', 'Resources'))).filter((p) =>
p.endsWith('asar'),
),
).toEqual(['app.asar']);
}, 60000);
});

describe('asar mode', () => {
it('should correctly merge two identical asars', async () => {
const out = path.resolve(appsOutPath, 'MergedAsar.app');
await makeUniversalApp({
x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
arm64AppPath: path.resolve(appsPath, 'Arm64Asar.app'),
outAppPath: out,
});
await ensureUniversal(out);
// Only a single asar as they were identical
expect(
(await fs.readdir(path.resolve(out, 'Contents', 'Resources'))).filter((p) =>
p.endsWith('asar'),
),
).toEqual(['app.asar']);
}, 60000);

it('should create a shim if asars are different between architectures', async () => {
const out = path.resolve(appsOutPath, 'ShimmedAsar.app');
await makeUniversalApp({
x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
arm64AppPath: path.resolve(appsPath, 'Arm64AsarExtraFile.app'),
outAppPath: out,
});
await ensureUniversal(out);
// We have three asars including the arch-agnostic shim
expect(
(await fs.readdir(path.resolve(out, 'Contents', 'Resources')))
.filter((p) => p.endsWith('asar'))
.sort(),
).toEqual(['app.asar', 'app-x64.asar', 'app-arm64.asar'].sort());
}, 60000);

it('should merge two different asars when `mergeASARs` is enabled', async () => {
const out = path.resolve(appsOutPath, 'MergedAsar.app');
await makeUniversalApp({
x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
arm64AppPath: path.resolve(appsPath, 'Arm64AsarExtraFile.app'),
outAppPath: out,
mergeASARs: true,
singleArchFiles: 'extra-file.txt',
});
await ensureUniversal(out);
// Only a single merged asar
expect(
(await fs.readdir(path.resolve(out, 'Contents', 'Resources'))).filter((p) =>
p.endsWith('asar'),
),
).toEqual(['app.asar']);
}, 60000);

it('throws an error if `mergeASARs` is enabled and `singleArchFiles` is missing a unique file', async () => {
const out = path.resolve(appsOutPath, 'Error.app');
await expect(
makeUniversalApp({
x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
arm64AppPath: path.resolve(appsPath, 'Arm64AsarExtraFile.app'),
outAppPath: out,
mergeASARs: true,
singleArchFiles: 'bad-rule',
}),
).rejects.toThrow(/Detected unique file "extra-file\.txt"/);
}, 60000);

it.todo('should not inject ElectronAsarIntegrity into `infoPlistsToIgnore`');
});

describe('no asar mode', () => {
it('should correctly merge two identical app folders', async () => {
const out = path.resolve(appsOutPath, 'MergedNoAsar.app');
await makeUniversalApp({
x64AppPath: path.resolve(appsPath, 'X64NoAsar.app'),
arm64AppPath: path.resolve(appsPath, 'Arm64NoAsar.app'),
outAppPath: out,
});
await ensureUniversal(out);
// Only a single app folder as they were identical
expect(
(await fs.readdir(path.resolve(out, 'Contents', 'Resources'))).filter((p) =>
p.startsWith('app'),
),
).toEqual(['app']);
}, 60000);

it.todo('should shim two different app folders');
});

// TODO: Add tests for
// * different asar files
// * identical app dirs
// * different app dirs
// * different app dirs with different macho files
// * identical app dirs with universal macho files
});

0 comments on commit 03e27e5

Please sign in to comment.