fix(ext/sw): model isomorphic-git PushResult correctly; test the real push-rejection throw

PushResult has a singular `error: string | null` and a `refs` map — there
is no top-level `errors: string[]`. Replace the fabricated type and the
`errors`-based rejection guard with a correct PushResultRuntime type and a
belt-and-suspenders refsOk check. The real rejection path is a thrown
GitPushError (isomorphic-git throws, never returns, when a hook declines);
replace the single fiction-testing test with (a) a throw-path test that mocks
push to reject with a GitPushError and (b) a defensive non-throwing test that
mocks push to resolve { ok: false, error: 'unpack failed' }.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKBbrAjmpVXMEK15pNi3Ha
This commit is contained in:
adlee-was-taken
2026-06-26 00:19:34 -04:00
parent 56dec78f44
commit d942650f9f
2 changed files with 32 additions and 14 deletions

View File

@@ -147,14 +147,32 @@ describe('commitSignedPush engine', () => {
expect(args.onAuth()).toEqual(AUTH);
});
test('5 — push rejection throws with server detail', async () => {
test('5a — push rejection throw path (real): GitPushError thrown by isomorphic-git propagates', async () => {
// isomorphic-git THROWS GitPushError (never returns) when a pre-receive hook declines.
// This is the real rejection path; commitSignedPush must not swallow it.
const hookError = Object.assign(
new Error('One or more branches were not updated: pre-receive hook declined'),
{ code: 'GitPushError' },
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
vi.mocked(git.push).mockResolvedValueOnce({ ok: false, errors: ['pre-receive hook declined'] } as any);
vi.mocked(git.push).mockRejectedValueOnce(hookError);
const files: CommitFile[] = [{ path: 'vault/item.enc', content: new Uint8Array([1]) }];
await expect(
commitSignedPush({ gitUrl: GIT_URL, branch: BRANCH, auth: AUTH, files, message: 'test', signer: makeSigner() }),
).rejects.toThrow('pre-receive hook declined');
).rejects.toThrow('not updated');
});
test('5b — push rejection defensive path: non-throwing ok:false triggers guard', async () => {
// Belt-and-suspenders: if push() somehow resolves with ok:false (non-standard),
// the guard must still throw with the error detail from the result.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
vi.mocked(git.push).mockResolvedValueOnce({ ok: false, error: 'unpack failed', refs: {} } as any);
const files: CommitFile[] = [{ path: 'vault/item.enc', content: new Uint8Array([1]) }];
await expect(
commitSignedPush({ gitUrl: GIT_URL, branch: BRANCH, auth: AUTH, files, message: 'test', signer: makeSigner() }),
).rejects.toThrow('unpack failed');
});
});