storebound/tests/cli-shim.test.ts

47 lines
3.4 KiB
TypeScript

import { describe, expect, test } from 'bun:test';
import { mkdtempSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { ensureCliShim, onPath, SHIM_MARKER, shimPlan } from '../cli/lib/cli-shim';
describe('desktop terminal launcher', () => {
test('per platform: file, content, PATH folder, profile', () => {
const w = shimPlan({ exe: 'C:\\Users\\you\\AppData\\Local\\storebound\\storebound.exe', platform: 'win32', home: 'C:\\Users\\you', env: { LOCALAPPDATA: 'C:\\Users\\you\\AppData\\Local' } });
expect(w.file.endsWith('storebound.cmd')).toBe(true);
expect(w.content).toContain('"C:\\Users\\you\\AppData\\Local\\storebound\\storebound.exe" %*');
expect(w.skip).toBeNull();
const m = shimPlan({ exe: "/Applications/store'bound.app/Contents/MacOS/storebound", platform: 'darwin', home: '/Users/you', env: {} });
expect(m.content).toContain(`exec '/Applications/store'\\''bound.app/Contents/MacOS/storebound' "$@"`);
expect(m.profile!.endsWith('.zprofile')).toBe(true);
expect(shimPlan({ exe: '/usr/bin/storebound', platform: 'linux', home: '/home/you', env: {} }).profile!.endsWith('.profile')).toBe(true);
});
test('skips AppImage runs and the opt-out', () => {
expect(shimPlan({ exe: '/tmp/.mount_sbX/usr/bin/storebound', platform: 'linux', home: '/h', env: {} }).skip).toContain('AppImage');
expect(shimPlan({ exe: '/usr/bin/storebound', platform: 'linux', home: '/h', env: { STOREBOUND_NO_CLI_SHIM: '1' } }).skip).toContain('STOREBOUND_NO_CLI_SHIM');
});
test('onPath: trailing slashes, case on Windows only', () => {
expect(onPath('C:\\A\\bin', 'c:\\a\\bin\\;D:\\x', 'win32')).toBe(true);
expect(onPath('/h/.local/bin', '/usr/bin:/h/.local/bin/', 'linux')).toBe(true);
expect(onPath('/h/.local/bin', '/usr/bin:/H/.local/bin', 'linux')).toBe(false);
});
test('writes once, rewrites a moved app, never touches a file that is not ours, adds the profile line once', () => {
const home = mkdtempSync(join(tmpdir(), 'sb-shim-'));
const env = { PATH: '/usr/bin' };
const first = ensureCliShim('/opt/a/storebound', 'linux', env, home);
expect(first.join('\n')).toContain('terminal launcher written');
expect(first.join('\n')).toContain('added ~/.local/bin to PATH');
const file = join(home, '.local', 'bin', 'storebound');
expect(readFileSync(file, 'utf8')).toContain(SHIM_MARKER);
expect(ensureCliShim('/opt/a/storebound', 'linux', env, home).join()).toContain('up to date');
expect(ensureCliShim('/opt/b/storebound', 'linux', env, home).join()).toContain('written');
expect(readFileSync(file, 'utf8')).toContain('/opt/b/storebound');
expect(readFileSync(join(home, '.profile'), 'utf8').split(SHIM_MARKER).length - 1).toBe(2 - 1);
writeFileSync(file, '#!/bin/sh\nexec npm-storebound "$@"\n');
expect(ensureCliShim('/opt/c/storebound', 'linux', env, home).join()).toContain('is not ours');
expect(readFileSync(file, 'utf8')).toContain('npm-storebound');
if (process.platform === 'win32') return; // a C:\ temp folder has a colon: no POSIX PATH can name it
const home2 = mkdtempSync(join(tmpdir(), 'sb-shim-'));
mkdirSync(join(home2, '.local', 'bin'), { recursive: true });
expect(ensureCliShim('/opt/a/storebound', 'linux', { PATH: `/usr/bin:${join(home2, '.local', 'bin')}` }, home2).join()).not.toContain('PATH');
});
});