Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
e9fde3f
test: add unit tests for maskToken utility
NianJiuZst May 16, 2026
f7c1705
test: add unit tests for CLIError and SDKError classes
NianJiuZst May 16, 2026
4da3880
test: add unit tests for isInteractive and isCI environment detection
NianJiuZst May 16, 2026
db04922
test: add unit tests for parseConfigFile configuration parsing
NianJiuZst May 16, 2026
cd72a81
test: add unit tests for polling logic (complete, failed, timeout)
NianJiuZst May 16, 2026
a72949c
test: add validateParams tests for SpeechSDK
NianJiuZst May 16, 2026
95182e9
test: add validateParams tests for ImageSDK (width/height constraints)
NianJiuZst May 16, 2026
4e7a475
test: add validateParams tests for VideoSDK (model selection, mode co…
NianJiuZst May 16, 2026
505f0dd
test: add validateParams tests for MusicSDK (mutual exclusion, format…
NianJiuZst May 16, 2026
f575655
test: add validateParams tests for TextSDK
NianJiuZst May 16, 2026
357347a
test: add validation tests for image generate command (width/height, …
NianJiuZst May 16, 2026
b753265
test: add validation tests for file upload command (file existence, d…
NianJiuZst May 16, 2026
6ed7c6b
test: add mock server tests for search query command
NianJiuZst May 16, 2026
60ce237
test: improve quota show command tests
NianJiuZst May 16, 2026
8860500
fix: catch unhandled rejections in SDK and poll tests
NianJiuZst May 16, 2026
9490496
fix: add missing createProgressBar to poll test mock
NianJiuZst May 16, 2026
f8c8f33
fix: use beforeEach to clean CI env and properly restore TTY mocks
NianJiuZst May 16, 2026
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
75 changes: 49 additions & 26 deletions test/commands/file/upload.test.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,61 @@
import { describe, it, expect } from 'bun:test';
import { default as uploadCommand } from '../../../src/commands/file/upload';

const baseConfig = {
apiKey: 'test-key',
region: 'global' as const,
baseUrl: 'https://api.mmx.io',
output: 'text' as const,
timeout: 10,
verbose: false,
quiet: false,
noColor: true,
yes: false,
dryRun: false,
nonInteractive: true,
async: false,
};

const baseFlags = {
quiet: false,
verbose: false,
noColor: true,
yes: false,
dryRun: false,
help: false,
nonInteractive: true,
async: false,
};

describe('file upload command', () => {
it('has correct name', () => {
expect(uploadCommand.name).toBe('file upload');
});

it('requires file argument', async () => {
const config = {
apiKey: 'test-key',
region: 'global' as const,
baseUrl: 'https://api.mmx.io',
output: 'text' as const,
timeout: 10,
verbose: false,
quiet: false,
noColor: true,
yes: false,
dryRun: true,
nonInteractive: true,
async: false,
};

it('requires file argument in non-interactive mode', async () => {
await expect(
uploadCommand.execute(config, {
quiet: false,
verbose: false,
noColor: true,
yes: false,
dryRun: true,
help: false,
nonInteractive: true,
async: false,
}),
uploadCommand.execute(baseConfig, baseFlags),
).rejects.toThrow('Missing required argument: --file');
});

it('throws when file does not exist', async () => {
await expect(
uploadCommand.execute(baseConfig, { ...baseFlags, file: '/tmp/nonexistent-file-xxxxx.bin' }),
).rejects.toThrow('File not found');
});

it('shows dry-run output with file info', async () => {
let captured = '';
const origWrite = process.stdout.write;
process.stdout.write = (chunk: any): any => { captured += String(chunk); return true; };

await uploadCommand.execute(
{ ...baseConfig, dryRun: true },
{ ...baseFlags, dryRun: true, file: '/dev/null', purpose: 'vision' },
);

process.stdout.write = origWrite;
expect(captured).toContain('/dev/null');
expect(captured).toContain('vision');
});
});
106 changes: 81 additions & 25 deletions test/commands/image/generate.test.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,94 @@
import { describe, it, expect } from 'bun:test';
import { default as generateCommand } from '../../../src/commands/image/generate';

const baseConfig = {
apiKey: 'test-key',
region: 'global' as const,
baseUrl: 'https://api.mmx.io',
output: 'text' as const,
timeout: 10,
verbose: false,
quiet: false,
noColor: true,
yes: false,
dryRun: false,
nonInteractive: true,
async: false,
};

const baseFlags = {
quiet: false,
verbose: false,
noColor: true,
yes: false,
dryRun: false,
help: false,
nonInteractive: true,
async: false,
};

describe('image generate command', () => {
it('has correct name', () => {
expect(generateCommand.name).toBe('image generate');
});

it('requires prompt', async () => {
const config = {
apiKey: 'test-key',
region: 'global' as const,
baseUrl: 'https://api.mmx.io',
output: 'text' as const,
timeout: 10,
verbose: false,
quiet: false,
noColor: true,
yes: false,
dryRun: false,
nonInteractive: true,
async: false,
};

await expect(
generateCommand.execute(config, {
quiet: false,
verbose: false,
noColor: true,
yes: false,
dryRun: false,
help: false,
nonInteractive: true,
async: false,
}),
generateCommand.execute(baseConfig, baseFlags),
).rejects.toThrow('Missing required argument: --prompt');
});

it('throws when width is provided without height', async () => {
await expect(
generateCommand.execute(baseConfig, { ...baseFlags, prompt: 'test', width: 1024 }),
).rejects.toThrow('--width requires --height');
});

it('throws when height is provided without width', async () => {
await expect(
generateCommand.execute(baseConfig, { ...baseFlags, prompt: 'test', height: 1024 }),
).rejects.toThrow('--height requires --width');
});

it('throws when width is below 512', async () => {
await expect(
generateCommand.execute(baseConfig, { ...baseFlags, prompt: 'test', width: 256, height: 256 }),
).rejects.toThrow('must be between 512 and 2048');
});

it('throws when height is above 2048', async () => {
await expect(
generateCommand.execute(baseConfig, { ...baseFlags, prompt: 'test', width: 1024, height: 4096 }),
).rejects.toThrow('must be between 512 and 2048');
});

it('throws when dimensions are not multiples of 8', async () => {
await expect(
generateCommand.execute(baseConfig, { ...baseFlags, prompt: 'test', width: 1025, height: 1024 }),
).rejects.toThrow('must be a multiple of 8');
});

it('throws when --out is used with --n > 1', async () => {
await expect(
generateCommand.execute(baseConfig, { ...baseFlags, prompt: 'test', out: '/tmp/img.jpg', n: 3 }),
).rejects.toThrow('--out cannot be used with --n > 1');
});

it('builds correct request body in dry-run', async () => {
let captured = '';
const origLog = console.log;
console.log = (msg: string) => { captured += msg; };
try {
await generateCommand.execute(
{ ...baseConfig, dryRun: true, output: 'json' as const },
{ ...baseFlags, dryRun: true, prompt: 'A cat', aspectRatio: '16:9', n: 2, seed: 42 },
);
} catch { /* dry-run may log or resolve */ }
console.log = origLog;
const parsed = JSON.parse(captured);
expect(parsed.request.prompt).toBe('A cat');
expect(parsed.request.n).toBe(2);
expect(parsed.request.seed).toBe(42);
expect(parsed.request.model).toBe('image-01');
});
});
68 changes: 36 additions & 32 deletions test/commands/quota/show.test.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,50 @@
import { describe, it, expect } from 'bun:test';
import { default as showCommand } from '../../../src/commands/quota/show';

const baseConfig = {
apiKey: 'test-key',
region: 'global' as const,
baseUrl: 'https://api.mmx.io',
output: 'text' as const,
timeout: 10,
verbose: false,
quiet: false,
noColor: true,
yes: false,
dryRun: false,
nonInteractive: true,
async: false,
};

const baseFlags = {
quiet: false,
verbose: false,
noColor: true,
yes: false,
dryRun: false,
help: false,
nonInteractive: true,
async: false,
};

describe('quota show command', () => {
it('has correct name', () => {
expect(showCommand.name).toBe('quota show');
});

it('handles dry run', async () => {
const config = {
apiKey: 'test-key',
region: 'global' as const,
baseUrl: 'https://api.mmx.io',
output: 'text' as const,
timeout: 10,
verbose: false,
quiet: false,
noColor: true,
yes: false,
dryRun: true,
nonInteractive: true,
async: false,
};

const originalLog = console.log;
let output = '';
console.log = (msg: string) => { output += msg; };

let captured = '';
const origLog = console.log;
console.log = (msg: string) => { captured += msg; };
try {
await showCommand.execute(config, {
quiet: false,
verbose: false,
noColor: true,
yes: false,
dryRun: true,
help: false,
nonInteractive: true,
async: false,
});

expect(output).toContain('Would fetch quota');
await showCommand.execute(
{ ...baseConfig, dryRun: true },
{ ...baseFlags, dryRun: true },
);
expect(captured).toContain('Would fetch quota');
} finally {
console.log = originalLog;
console.log = origLog;
}
});

});
Loading
Loading