diff --git a/__tests__/commands/cli.test.ts b/__tests__/commands/cli.test.ts new file mode 100644 index 0000000..5817a20 --- /dev/null +++ b/__tests__/commands/cli.test.ts @@ -0,0 +1,20 @@ +import { execFile } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; +import { promisify } from 'node:util'; + +const run = promisify(execFile); +const projectRoot = fileURLToPath(new URL('../../', import.meta.url)); + +describe('when opting out of telemetry from the CLI', () => { + it.each([ + ['help', '--no-telemetry'], + ['--no-telemetry', 'help'], + ])('accepts %j %j without an argument error', async (...args) => { + const sut = await run(process.execPath, ['--import', 'tsx', 'bin/cli.ts', ...args], { + cwd: projectRoot, + }); + + expect(sut.stdout).toContain('Usage:'); + expect(sut.stderr).not.toContain('Unknown argument'); + }); +}); diff --git a/__tests__/commands/default.test.ts b/__tests__/commands/default.test.ts new file mode 100644 index 0000000..2e095ec --- /dev/null +++ b/__tests__/commands/default.test.ts @@ -0,0 +1,45 @@ +import { defaultCommand } from '@commands/default.js'; +import { isTelemetryEnabled, resetTelemetry } from '@lib/telemetry.js'; + +// Keep the real command and telemetry initialization, without opening a terminal UI. +vi.mock('ink', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + render: () => ({ waitUntilExit: () => Promise.resolve() }), + }; +}); + +afterEach(() => { + vi.unstubAllEnvs(); + resetTelemetry(); +}); + +describe('when starting the wizard', () => { + it('honors the telemetry opt-out even when enabled by the environment', async () => { + vi.stubEnv('CONFIDENCE_TELEMETRY', 'true'); + const sut = defaultCommand; + + await sut.handler({ telemetry: false } as never); + + expect(isTelemetryEnabled()).toBe(false); + }); + + it('preserves the environment opt-out with the default CLI value', async () => { + vi.stubEnv('CONFIDENCE_TELEMETRY', 'false'); + const sut = defaultCommand; + + await sut.handler({ telemetry: true } as never); + + expect(isTelemetryEnabled()).toBe(false); + }); + + it('preserves enabled telemetry when no opt-out is requested', async () => { + vi.stubEnv('CONFIDENCE_TELEMETRY', 'true'); + const sut = defaultCommand; + + await sut.handler({ telemetry: true } as never); + + expect(isTelemetryEnabled()).toBe(true); + }); +}); diff --git a/bin/cli.ts b/bin/cli.ts index 90e38b6..b7de217 100644 --- a/bin/cli.ts +++ b/bin/cli.ts @@ -23,10 +23,10 @@ const cli = yargs(hideBin(process.argv)) describe: 'Project directory to run the wizard in', normalize: true, }) - .option('no-telemetry', { + .option('telemetry', { type: 'boolean', - default: false, - describe: 'Disable anonymous usage telemetry', + default: true, + describe: 'Collect anonymous usage telemetry (disable with --no-telemetry)', }) .command(defaultCommand.name, defaultCommand.description, () => {}, defaultCommand.handler) .command('start', defaultCommand.description, () => {}, defaultCommand.handler) diff --git a/src/commands/default.ts b/src/commands/default.ts index 4c3db6a..7bbe01f 100644 --- a/src/commands/default.ts +++ b/src/commands/default.ts @@ -9,7 +9,7 @@ export const defaultCommand: Command = { const dryRun = Boolean(args['dry-run'] ?? args.dryRun); const debug = Boolean(args.debug); const dir = args.dir as string | undefined; - const noTelemetry = Boolean(args['no-telemetry'] ?? args.noTelemetry); + const noTelemetry = args.telemetry === false; if (noTelemetry) { process.env.CONFIDENCE_TELEMETRY = 'false';