feat!: bump engines to Node.js >=22.12.0 (#139)
Some checks failed
Publish documentation / docs (push) Failing after 1m9s
Some checks failed
Publish documentation / docs (push) Failing after 1m9s
BREAKING CHANGE: Requires Node.js v22.12.0 LTS or higher. ESM-only.
This commit is contained in:
@@ -1,24 +1,27 @@
|
||||
import * as fs from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import { makeUniversalApp } from '../dist/cjs/index';
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
|
||||
import { makeUniversalApp } from '../dist/index.js';
|
||||
import { fsMove } from '../src/file-utils.js';
|
||||
import {
|
||||
createStagingAppDir,
|
||||
generateNativeApp,
|
||||
templateApp,
|
||||
VERIFY_APP_TIMEOUT,
|
||||
verifyApp,
|
||||
} from './util';
|
||||
} from './util.js';
|
||||
import { createPackage, createPackageWithOptions } from '@electron/asar';
|
||||
import { afterEach, describe, expect, it } from '@jest/globals';
|
||||
|
||||
const appsPath = path.resolve(__dirname, 'fixtures', 'apps');
|
||||
const appsOutPath = path.resolve(__dirname, 'fixtures', 'apps', 'out');
|
||||
const appsPath = path.resolve(import.meta.dirname, 'fixtures', 'apps');
|
||||
const appsOutPath = path.resolve(import.meta.dirname, 'fixtures', 'apps', 'out');
|
||||
|
||||
// See `jest.setup.ts` for app fixture setup process
|
||||
// See `globalSetup.ts` for app fixture setup process
|
||||
describe('makeUniversalApp', () => {
|
||||
afterEach(async () => {
|
||||
await fs.emptyDir(appsOutPath);
|
||||
await fs.promises.rm(appsOutPath, { force: true, recursive: true });
|
||||
await fs.promises.mkdir(appsOutPath, { recursive: true });
|
||||
});
|
||||
|
||||
it('throws an error if asar is only detected in one arch', async () => {
|
||||
@@ -34,31 +37,27 @@ describe('makeUniversalApp', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it(
|
||||
'works for lipo binary resources',
|
||||
async () => {
|
||||
const x64AppPath = await generateNativeApp({
|
||||
appNameWithExtension: 'LipoX64.app',
|
||||
arch: 'x64',
|
||||
createAsar: true,
|
||||
});
|
||||
const arm64AppPath = await generateNativeApp({
|
||||
appNameWithExtension: 'LipoArm64.app',
|
||||
arch: 'arm64',
|
||||
createAsar: true,
|
||||
});
|
||||
it('works for lipo binary resources', { timeout: VERIFY_APP_TIMEOUT }, async () => {
|
||||
const x64AppPath = await generateNativeApp({
|
||||
appNameWithExtension: 'LipoX64.app',
|
||||
arch: 'x64',
|
||||
createAsar: true,
|
||||
});
|
||||
const arm64AppPath = await generateNativeApp({
|
||||
appNameWithExtension: 'LipoArm64.app',
|
||||
arch: 'arm64',
|
||||
createAsar: true,
|
||||
});
|
||||
|
||||
const out = path.resolve(appsOutPath, 'Lipo.app');
|
||||
await makeUniversalApp({ x64AppPath, arm64AppPath, outAppPath: out, mergeASARs: true });
|
||||
await verifyApp(out, true);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
const out = path.resolve(appsOutPath, 'Lipo.app');
|
||||
await makeUniversalApp({ x64AppPath, arm64AppPath, outAppPath: out, mergeASARs: true });
|
||||
await verifyApp(out, true);
|
||||
});
|
||||
|
||||
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 fs.promises.mkdir(out, { recursive: true });
|
||||
await expect(
|
||||
makeUniversalApp({
|
||||
x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
|
||||
@@ -70,9 +69,10 @@ describe('makeUniversalApp', () => {
|
||||
|
||||
it(
|
||||
'packages successfully if `out` bundle already exists and `force` is `true`',
|
||||
{ timeout: VERIFY_APP_TIMEOUT },
|
||||
async () => {
|
||||
const out = path.resolve(appsOutPath, 'NoError.app');
|
||||
await fs.mkdirp(out);
|
||||
await fs.promises.mkdir(out, { recursive: true });
|
||||
await makeUniversalApp({
|
||||
x64AppPath: path.resolve(appsPath, 'X64Asar.app'),
|
||||
arm64AppPath: path.resolve(appsPath, 'Arm64Asar.app'),
|
||||
@@ -81,27 +81,23 @@ describe('makeUniversalApp', () => {
|
||||
});
|
||||
await verifyApp(out);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
});
|
||||
|
||||
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 verifyApp(out);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
it('should correctly merge two identical asars', { timeout: VERIFY_APP_TIMEOUT }, 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 verifyApp(out);
|
||||
});
|
||||
|
||||
it(
|
||||
'should create a shim if asars are different between architectures',
|
||||
{ timeout: VERIFY_APP_TIMEOUT },
|
||||
async () => {
|
||||
const out = path.resolve(appsOutPath, 'ShimmedAsar.app');
|
||||
await makeUniversalApp({
|
||||
@@ -111,11 +107,11 @@ describe('makeUniversalApp', () => {
|
||||
});
|
||||
await verifyApp(out);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
|
||||
it(
|
||||
'should merge two different asars when `mergeASARs` is enabled',
|
||||
{ timeout: VERIFY_APP_TIMEOUT },
|
||||
async () => {
|
||||
const out = path.resolve(appsOutPath, 'MergedAsar.app');
|
||||
await makeUniversalApp({
|
||||
@@ -127,11 +123,11 @@ describe('makeUniversalApp', () => {
|
||||
});
|
||||
await verifyApp(out);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
|
||||
it(
|
||||
'throws an error if `mergeASARs` is enabled and `singleArchFiles` is missing a unique file',
|
||||
{ timeout: VERIFY_APP_TIMEOUT },
|
||||
async () => {
|
||||
const out = path.resolve(appsOutPath, 'Error.app');
|
||||
await expect(
|
||||
@@ -144,17 +140,17 @@ describe('makeUniversalApp', () => {
|
||||
}),
|
||||
).rejects.toThrow(/Detected unique file "extra-file\.txt"/);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
|
||||
it(
|
||||
'should not inject ElectronAsarIntegrity into `infoPlistsToIgnore`',
|
||||
{ timeout: VERIFY_APP_TIMEOUT },
|
||||
async () => {
|
||||
const arm64AppPath = await templateApp('Arm64-1.app', 'arm64', async (appPath) => {
|
||||
const { testPath } = await createStagingAppDir('Arm64-1');
|
||||
await createPackage(testPath, path.resolve(appPath, 'Contents', 'Resources', 'app.asar'));
|
||||
await templateApp('SubApp-1.app', 'arm64', async (subArm64AppPath) => {
|
||||
await fs.move(
|
||||
await fsMove(
|
||||
subArm64AppPath,
|
||||
path.resolve(appPath, 'Contents', 'Resources', path.basename(subArm64AppPath)),
|
||||
);
|
||||
@@ -164,7 +160,7 @@ describe('makeUniversalApp', () => {
|
||||
const { testPath } = await createStagingAppDir('X64-1');
|
||||
await createPackage(testPath, path.resolve(appPath, 'Contents', 'Resources', 'app.asar'));
|
||||
await templateApp('SubApp-1.app', 'x64', async (subArm64AppPath) => {
|
||||
await fs.move(
|
||||
await fsMove(
|
||||
subArm64AppPath,
|
||||
path.resolve(appPath, 'Contents', 'Resources', path.basename(subArm64AppPath)),
|
||||
);
|
||||
@@ -180,7 +176,6 @@ describe('makeUniversalApp', () => {
|
||||
});
|
||||
await verifyApp(outAppPath);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
|
||||
// TODO: Investigate if this should even be allowed.
|
||||
@@ -188,6 +183,7 @@ describe('makeUniversalApp', () => {
|
||||
// https://github.com/electron/universal/blob/d90d573ccf69a5b14b91aa818c8b97e0e6840399/src/file-utils.ts#L48-L49
|
||||
it.skip(
|
||||
'should shim asars with different unpacked dirs',
|
||||
{ timeout: VERIFY_APP_TIMEOUT },
|
||||
async () => {
|
||||
const arm64AppPath = await templateApp('UnpackedArm64.app', 'arm64', async (appPath) => {
|
||||
const { testPath } = await createStagingAppDir('UnpackedAppArm64');
|
||||
@@ -218,32 +214,32 @@ describe('makeUniversalApp', () => {
|
||||
});
|
||||
await verifyApp(outAppPath);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
|
||||
it(
|
||||
'should generate AsarIntegrity for all asars in the application',
|
||||
{ timeout: VERIFY_APP_TIMEOUT },
|
||||
async () => {
|
||||
const { testPath } = await createStagingAppDir('app-2');
|
||||
const testAsarPath = path.resolve(appsOutPath, 'app-2.asar');
|
||||
await createPackage(testPath, testAsarPath);
|
||||
|
||||
const arm64AppPath = await templateApp('Arm64-2.app', 'arm64', async (appPath) => {
|
||||
await fs.copyFile(
|
||||
await fs.promises.copyFile(
|
||||
testAsarPath,
|
||||
path.resolve(appPath, 'Contents', 'Resources', 'app.asar'),
|
||||
);
|
||||
await fs.copyFile(
|
||||
await fs.promises.copyFile(
|
||||
testAsarPath,
|
||||
path.resolve(appPath, 'Contents', 'Resources', 'webapp.asar'),
|
||||
);
|
||||
});
|
||||
const x64AppPath = await templateApp('X64-2.app', 'x64', async (appPath) => {
|
||||
await fs.copyFile(
|
||||
await fs.promises.copyFile(
|
||||
testAsarPath,
|
||||
path.resolve(appPath, 'Contents', 'Resources', 'app.asar'),
|
||||
);
|
||||
await fs.copyFile(
|
||||
await fs.promises.copyFile(
|
||||
testAsarPath,
|
||||
path.resolve(appPath, 'Contents', 'Resources', 'webbapp.asar'),
|
||||
);
|
||||
@@ -257,13 +253,13 @@ describe('makeUniversalApp', () => {
|
||||
});
|
||||
await verifyApp(outAppPath);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
});
|
||||
|
||||
describe('no asar mode', () => {
|
||||
it(
|
||||
'should correctly merge two identical app folders',
|
||||
{ timeout: VERIFY_APP_TIMEOUT },
|
||||
async () => {
|
||||
const out = path.resolve(appsOutPath, 'MergedNoAsar.app');
|
||||
await makeUniversalApp({
|
||||
@@ -273,39 +269,41 @@ describe('makeUniversalApp', () => {
|
||||
});
|
||||
await verifyApp(out);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
|
||||
it(
|
||||
'should shim two different app folders',
|
||||
async () => {
|
||||
const arm64AppPath = await templateApp('ShimArm64.app', 'arm64', async (appPath) => {
|
||||
const { testPath } = await createStagingAppDir('shimArm64', {
|
||||
'i-aint-got-no-rhythm.bin': 'boomshakalaka',
|
||||
});
|
||||
await fs.copy(testPath, path.resolve(appPath, 'Contents', 'Resources', 'app'));
|
||||
it('should shim two different app folders', { timeout: VERIFY_APP_TIMEOUT }, async () => {
|
||||
const arm64AppPath = await templateApp('ShimArm64.app', 'arm64', async (appPath) => {
|
||||
const { testPath } = await createStagingAppDir('shimArm64', {
|
||||
'i-aint-got-no-rhythm.bin': 'boomshakalaka',
|
||||
});
|
||||
await fs.promises.cp(testPath, path.resolve(appPath, 'Contents', 'Resources', 'app'), {
|
||||
recursive: true,
|
||||
verbatimSymlinks: true,
|
||||
});
|
||||
});
|
||||
|
||||
const x64AppPath = await templateApp('ShimX64.app', 'x64', async (appPath) => {
|
||||
const { testPath } = await createStagingAppDir('shimX64', {
|
||||
'hello-world.bin': 'Hello World',
|
||||
});
|
||||
await fs.copy(testPath, path.resolve(appPath, 'Contents', 'Resources', 'app'));
|
||||
const x64AppPath = await templateApp('ShimX64.app', 'x64', async (appPath) => {
|
||||
const { testPath } = await createStagingAppDir('shimX64', {
|
||||
'hello-world.bin': 'Hello World',
|
||||
});
|
||||
await fs.promises.cp(testPath, path.resolve(appPath, 'Contents', 'Resources', 'app'), {
|
||||
recursive: true,
|
||||
verbatimSymlinks: true,
|
||||
});
|
||||
});
|
||||
|
||||
const outAppPath = path.resolve(appsOutPath, 'ShimNoAsar.app');
|
||||
await makeUniversalApp({
|
||||
x64AppPath,
|
||||
arm64AppPath,
|
||||
outAppPath,
|
||||
});
|
||||
await verifyApp(outAppPath);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
const outAppPath = path.resolve(appsOutPath, 'ShimNoAsar.app');
|
||||
await makeUniversalApp({
|
||||
x64AppPath,
|
||||
arm64AppPath,
|
||||
outAppPath,
|
||||
});
|
||||
await verifyApp(outAppPath);
|
||||
});
|
||||
|
||||
it(
|
||||
'different app dirs with different macho files (shim and lipo)',
|
||||
{ timeout: VERIFY_APP_TIMEOUT },
|
||||
async () => {
|
||||
const x64AppPath = await generateNativeApp({
|
||||
appNameWithExtension: 'DifferentMachoAppX64-1.app',
|
||||
@@ -332,11 +330,11 @@ describe('makeUniversalApp', () => {
|
||||
});
|
||||
await verifyApp(outAppPath, true);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
|
||||
it(
|
||||
"different app dirs with universal macho files (shim but don't lipo)",
|
||||
{ timeout: VERIFY_APP_TIMEOUT },
|
||||
async () => {
|
||||
const x64AppPath = await generateNativeApp({
|
||||
appNameWithExtension: 'DifferentButUniversalMachoAppX64-2.app',
|
||||
@@ -365,11 +363,11 @@ describe('makeUniversalApp', () => {
|
||||
});
|
||||
await verifyApp(outAppPath, true);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
|
||||
it(
|
||||
'identical app dirs with different macho files (e.g. do not shim, but still lipo)',
|
||||
{ timeout: VERIFY_APP_TIMEOUT },
|
||||
async () => {
|
||||
const x64AppPath = await generateNativeApp({
|
||||
appNameWithExtension: 'DifferentMachoAppX64-2.app',
|
||||
@@ -390,11 +388,11 @@ describe('makeUniversalApp', () => {
|
||||
});
|
||||
await verifyApp(out, true);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
|
||||
it(
|
||||
'identical app dirs with universal macho files (e.g., do not shim, just copy x64 dir)',
|
||||
{ timeout: VERIFY_APP_TIMEOUT },
|
||||
async () => {
|
||||
const x64AppPath = await generateNativeApp({
|
||||
appNameWithExtension: 'UniversalMachoAppX64.app',
|
||||
@@ -413,7 +411,6 @@ describe('makeUniversalApp', () => {
|
||||
await makeUniversalApp({ x64AppPath, arm64AppPath, outAppPath: out });
|
||||
await verifyApp(out, true);
|
||||
},
|
||||
VERIFY_APP_TIMEOUT,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user