open source is social v-it.org
at main 132 lines 5.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, writeFileSync } from 'node:fs'; 7import { tmpdir } from 'node:os'; 8import { join } from 'node:path'; 9 10const agentEnv = { CLAUDECODE: '1' }; 11 12function makeVitDir(base, beacon) { 13 const vitDir = join(base, '.vit'); 14 mkdirSync(vitDir, { recursive: true }); 15 writeFileSync(join(vitDir, 'config.json'), JSON.stringify({ beacon })); 16 return base; 17} 18 19describe('vit ship --kind request', () => { 20 test('accepts request as a valid kind value (errors at auth, not validation)', () => { 21 const tmp = join(tmpdir(), '.test-ship-req-' + Math.random().toString(36).slice(2)); 22 makeVitDir(tmp, 'vit:github.com/test/project'); 23 const r = run( 24 'ship --kind request --title "Add async validation" --description "Need async validators" --did did:plc:abc', 25 tmp, 26 agentEnv, 27 '', 28 ); 29 expect(r.stderr).not.toMatch(/--kind must be one of/i); 30 rmSync(tmp, { recursive: true, force: true }); 31 }); 32 33 test('rejects request without beacon when not in vit-initialized dir', () => { 34 const tmp = join(tmpdir(), '.test-ship-req-nobeacon-' + Math.random().toString(36).slice(2)); 35 mkdirSync(tmp, { recursive: true }); 36 const r = run( 37 'ship --kind request --title "Add async validation" --description "Need async validators" --did did:plc:abc', 38 tmp, 39 agentEnv, 40 '', 41 ); 42 expect(r.exitCode).not.toBe(0); 43 expect(r.stderr).toContain('request caps must be addressed to a project'); 44 rmSync(tmp, { recursive: true, force: true }); 45 }); 46 47 test('accepts --beacon flag for request caps outside vit dir', () => { 48 const tmp = join(tmpdir(), '.test-ship-req-beacon-' + Math.random().toString(36).slice(2)); 49 mkdirSync(tmp, { recursive: true }); 50 const r = run( 51 'ship --kind request --title "Add async validation" --description "Need async validators" --beacon github.com/pydantic/pydantic --did did:plc:abc', 52 tmp, 53 agentEnv, 54 '', 55 ); 56 // Should not fail on beacon validation — will fail at auth 57 expect(r.stderr).not.toContain('request caps must be addressed to a project'); 58 expect(r.stderr).not.toMatch(/--kind must be one of/i); 59 rmSync(tmp, { recursive: true, force: true }); 60 }); 61 62 test('normalizes github.com URL to vit: beacon', () => { 63 const tmp = join(tmpdir(), '.test-ship-req-norm-' + Math.random().toString(36).slice(2)); 64 mkdirSync(tmp, { recursive: true }); 65 const r = run( 66 'ship --kind request --title "Add async validation" --description "Need async validators" --beacon github.com/pydantic/pydantic --did did:plc:abc', 67 tmp, 68 agentEnv, 69 '', 70 ); 71 // Beacon normalization succeeds; error is at auth 72 expect(r.stderr).not.toContain('invalid --beacon'); 73 rmSync(tmp, { recursive: true, force: true }); 74 }); 75 76 test('auto-generates ref from title when --ref not provided', () => { 77 const tmp = join(tmpdir(), '.test-ship-req-autoref-' + Math.random().toString(36).slice(2)); 78 makeVitDir(tmp, 'vit:github.com/test/project'); 79 const r = run( 80 'ship --kind request --title "Add async validation support" --description "Need async validators" --did did:plc:abc', 81 tmp, 82 agentEnv, 83 '', 84 ); 85 // Should not fail on missing --ref 86 expect(r.stderr).not.toMatch(/--ref.*not specified/i); 87 // Auto-generated ref is printed (fails at auth, not ref generation) 88 expect(r.stderr).not.toMatch(/three lowercase words/i); 89 rmSync(tmp, { recursive: true, force: true }); 90 }); 91 92 test('requires --title for ref auto-generation', () => { 93 const tmp = join(tmpdir(), '.test-ship-req-notitle-' + Math.random().toString(36).slice(2)); 94 makeVitDir(tmp, 'vit:github.com/test/project'); 95 const r = run( 96 'ship --kind request --description "Need async validators" --did did:plc:abc', 97 tmp, 98 agentEnv, 99 '', 100 ); 101 // Missing --title is caught before ref generation 102 expect(r.exitCode).not.toBe(0); 103 expect(r.stderr).toMatch(/--title/i); 104 rmSync(tmp, { recursive: true, force: true }); 105 }); 106 107 test('text is optional for request caps (empty stdin does not error)', () => { 108 const tmp = join(tmpdir(), '.test-ship-req-notext-' + Math.random().toString(36).slice(2)); 109 makeVitDir(tmp, 'vit:github.com/test/project'); 110 const r = run( 111 'ship --kind request --title "Add async validation support" --description "Need async validators" --did did:plc:abc', 112 tmp, 113 agentEnv, 114 '', 115 ); 116 // Should not error on empty stdin for request caps 117 expect(r.stderr).not.toMatch(/body is required/i); 118 rmSync(tmp, { recursive: true, force: true }); 119 }); 120 121 test('--help shows request in --kind options', () => { 122 const r = run('ship --help'); 123 expect(r.exitCode).toBe(0); 124 expect(r.stdout).toContain('request'); 125 }); 126 127 test('--help shows --beacon option', () => { 128 const r = run('ship --help'); 129 expect(r.exitCode).toBe(0); 130 expect(r.stdout).toContain('--beacon'); 131 }); 132});