mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-06 05:35:46 +02:00
46c82ce8ec
New `gstack team` CLI with create, members, set subcommands. Migration adds team_settings (admin-only), alert_cooldowns (edge-fn dedup), and create_team() SECURITY DEFINER RPC for atomic team + first member creation. 9 tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
86 lines
3.0 KiB
TypeScript
86 lines
3.0 KiB
TypeScript
/**
|
|
* Tests for lib/cli-team.ts — team admin pure functions.
|
|
*/
|
|
|
|
import { describe, test, expect } from 'bun:test';
|
|
import { formatMembersTable } from '../lib/cli-team';
|
|
|
|
describe('formatMembersTable', () => {
|
|
test('formats members as table', () => {
|
|
const members = [
|
|
{ user_id: 'u1', email: 'alice@test.com', role: 'owner' },
|
|
{ user_id: 'u2', email: 'bob@test.com', role: 'member' },
|
|
{ user_id: 'u3', email: 'carol@test.com', role: 'admin' },
|
|
];
|
|
const output = formatMembersTable(members);
|
|
|
|
expect(output).toContain('Team Members');
|
|
expect(output).toContain('alice@test.com');
|
|
expect(output).toContain('bob@test.com');
|
|
expect(output).toContain('carol@test.com');
|
|
expect(output).toContain('owner');
|
|
expect(output).toContain('member');
|
|
expect(output).toContain('admin');
|
|
expect(output).toContain('3 members');
|
|
});
|
|
|
|
test('returns message for empty array', () => {
|
|
const output = formatMembersTable([]);
|
|
expect(output).toContain('No team members');
|
|
});
|
|
|
|
test('singular member count', () => {
|
|
const members = [{ user_id: 'u1', role: 'owner' }];
|
|
const output = formatMembersTable(members);
|
|
expect(output).toContain('1 member');
|
|
expect(output).not.toContain('1 members');
|
|
});
|
|
|
|
test('handles missing email gracefully', () => {
|
|
const members = [{ user_id: 'uuid-1234-abcd', role: 'member' }];
|
|
const output = formatMembersTable(members);
|
|
expect(output).toContain('uuid-1234-abcd');
|
|
expect(output).not.toContain('undefined');
|
|
});
|
|
|
|
test('truncates long emails', () => {
|
|
const members = [{ user_id: 'u1', email: 'very-long-email-address-that-exceeds-the-column-width@extremely-long-domain-name.com', role: 'member' }];
|
|
const output = formatMembersTable(members);
|
|
// Should not break the table layout
|
|
expect(output).toContain('Team Members');
|
|
expect(output).toContain('member');
|
|
});
|
|
});
|
|
|
|
describe('gstack team CLI', () => {
|
|
test('help shows usage', () => {
|
|
const proc = Bun.spawnSync(['bun', 'run', 'lib/cli-team.ts', '--help']);
|
|
const stdout = proc.stdout?.toString() || '';
|
|
expect(stdout).toContain('gstack team');
|
|
expect(stdout).toContain('create');
|
|
expect(stdout).toContain('members');
|
|
expect(stdout).toContain('set');
|
|
});
|
|
|
|
test('unknown command exits with error', () => {
|
|
const proc = Bun.spawnSync(['bun', 'run', 'lib/cli-team.ts', 'nonsense']);
|
|
expect(proc.exitCode).toBe(1);
|
|
const stderr = proc.stderr?.toString() || '';
|
|
expect(stderr).toContain('Unknown command');
|
|
});
|
|
|
|
test('create without args shows usage', () => {
|
|
const proc = Bun.spawnSync(['bun', 'run', 'lib/cli-team.ts', 'create']);
|
|
expect(proc.exitCode).toBe(1);
|
|
const stderr = proc.stderr?.toString() || '';
|
|
expect(stderr).toContain('Usage');
|
|
});
|
|
|
|
test('set without args shows usage', () => {
|
|
const proc = Bun.spawnSync(['bun', 'run', 'lib/cli-team.ts', 'set']);
|
|
expect(proc.exitCode).toBe(1);
|
|
const stderr = proc.stderr?.toString() || '';
|
|
expect(stderr).toContain('Usage');
|
|
});
|
|
});
|