73 lines
4.3 KiB
TypeScript
73 lines
4.3 KiB
TypeScript
// One app record, an iOS and a macOS App Store version (pitfall 79): CFBundleVersion must be unique across ALL the app's
|
|
// builds, so `apple next-build`, `apple build` and `apple build --platform macos` (also --dry) share one computation.
|
|
// Seen live: the macOS dry run proposed a build number an uploaded macOS build already had (it asked only for macOS
|
|
// builds), while next-build said the right one. Against the fake App Store Connect.
|
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test } from 'bun:test';
|
|
import type { ShipConfig } from '../cli/lib/config';
|
|
import { appNextBuild, run as nextBuild } from '../cli/apple/next-build';
|
|
import { identityLine, run as buildMas } from '../cli/apple/build-mas';
|
|
import { ascEnv, BASE, capture, project, restore } from './helpers/store-mock';
|
|
import { installStores, type Stores, uninstallStores } from './helpers/fake-stores';
|
|
|
|
const APP = '6400000101';
|
|
const CONFIG: ShipConfig = { ...BASE };
|
|
const TAURI = JSON.stringify({ productName: 'Example Notes', identifier: 'com.example.notes', version: '1.2.0' });
|
|
let s: Stores;
|
|
beforeAll(ascEnv);
|
|
afterAll(restore);
|
|
beforeEach(() => { s = installStores(); });
|
|
afterEach(uninstallStores);
|
|
|
|
const build = (id: string, version: string, state = 'VALID') => s.asc.put({ type: 'builds', id, attributes: { version, processingState: state }, rels: { app: APP } });
|
|
/** iOS builds 202610261700 / ...1730, a macOS build ...1731 and an expired one ...1734 in another state. */
|
|
function seed(): void {
|
|
build('b-ios-1', '202610261700');
|
|
build('b-ios-2', '202610261730');
|
|
build('b-mac-1', '202610261731');
|
|
build('b-mac-2', '202610261734', 'PROCESSING');
|
|
}
|
|
|
|
describe('next build number over every platform', () => {
|
|
test('apple next-build and the macOS dry run agree and sit above the highest build', async () => {
|
|
seed();
|
|
const p = project(CONFIG, { 'src-tauri/tauri.conf.json': TAURI });
|
|
const nb = await capture(() => nextBuild(p.ctx(['--json'])));
|
|
expect(JSON.parse(nb.out)).toEqual({ next: '202610261735', builds: 4 });
|
|
const dry = await capture(() => buildMas(p.ctx(['--tauri', 'src-tauri', '--unsigned', '--dry', '--json']), 'linux'));
|
|
expect(JSON.parse(dry.out.slice(dry.out.indexOf('{')))).toMatchObject({ platform: 'MAC_OS', build: '202610261735' });
|
|
});
|
|
test('no request narrows the build list to one platform', async () => {
|
|
seed();
|
|
const p = project(CONFIG, { 'src-tauri/tauri.conf.json': TAURI });
|
|
await capture(() => buildMas(p.ctx(['--tauri', 'src-tauri', '--unsigned', '--dry', '--json']), 'linux'));
|
|
const reads = s.calls.filter(c => /\/v1\/builds/.test(c.path));
|
|
expect(reads.length).toBeGreaterThan(0);
|
|
for (const r of reads) expect(decodeURIComponent(r.path)).not.toMatch(/preReleaseVersion|platform|processingState/);
|
|
});
|
|
test('every page counts', async () => {
|
|
const pages: Record<string, unknown> = {
|
|
'/p1': { data: [{ attributes: { version: '5' } }], links: { next: '/p2' } },
|
|
'/p2': { data: [{ attributes: { version: '41' } }], links: { next: '/p3' } },
|
|
'/p3': { data: [{ attributes: { version: '9' } }], links: {} },
|
|
};
|
|
const seen: string[] = [];
|
|
const client = { app: async () => APP, all: async (path: string) => { seen.push(path); const out: unknown[] = []; for (let u: string | undefined = '/p1'; u; u = (pages[u] as { links: { next?: string } }).links.next) out.push(...(pages[u] as { data: unknown[] }).data); return out; } };
|
|
expect(await appNextBuild(client as never)).toEqual({ next: '42', builds: 3 });
|
|
expect(seen[0]).toContain(`filter[app]=${APP}`);
|
|
});
|
|
test('an app without builds starts at 1', async () => {
|
|
expect((await appNextBuild({ app: async () => APP, all: async () => [] } as never)).next).toBe('1');
|
|
});
|
|
});
|
|
|
|
describe('identity line off a Mac', () => {
|
|
test('a non-macOS machine is called a non-build machine, not "none found"', () => {
|
|
const line = identityLine({ platform: 'win32', appIdentity: null, installerIdentity: null, profile: null });
|
|
expect(line).toContain('not a build machine');
|
|
expect(line).toContain('Mac');
|
|
expect(line).not.toContain('none found');
|
|
});
|
|
test('on a Mac a missing identity is still reported as missing', () => {
|
|
expect(identityLine({ platform: 'darwin', appIdentity: null, installerIdentity: 'Mac Installer', profile: null })).toContain('app identity: (none found); installer identity: Mac Installer');
|
|
});
|
|
});
|