Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions src/commands/account/account.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Command } from 'commander'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { captureConsole } from '../../test-helpers/console.js'
import { createTestProgram } from '../../test-helpers/program.js'

const storeMocks = vi.hoisted(() => ({
set: vi.fn(),
Expand Down Expand Up @@ -31,12 +32,7 @@ import { type TwistAccount } from '../../lib/auth-provider.js'
import { TOKEN_ENV_VAR } from '../../lib/auth.js'
import { registerAccountCommand } from './index.js'

function createProgram() {
const program = new Command()
program.exitOverride()
registerAccountCommand(program)
return program
}
const createProgram = () => createTestProgram(registerAccountCommand)

/** Seed `store.list()` and `store.setDefault/clear` resolvers in one call. */
function seedStore(...records: Array<TwistAccount | [TwistAccount, 'default']>): void {
Expand All @@ -63,13 +59,11 @@ describe('account command', () => {
beforeEach(() => {
vi.clearAllMocks()
legacyMocks.isLegacyAuthActive.mockResolvedValue(false)
consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
consoleSpy = captureConsole()
errorSpy = captureConsole('error')
})

afterEach(() => {
consoleSpy.mockRestore()
errorSpy.mockRestore()
vi.unstubAllEnvs()
})

Expand Down
19 changes: 5 additions & 14 deletions src/commands/auth/auth.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Command } from 'commander'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { captureConsole } from '../../test-helpers/console.js'
import { createTestProgram } from '../../test-helpers/program.js'

// Mock the auth module (only the read-side shims are stubbed; the
// write-side path now goes through `createTwistTokenStore` from
Expand Down Expand Up @@ -89,12 +91,7 @@ const mockGetAuthMetadata = vi.mocked(getAuthMetadata)
const mockCreateWrappedTwistClient = vi.mocked(createWrappedTwistClient)
const mockAttachLoginCommand = vi.mocked(attachLoginCommand)

function createProgram() {
const program = new Command()
program.exitOverride()
registerAuthCommand(program)
return program
}
const createProgram = () => createTestProgram(registerAuthCommand)

const TEST_USER: User = {
id: 1,
Expand All @@ -114,14 +111,8 @@ describe('auth command', () => {
beforeEach(() => {
vi.clearAllMocks()

// Mock console.log to capture output
consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
})

afterEach(() => {
consoleSpy.mockRestore()
errorSpy.mockRestore()
consoleSpy = captureConsole()
errorSpy = captureConsole('error')
})

const STORED_ACCOUNT: TwistAccount = {
Expand Down
31 changes: 10 additions & 21 deletions src/commands/away/away.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TwistRequestError } from '@doist/twist-sdk'
import { Command } from 'commander'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { captureConsole } from '../../test-helpers/console.js'
import { createTestProgram } from '../../test-helpers/program.js'

const apiMocks = vi.hoisted(() => ({
getSessionUser: vi.fn(),
Expand All @@ -17,12 +18,7 @@ vi.mock('chalk')

import { registerAwayCommand } from './index.js'

function createProgram() {
const program = new Command()
program.exitOverride()
registerAwayCommand(program)
return program
}
const createProgram = () => createTestProgram(registerAwayCommand)

describe('away', () => {
beforeEach(() => {
Expand All @@ -45,13 +41,12 @@ describe('away', () => {
name: 'Test User',
awayMode: null,
})
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const logSpy = captureConsole()
const program = createProgram()

await program.parseAsync(['node', 'tw', 'away'])

expect(logSpy).toHaveBeenCalledWith('Not away.')
logSpy.mockRestore()
})

it('shows away status when set', async () => {
Expand All @@ -60,19 +55,18 @@ describe('away', () => {
name: 'Test User',
awayMode: { type: 'vacation', dateFrom: '2026-03-10', dateTo: '2026-03-20' },
})
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const logSpy = captureConsole()
const program = createProgram()

await program.parseAsync(['node', 'tw', 'away'])

expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Vacation'))
logSpy.mockRestore()
})
})

describe('set', () => {
it('calls users.update with awayMode', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
captureConsole()
const program = createProgram()

await program.parseAsync(['node', 'tw', 'away', 'set', 'vacation', '2026-03-20'])
Expand All @@ -85,11 +79,10 @@ describe('away', () => {
}),
}),
)
logSpy.mockRestore()
})

it('supports --from flag', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
captureConsole()
const program = createProgram()

await program.parseAsync([
Expand All @@ -106,11 +99,10 @@ describe('away', () => {
expect(apiMocks.updateUser).toHaveBeenCalledWith({
awayMode: { type: 'vacation', dateFrom: '2026-03-15', dateTo: '2026-03-20' },
})
logSpy.mockRestore()
})

it('shows dry-run message', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const logSpy = captureConsole()
const program = createProgram()

await program.parseAsync([
Expand All @@ -125,7 +117,6 @@ describe('away', () => {

expect(apiMocks.updateUser).not.toHaveBeenCalled()
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Would set away status'))
logSpy.mockRestore()
})

it('propagates insufficient scope errors (handled globally by API proxy)', async () => {
Expand All @@ -152,25 +143,23 @@ describe('away', () => {

describe('clear', () => {
it('calls users.update with empty string awayMode to clear', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const logSpy = captureConsole()
const program = createProgram()

await program.parseAsync(['node', 'tw', 'away', 'clear'])

expect(apiMocks.updateUser).toHaveBeenCalledWith({ awayMode: '' })
expect(logSpy).toHaveBeenCalledWith('Away status cleared.')
logSpy.mockRestore()
})

it('shows dry-run message', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const logSpy = captureConsole()
const program = createProgram()

await program.parseAsync(['node', 'tw', 'away', 'clear', '--dry-run'])

expect(apiMocks.updateUser).not.toHaveBeenCalled()
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Would clear away status'))
logSpy.mockRestore()
})
})
})
12 changes: 4 additions & 8 deletions src/commands/changelog.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Command } from 'commander'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { captureConsole } from '../test-helpers/console.js'
import { createTestProgram } from '../test-helpers/program.js'

vi.mock('node:fs/promises')

Expand Down Expand Up @@ -32,18 +33,13 @@ const SAMPLE_CHANGELOG = `# Changelog
* prior release with a level-2 heading
`

function createProgram() {
const program = new Command()
program.exitOverride()
registerChangelogCommand(program)
return program
}
const createProgram = () => createTestProgram(registerChangelogCommand)

describe('changelog wrapper', () => {
let logSpy: ReturnType<typeof vi.spyOn>

beforeEach(() => {
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
logSpy = captureConsole()
})

afterEach(() => {
Expand Down
38 changes: 12 additions & 26 deletions src/commands/channel/add.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Command } from 'commander'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createChannelFixture } from '../../lib/__fixtures__/channels.js'
import { captureConsole } from '../../test-helpers/console.js'
import { createTestProgram } from '../../test-helpers/program.js'

const mockGetChannel = vi.fn()

Expand All @@ -26,25 +28,9 @@ vi.mock('chalk')

import { registerChannelCommand } from './index.js'

function createProgram() {
const program = new Command()
program.exitOverride()
registerChannelCommand(program)
return program
}

const sampleChannel = {
id: 500,
name: 'general',
workspaceId: 1,
userIds: [1, 2, 3],
creator: 1,
public: true,
archived: false,
created: new Date(),
version: 1,
url: 'https://twist.com/a/1/ch/500',
}
const createProgram = () => createTestProgram(registerChannelCommand)

const sampleChannel = createChannelFixture()
Comment thread
scottlovegrove marked this conversation as resolved.

beforeEach(() => {
vi.clearAllMocks()
Expand All @@ -63,7 +49,7 @@ describe('tw channel members add', () => {
expandedFrom: [],
})
const program = createProgram()
vi.spyOn(console, 'log').mockImplementation(() => {})
captureConsole()

await program.parseAsync([
'node',
Expand All @@ -89,7 +75,7 @@ describe('tw channel members add', () => {
expandedFrom: [{ groupId: 200, groupName: 'Backend', userIds: [4, 5] }],
})
const program = createProgram()
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const consoleSpy = captureConsole()

await program.parseAsync([
'node',
Expand All @@ -114,7 +100,7 @@ describe('tw channel members add', () => {
expandedFrom: [],
})
const program = createProgram()
vi.spyOn(console, 'log').mockImplementation(() => {})
captureConsole()

await program.parseAsync([
'node',
Expand All @@ -136,7 +122,7 @@ describe('tw channel members add', () => {
expandedFrom: [],
})
const program = createProgram()
vi.spyOn(console, 'log').mockImplementation(() => {})
captureConsole()

await program.parseAsync([
'node',
Expand All @@ -158,7 +144,7 @@ describe('tw channel members add', () => {
expandedFrom: [],
})
const program = createProgram()
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const consoleSpy = captureConsole()

await program.parseAsync([
'node',
Expand All @@ -182,7 +168,7 @@ describe('tw channel members add', () => {
expandedFrom: [],
})
const program = createProgram()
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const consoleSpy = captureConsole()

await program.parseAsync([
'node',
Expand Down
Loading
Loading