From 73e04fb9a1b255d34d28f3fb1feb6952882a7024 Mon Sep 17 00:00:00 2001 From: kbkb628 <278338969+kbkb628@users.noreply.github.com> Date: Thu, 3 Sep 2026 13:12:08 +0800 Subject: [PATCH] test(longbridge-tools): skip account-fixture tests when captured fixtures are absent positions/assets/cash-flow/portfolio fixtures are captured from a real authenticated account and deliberately gitignored, so a fresh clone (and CI) failed 7 tests. Skip them when the fixture files are missing; maintainers who regenerate fixtures via capture.sh keep full coverage. --- .../longbridge-tools/src/normalizer.test.ts | 7 ++++-- .../longbridge-tools/src/phase-two.test.ts | 22 +++++++++++++------ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/longbridge-tools/src/normalizer.test.ts b/packages/longbridge-tools/src/normalizer.test.ts index 7173722..d34e469 100644 --- a/packages/longbridge-tools/src/normalizer.test.ts +++ b/packages/longbridge-tools/src/normalizer.test.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from 'bun:test'; +import { existsSync } from 'node:fs'; import { classifyPortfolioFailure, computeUnrealizedPnLPercent, @@ -7,7 +8,7 @@ import { } from './normalizer.ts'; import { parsePortfolioResponse } from './parser.ts'; import { LongBridgeError } from './errors.ts'; -import { loadFixture, loadFixtureText } from './testing/load-fixture.ts'; +import { fixturePath, loadFixture, loadFixtureText } from './testing/load-fixture.ts'; import type { Holding, PortfolioSnapshot } from '@finagent/core'; // ── UI-visible invariants (spec §15, §17) ───────────────────────────────── @@ -161,7 +162,9 @@ describe('normalizePortfolioSnapshot fixture matrix (spec §59)', () => { }); describe('real CLI fixture', () => { - it('maps the real `longbridge portfolio --format json` body (totals + holdings + base USD)', () => { + // The `portfolio` fixture is captured from a real authenticated account and + // never committed; skip when absent (see .gitignore + capture.sh). + it.skipIf(!existsSync(fixturePath('portfolio')))('maps the real `longbridge portfolio --format json` body (totals + holdings + base USD)', () => { const raw = JSON.parse(loadFixtureText('portfolio')); const snapshot = normalizePortfolioSnapshot(raw, 1000); expect(snapshot.baseCurrency).toBe('USD'); diff --git a/packages/longbridge-tools/src/phase-two.test.ts b/packages/longbridge-tools/src/phase-two.test.ts index 47d8e13..a9019d0 100644 --- a/packages/longbridge-tools/src/phase-two.test.ts +++ b/packages/longbridge-tools/src/phase-two.test.ts @@ -1,7 +1,15 @@ import { beforeEach, describe, expect, it, mock } from 'bun:test'; -import { loadFixture } from './testing/load-fixture.ts'; +import { existsSync } from 'node:fs'; +import { fixturePath, loadFixture } from './testing/load-fixture.ts'; import { LongBridgeError } from './errors.ts'; +// Account-scoped fixtures (positions/assets/cash-flow/portfolio) are captured +// from a real authenticated account and never committed (see .gitignore + +// capture.sh). Skip the tests that need them when they are absent, so a fresh +// clone keeps a green suite; maintainers with a captured account still get the +// coverage. +const hasAccountFixture = (name: string): boolean => existsSync(fixturePath(name)); + type ExecaResult = { stdout: string }; type ExecaHandler = ( command: string, @@ -135,7 +143,7 @@ describe('phase-2 parser normalization', () => { expect(events).toEqual([]); }); - it('parses positions fixture', () => { + it.skipIf(!hasAccountFixture('positions'))('parses positions fixture', () => { const positions = parsePositionsResponse(JSON.stringify(loadFixture('positions'))); expect(positions.length).toBeGreaterThan(0); expect(typeof positions[0].quantity).toBe('number'); @@ -143,14 +151,14 @@ describe('phase-2 parser normalization', () => { expect(positions[0].symbol).toBeTruthy(); }); - it('parses assets fixture', () => { + it.skipIf(!hasAccountFixture('assets'))('parses assets fixture', () => { const assets = parseAssetsResponse(JSON.stringify(loadFixture('assets'))); expect(assets.length).toBeGreaterThan(0); expect(typeof assets[0].netAssets).toBe('number'); expect(assets[0].cashInfos.length).toBeGreaterThan(0); }); - it('parses cash-flow fixture', () => { + it.skipIf(!hasAccountFixture('cash-flow'))('parses cash-flow fixture', () => { const flows = parseCashFlowResponse(JSON.stringify(loadFixture('cash-flow'))); expect(flows.length).toBeGreaterThan(0); expect(typeof flows[0].amount).toBe('number'); @@ -227,13 +235,13 @@ describe('phase-2 argv construction', () => { ); }); - it('getAccountPositions takes no symbol', async () => { + it.skipIf(!hasAccountFixture('positions'))('getAccountPositions takes no symbol', async () => { execaHandler = async () => ({ stdout: JSON.stringify(loadFixture('positions')) }); await getAccountPositions(); expect(execaMock).toHaveBeenCalledWith('longbridge', ['positions', '--format', 'json'], expect.any(Object)); }); - it('getAssets forwards optional currency', async () => { + it.skipIf(!hasAccountFixture('assets'))('getAssets forwards optional currency', async () => { execaHandler = async () => ({ stdout: JSON.stringify(loadFixture('assets')) }); await getAssets('HKD'); expect(execaMock).toHaveBeenCalledWith( @@ -243,7 +251,7 @@ describe('phase-2 argv construction', () => { ); }); - it('getCashFlow forwards date range', async () => { + it.skipIf(!hasAccountFixture('cash-flow'))('getCashFlow forwards date range', async () => { execaHandler = async () => ({ stdout: JSON.stringify(loadFixture('cash-flow')) }); await getCashFlow({ start: '2026-01-01', end: '2026-03-31' }); expect(execaMock).toHaveBeenCalledWith(