UNPKG

@aaronshaf/ger

Version:

Gerrit CLI and SDK - A modern CLI tool and TypeScript SDK for Gerrit Code Review, built with Effect-TS

234 lines (200 loc) 6.44 kB
import { afterAll, beforeAll, beforeEach, describe, expect, mock, test } from 'bun:test' import { http, HttpResponse } from 'msw' import { setupServer } from 'msw/node' import { Layer } from 'effect' import { Effect } from 'effect' import { GerritApiServiceLive } from '@/api/gerrit' import { openCommand } from '@/cli/commands/open' import { ConfigService } from '@/services/config' import { createMockConfigService } from './helpers/config-mock' // Mock child_process.exec const mockExec = mock() mock.module('node:child_process', () => ({ exec: mockExec, })) const server = setupServer() beforeAll(() => { server.listen() }) beforeEach(() => { mockExec.mockClear() }) afterAll(() => { server.close() }) describe('open command', () => { test('should open change URL in browser', async () => { // Mock the exec function to simulate successful browser opening mockExec.mockImplementation((cmd: string, callback: (error: null) => void) => { expect(cmd).toMatch( /^(open|start|xdg-open) "https:\/\/gerrit\.example\.com\/c\/test-project\/\+\/12345"$/, ) callback(null) }) server.use( http.get('*/a/changes/12345', () => { return HttpResponse.text( `)]}'\n${JSON.stringify({ id: 'test-project~main~I1234567890abcdef', project: 'test-project', branch: 'main', change_id: 'I1234567890abcdef', subject: 'Test change', status: 'NEW', _number: 12345, owner: { _account_id: 1000000, name: 'Test User', email: 'test@example.com', }, })}`, ) }), ) const mockConfigLayer = Layer.succeed( ConfigService, createMockConfigService({ host: 'https://gerrit.example.com', username: 'testuser', password: 'testpass', }), ) const consoleSpy = mock(() => {}) const originalLog = console.log console.log = consoleSpy const program = openCommand('12345').pipe( Effect.provide(GerritApiServiceLive), Effect.provide(mockConfigLayer), ) await Effect.runPromise(program) console.log = originalLog expect(mockExec).toHaveBeenCalledTimes(1) expect(consoleSpy).toHaveBeenCalledWith( 'Opened: https://gerrit.example.com/c/test-project/+/12345', ) }) test('should handle URLs and extract change number', async () => { mockExec.mockImplementation((cmd: string, callback: (error: null) => void) => { expect(cmd).toMatch( /^(open|start|xdg-open) "https:\/\/gerrit\.example\.com\/c\/test-project\/\+\/12345"$/, ) callback(null) }) server.use( http.get('*/a/changes/12345', () => { return HttpResponse.text( `)]}'\n${JSON.stringify({ id: 'test-project~main~I1234567890abcdef', project: 'test-project', branch: 'main', change_id: 'I1234567890abcdef', subject: 'Test change', status: 'NEW', _number: 12345, owner: { _account_id: 1000000, name: 'Test User', }, })}`, ) }), ) const mockConfigLayer = Layer.succeed( ConfigService, createMockConfigService({ host: 'https://gerrit.example.com', username: 'testuser', password: 'testpass', }), ) const consoleSpy = mock(() => {}) const originalLog = console.log console.log = consoleSpy // Test with a full Gerrit URL const program = openCommand('https://gerrit.example.com/c/test-project/+/12345').pipe( Effect.provide(GerritApiServiceLive), Effect.provide(mockConfigLayer), ) await Effect.runPromise(program) console.log = originalLog expect(mockExec).toHaveBeenCalledTimes(1) expect(consoleSpy).toHaveBeenCalledWith( 'Opened: https://gerrit.example.com/c/test-project/+/12345', ) }) test('should handle invalid change ID', async () => { const mockConfigLayer = Layer.succeed( ConfigService, createMockConfigService({ host: 'https://gerrit.example.com', username: 'testuser', password: 'testpass', }), ) // Use an empty string which is truly invalid according to isValidChangeId const program = openCommand('').pipe( Effect.provide(GerritApiServiceLive), Effect.provide(mockConfigLayer), ) await expect(Effect.runPromise(program)).rejects.toThrow('Invalid change ID: ') }) test('should handle API errors gracefully', async () => { server.use( http.get('*/a/changes/12345', () => { return HttpResponse.json({ error: 'Change not found' }, { status: 404 }) }), ) const mockConfigLayer = Layer.succeed( ConfigService, createMockConfigService({ host: 'https://gerrit.example.com', username: 'testuser', password: 'testpass', }), ) const program = openCommand('12345').pipe( Effect.provide(GerritApiServiceLive), Effect.provide(mockConfigLayer), ) await expect(Effect.runPromise(program)).rejects.toThrow() }) test('should handle browser opening errors', async () => { mockExec.mockImplementation((cmd: string, callback: (error: Error) => void) => { callback(new Error('Browser not found')) }) server.use( http.get('*/a/changes/12345', () => { return HttpResponse.text( `)]}'\n${JSON.stringify({ id: 'test-project~main~I1234567890abcdef', project: 'test-project', branch: 'main', change_id: 'I1234567890abcdef', subject: 'Test change', status: 'NEW', _number: 12345, owner: { _account_id: 1000000, name: 'Test User', }, })}`, ) }), ) const mockConfigLayer = Layer.succeed( ConfigService, createMockConfigService({ host: 'https://gerrit.example.com', username: 'testuser', password: 'testpass', }), ) const program = openCommand('12345').pipe( Effect.provide(GerritApiServiceLive), Effect.provide(mockConfigLayer), ) await expect(Effect.runPromise(program)).rejects.toThrow( 'Failed to open URL: Browser not found', ) }) })