Files
wehub-resource-sync 0d3cb498a3
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Waiting to run
Test and Publish Multi-arch Docker Image / test (push) Waiting to run
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Blocked by required conditions
Validate Renovate Config / Validate Renovate Configuration (push) Waiting to run
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:08 +08:00

241 lines
6.7 KiB
TypeScript

import chalk from 'chalk';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { TERMINAL_MAX_WIDTH } from '../src/constants';
import { generateTable, wrapTable } from '../src/table';
import { type EvaluateTable, ResultFailureReason } from '../src/types/index';
import {
createCompletedPrompt,
createEvaluateTable,
createEvaluateTableOutput,
createEvaluateTableRow,
} from './factories/eval';
// Track all created instances and constructor calls
const mockTableInstances: any[] = [];
const mockConstructorCalls: any[] = [];
// Create a hoisted mock class for Table - must be an actual class to work with `new`
const MockTable = vi.hoisted(() => {
return class MockTable {
push: ReturnType<typeof vi.fn>;
toString: ReturnType<typeof vi.fn>;
options: object;
width: number;
length: number;
pop: ReturnType<typeof vi.fn>;
constructor(options: any) {
mockConstructorCalls.push(options);
this.push = vi.fn();
this.toString = vi.fn().mockReturnValue('mocked table string');
this.options = options || {};
this.width = 0;
this.length = 0;
this.pop = vi.fn();
mockTableInstances.push(this);
}
};
});
vi.mock('cli-table3', () => ({
default: MockTable,
}));
describe('table', () => {
beforeEach(() => {
vi.resetAllMocks();
mockTableInstances.length = 0;
mockConstructorCalls.length = 0;
});
describe('generateTable', () => {
const mockEvaluateTable: EvaluateTable = createEvaluateTable({
head: {
vars: ['var1', 'var2'],
prompts: [
createCompletedPrompt('test prompt', {
provider: 'test-provider',
label: 'test-label',
id: 'test-id',
display: 'test display',
config: {},
metrics: undefined,
}),
],
},
body: [
createEvaluateTableRow({
vars: ['value1', 'value2'],
outputs: [createEvaluateTableOutput({ text: 'passing test' })],
testIdx: 0,
}),
createEvaluateTableRow({
vars: ['value3', 'value4'],
outputs: [
createEvaluateTableOutput({
pass: false,
score: 0,
text: 'failing test',
failureReason: ResultFailureReason.ASSERT,
}),
],
testIdx: 1,
}),
],
});
it('should generate table with correct headers', () => {
generateTable(mockEvaluateTable);
expect(mockConstructorCalls[0]).toEqual({
head: ['var1', 'var2', '[test-provider] test-label'],
colWidths: expect.any(Array),
wordWrap: true,
wrapOnWordBoundary: true,
style: { head: ['blue', 'bold'] },
});
});
it('should handle passing and failing rows correctly', () => {
generateTable(mockEvaluateTable);
const table = mockTableInstances[0];
expect(table.push).toHaveBeenCalledWith([
'value1',
'value2',
chalk.green('[PASS] ') + 'passing test',
]);
expect(table.push).toHaveBeenCalledWith([
'value3',
'value4',
chalk.red('[FAIL] ') + chalk.red.bold('failing test'),
]);
});
it('should respect maxRows parameter', () => {
generateTable(mockEvaluateTable, 250, 1);
const table = mockTableInstances[0];
expect(table.push).toHaveBeenCalledTimes(1);
});
it('should respect tableCellMaxLength parameter', () => {
const longText = 'a'.repeat(300);
const shortMaxLength = 10;
const testTable: EvaluateTable = createEvaluateTable({
head: { vars: [longText], prompts: [] },
body: [
createEvaluateTableRow({
vars: [longText],
outputs: [createEvaluateTableOutput({ text: 'test' })],
}),
],
});
generateTable(testTable, shortMaxLength);
expect(mockConstructorCalls[0]).toEqual(
expect.objectContaining({
head: [expect.stringMatching(/^a{7}\.{3}$/)],
}),
);
});
});
describe('wrapTable', () => {
it('should return message when no rows provided', () => {
const result = wrapTable([]);
expect(result).toBe('No data to display');
});
it('should create table with correct headers and data', () => {
const rows = [
{ col1: 'value1', col2: 'value2' },
{ col1: 'value3', col2: 'value4' },
];
wrapTable(rows);
expect(mockConstructorCalls[0]).toEqual({
head: ['col1', 'col2'],
colWidths: expect.any(Array),
wordWrap: true,
wrapOnWordBoundary: true,
});
const table = mockTableInstances[0];
expect(table.push).toHaveBeenCalledWith(['value1', 'value2']);
expect(table.push).toHaveBeenCalledWith(['value3', 'value4']);
});
it('should create table with custom column widths', () => {
const rows = [
{ col1: 'value1', col2: 'value2', col3: 'value3' },
{ col1: 'value4', col2: 'value5', col3: 'value6' },
];
const columnWidths = {
col1: 10,
col2: 20,
col3: 15,
};
wrapTable(rows, columnWidths);
expect(mockConstructorCalls[0]).toEqual({
head: ['col1', 'col2', 'col3'],
colWidths: [10, 20, 15],
wordWrap: true,
wrapOnWordBoundary: true,
});
const table = mockTableInstances[0];
expect(table.push).toHaveBeenCalledWith(['value1', 'value2', 'value3']);
expect(table.push).toHaveBeenCalledWith(['value4', 'value5', 'value6']);
});
it('should use default width for columns not specified in columnWidths', () => {
const rows = [{ col1: 'value1', col2: 'value2', col3: 'value3' }];
const columnWidths = {
col1: 10,
// col2 not specified
col3: 15,
};
wrapTable(rows, columnWidths);
const defaultWidth = Math.floor(TERMINAL_MAX_WIDTH / 3); // 3 columns
expect(mockConstructorCalls[0]).toEqual({
head: ['col1', 'col2', 'col3'],
colWidths: [10, defaultWidth, 15],
wordWrap: true,
wrapOnWordBoundary: true,
});
});
it('should return a string representation of the table', () => {
const rows = [
{ col1: 'value1', col2: 'value2' },
{ col1: 'value3', col2: 'value4' },
];
const result = wrapTable(rows);
expect(typeof result).toBe('string');
expect(result).toBe('mocked table string');
const table = mockTableInstances[0];
expect(table.toString).toHaveBeenCalled();
});
it('should return string for single row', () => {
const rows = [{ name: 'John', age: 30 }];
const result = wrapTable(rows);
expect(typeof result).toBe('string');
expect(result).toBe('mocked table string');
});
});
});