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

80 lines
3.2 KiB
JavaScript

/**
* WARNING: The `counter` variable is NOT thread-safe. When running with concurrency > 1,
* the counter may not accurately track test numbers. Consider using per-test metadata
* for accurate tracking in concurrent scenarios.
*/
let counter = 0;
/**
* Handles different extension hooks for promptfoo.
*
* IMPORTANT: The function signature is (hookName, context) where:
* - hookName: 'beforeAll' | 'beforeEach' | 'afterEach' | 'afterAll'
* - context: The hook-specific data (e.g., { suite } for beforeAll)
*
* @param {string} hookName - The name of the hook being called.
* @param {Object} context - A dictionary containing contextual information for the hook.
* The contents vary depending on the hook being called:
* - beforeAll: { suite: TestSuite }
* - beforeEach: { test: TestCase }
* - afterEach: { test: TestCase, result: EvaluateResult }
* - afterAll: { results: EvaluateResult[], suite: TestSuite, ... }
* @returns {Object|undefined} The "beforeAll" and "beforeEach" hooks should return the context object,
* while the "afterAll" and "afterEach" hooks should not return anything.
*/
async function extensionHook(hookName, context) {
if (hookName === 'beforeAll') {
console.log(`Setting up test suite: ${context.suite.description || 'Unnamed suite'}`);
console.log(`Total prompts: ${context.suite.prompts?.length || 0}`);
console.log(`Total providers: ${context.suite.providers?.length || 0}`);
console.log(`Total tests: ${context.suite.tests?.length || 0}`);
// Add an additional test case to the suite:
context.suite.tests.push({
vars: {
body: "It's a beautiful day",
language: 'Spanish',
},
assert: [{ type: 'contains', value: 'Es un día hermoso.' }],
});
// Add an additional default assertion to the suite:
context.suite.defaultTest.assert.push({ type: 'is-json' });
return context;
} else if (hookName === 'beforeEach') {
console.log(`Preparing test`);
// All languages are now pirate:
context.test.vars.language = `Pirate ${context.test.vars.language}`;
return context;
} else if (hookName === 'afterEach') {
console.log(
`Completed test ${counter++}${context.result ? `, Result: ${context.result.success ? 'Pass' : 'Fail'}, Score: ${context.result.score}` : ''}`,
);
// Access sessionId if available (from multi-turn conversations or stateful tests)
if (context.result?.metadata?.sessionId) {
console.log(`Session ID: ${context.result.metadata.sessionId}`);
}
if (context.result?.metadata?.sessionIds) {
console.log(`Session IDs: ${context.result.metadata.sessionIds}`);
}
} else if (hookName === 'afterAll') {
console.log('Test suite completed');
console.log(`Total tests run: ${context.results?.length || 0}`);
const successes = context.results?.filter((r) => r.success).length || 0;
const failures = context.results?.filter((r) => !r.success).length || 0;
console.log(`Successes: ${successes}`);
console.log(`Failures: ${failures}`);
const totalTokenUsage =
context.results?.reduce((sum, r) => sum + (r.response?.tokenUsage?.total || 0), 0) || 0;
console.log(`Total token usage: ${totalTokenUsage}`);
}
}
module.exports = extensionHook;