open source is social v-it.org
at main 95 lines 4.1 kB view raw
1// SPDX-License-Identifier: MIT 2// Copyright (c) 2026 sol pbc 3 4import { describe, test, expect } from 'bun:test'; 5import { run } from './helpers.js'; 6import { mkdirSync, rmSync } from 'node:fs'; 7import { tmpdir } from 'node:os'; 8import { join } from 'node:path'; 9 10const agentEnv = { CLAUDECODE: '1' }; 11 12describe('vit ship', () => { 13 test('rejects when run outside a coding agent', () => { 14 const r = run('ship --title "Hi" --description "desc" --ref "one-two-three"', '/tmp', { CLAUDECODE: '', GEMINI_CLI: '', CODEX_CI: '' }, 'body text'); 15 expect(r.exitCode).not.toBe(0); 16 expect(r.stderr).toContain('should be run by a coding agent'); 17 }); 18 19 test('fails when --title is missing', () => { 20 const r = run('ship --description "desc" --ref "one-two-three"'); 21 expect(r.exitCode).not.toBe(0); 22 expect(r.stderr).toMatch(/--title/i); 23 }); 24 25 test('fails when --description is missing', () => { 26 const r = run('ship --title "Hi" --ref "one-two-three"'); 27 expect(r.exitCode).not.toBe(0); 28 expect(r.stderr).toMatch(/--description/i); 29 }); 30 31 test('fails when --ref is missing', () => { 32 const r = run('ship --title "Hi" --description "desc"'); 33 expect(r.exitCode).not.toBe(0); 34 expect(r.stderr).toMatch(/--ref/i); 35 }); 36 37 test('fails when stdin body is empty', () => { 38 const r = run('ship --title "Hi" --description "desc" --ref "one-two-three" --did "did:plc:abc"', undefined, agentEnv, ''); 39 expect(r.exitCode).not.toBe(0); 40 expect(r.stderr).toMatch(/body is required/i); 41 }); 42 43 test('rejects ref with uppercase letters', () => { 44 const r = run('ship --title "Hi" --description "desc" --ref "Bad-Ref-Here" --did "did:plc:abc"', undefined, agentEnv, 'body text'); 45 expect(r.exitCode).not.toBe(0); 46 expect(r.stderr).toMatch(/three lowercase words/i); 47 }); 48 49 test('rejects ref with wrong segment count', () => { 50 const r = run('ship --title "Hi" --description "desc" --ref "only-two" --did "did:plc:abc"', undefined, agentEnv, 'body text'); 51 expect(r.exitCode).not.toBe(0); 52 expect(r.stderr).toMatch(/three lowercase words/i); 53 }); 54 55 test('rejects ref with digits', () => { 56 const r = run('ship --title "Hi" --description "desc" --ref "has-num-3bers" --did "did:plc:abc"', undefined, agentEnv, 'body text'); 57 expect(r.exitCode).not.toBe(0); 58 expect(r.stderr).toMatch(/three lowercase words/i); 59 }); 60 61 test('rejects --recap with invalid ref format', () => { 62 const r = run('ship --title "Hi" --description "desc" --ref "one-two-three" --recap "BAD" --did "did:plc:abc"', undefined, agentEnv, 'body text'); 63 expect(r.exitCode).not.toBe(0); 64 expect(r.stderr).toMatch(/--recap must be exactly three lowercase words/i); 65 }); 66 67 test('rejects --kind with invalid value', () => { 68 const r = run('ship --title "Hi" --description "desc" --ref "one-two-three" --kind "invalid" --did "did:plc:abc"', undefined, agentEnv, 'body text'); 69 expect(r.exitCode).not.toBe(0); 70 expect(r.stderr).toMatch(/--kind must be one of/i); 71 }); 72 73 test('--help shows --kind and --recap', () => { 74 const r = run('ship --help'); 75 expect(r.exitCode).toBe(0); 76 expect(r.stdout).toContain('--kind <kind>'); 77 expect(r.stdout).toContain('--recap <ref>'); 78 }); 79 80 test('accepts valid ref format (fails at auth, not validation)', () => { 81 const r = run('ship --title "Hi" --description "desc" --ref "one-two-three" --did "did:plc:abc"', undefined, agentEnv, 'body text'); 82 expect(r.exitCode).not.toBe(0); 83 expect(r.stderr).not.toMatch(/three lowercase words/i); 84 expect(r.stderr).not.toMatch(/body is required/i); 85 }); 86 87 test('errors when no beacon set', () => { 88 const tmp = join(tmpdir(), '.test-ship-beacon-' + Math.random().toString(36).slice(2)); 89 mkdirSync(tmp, { recursive: true }); 90 const r = run('ship --title "Hi" --description "desc" --ref "one-two-three" --did "did:plc:abc"', tmp, agentEnv, 'body text'); 91 expect(r.exitCode).not.toBe(0); 92 expect(r.stderr).toContain('no beacon set'); 93 rmSync(tmp, { recursive: true, force: true }); 94 }); 95});