import { describe, expect, it } from 'vitest' import { formatSubmodulePushFailureDetail, isNoUpstreamError, normalizeGitErrorMessage } from './git-remote-error' describe('normalizeGitErrorMessage', () => { it('keeps the submodule name when a recursive push is rejected', () => { const error = new Error( "Command failed: git push\nPushing submodule 'find-cmux-followers'\n" + 'To https://github.com/stablyai/orca-internal\n' + ' ! [rejected] master -> master (fetch first)\n' + "Unable to push submodule 'find-cmux-followers'\n" + 'fatal: failed to push all needed submodules' ) expect(normalizeGitErrorMessage(error, 'push')).toBe( "Submodule 'find-cmux-followers' has remote changes. Pull inside the submodule, then try again." ) }) }) describe('formatSubmodulePushFailureDetail', () => { it('keeps normalized guidance when transport layers prefix the error', () => { expect( formatSubmodulePushFailureDetail( "Error invoking remote method 'git:push': Error: Submodule 'vendor/tools' has remote changes. Pull inside the submodule, then try again." ) ).toBe( "Submodule 'vendor/tools' has remote changes. Pull inside the submodule, then try again." ) }) it('falls back to submodule-specific guidance when git omits the nested reason', () => { expect( formatSubmodulePushFailureDetail( "Unable to push submodule 'vendor/tools'\nfatal: failed to push all needed submodules" ) ).toBe( "Submodule 'vendor/tools' could not be pushed. Resolve the submodule push error, then try again." ) }) }) describe('isNoUpstreamError', () => { it('treats a missing HEAD@{u} tracking ref as no upstream', () => { const error = new Error( "fatal: ambiguous argument 'HEAD@{u}': unknown revision or path not in the working tree.\n" + "Use '--' to separate paths from revisions, like this:\n" + "'git [...] -- [...]'" ) expect(isNoUpstreamError(error)).toBe(true) }) it('does not treat unrelated ambiguous refs as no upstream', () => { const error = new Error( "fatal: ambiguous argument 'feature': unknown revision or path not in the working tree." ) expect(isNoUpstreamError(error)).toBe(false) }) })