Skip to content

Commit

Permalink
Type safe scrub errors
Browse files Browse the repository at this point in the history
Signed-off-by: Thomas Farr <[email protected]>
  • Loading branch information
Xtansia committed Jun 5, 2024
1 parent f98afb7 commit 7695759
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 24 deletions.
2 changes: 1 addition & 1 deletion tools/src/tester/ResultLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class ConsoleResultLogger implements ResultLogger {
const result = ansi.padding(this.#result(evaluation.result), 0, prefix)
const message = evaluation.message != null ? `${ansi.gray('(' + evaluation.message + ')')}` : ''
console.log(`${result} ${title} ${message}`)
if (evaluation.error && this._verbose) {
if (evaluation.error != null && this._verbose) {
console.log('-'.repeat(100))
console.error(evaluation.error)
console.log('-'.repeat(100))
Expand Down
2 changes: 1 addition & 1 deletion tools/src/tester/types/eval.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export interface ChapterEvaluation {
export interface Evaluation {
result: Result
message?: string
error?: Error
error?: Error | string
}

export enum Result {
Expand Down
13 changes: 7 additions & 6 deletions tools/tests/tester/TestRunner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,21 @@
* compatible open source license.
*/

import { construct_tester_components, load_expected_evaluation, scrub_errors } from './helpers'
import { construct_tester_components, flatten_errors, load_expected_evaluation } from './helpers'
import { type StoryEvaluation } from '../../src/tester/types/eval.types'

test('stories folder', async () => {
const { test_runner } = construct_tester_components('tools/tests/tester/fixtures/specs/indices_excerpt.yaml')
const result = await test_runner.run('tools/tests/tester/fixtures/stories')

expect(result.failed).toBeTruthy()

const actual_evaluations: any[] = result.evaluations
const actual_evaluations: Array<Omit<StoryEvaluation, 'full_path'>> = []

for (const evaluation of actual_evaluations) {
expect(evaluation.full_path.endsWith(evaluation.display_path)).toBeTruthy()
scrub_errors(evaluation)
delete evaluation.full_path
for (const evaluation of result.evaluations) {
const { full_path, ...rest } = flatten_errors(evaluation)
expect(full_path.endsWith(rest.display_path)).toBeTruthy()
actual_evaluations.push(rest)
}

const skipped = load_expected_evaluation('skipped', true)
Expand Down
60 changes: 44 additions & 16 deletions tools/tests/tester/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
*/

import YAML from 'yaml'
import type { StoryEvaluation } from '../../src/tester/types/eval.types'
import type { Story } from '../../src/tester/types/story.types'
import type { ChapterEvaluation, Evaluation, StoryEvaluation } from '../../src/tester/types/eval.types'
import { read_yaml } from '../../helpers'
import StoryEvaluator from '../../src/tester/StoryEvaluator'
import SpecParser from '../../src/tester/SpecParser'
Expand Down Expand Up @@ -63,25 +62,54 @@ export function print_yaml (obj: any): void {
console.log(YAML.stringify(obj, { indent: 2, singleQuote: true, lineWidth: undefined }))
}

export function scrub_errors (obj: any): void {
for (const key in obj) {
if (typeof obj[key] !== 'object') continue
if (key === 'error') obj.error = obj.error.message
else scrub_errors(obj[key])
export function flatten_errors (evaluation: StoryEvaluation): StoryEvaluation {
const flatten = <T extends Evaluation | undefined>(e: T): T => (e !== undefined
? {
...e,
error: typeof e.error === 'object' ? e.error.message : e.error
}
: undefined as T)

const flatten_chapters = <T extends ChapterEvaluation[] | undefined> (chapters: T): T => {
if (chapters === undefined) return undefined as T
return chapters.map((c: ChapterEvaluation): ChapterEvaluation => ({
...c,
overall: flatten(c.overall),
request: c.request !== undefined
? {
parameters: c.request.parameters !== undefined
? Object.fromEntries(Object.entries(c.request.parameters).map(([k, v]) => [k, flatten(v)]))
: undefined,
request_body: flatten(c.request.request_body)
}
: undefined,
response: c.response !== undefined
? {
status: flatten(c.response.status),
payload: flatten(c.response.payload)
}
: undefined
})) as T
}

return {
...evaluation,
chapters: flatten_chapters(evaluation.chapters),
epilogues: flatten_chapters(evaluation.epilogues),
prologues: flatten_chapters(evaluation.prologues)
}
}

export function load_expected_evaluation (name: string, exclude_full_path: boolean = false): Record<string, any> {
const expected = read_yaml(`tools/tests/tester/fixtures/evals/${name}.yaml`)
if (exclude_full_path) delete expected.full_path
return expected
export function load_expected_evaluation (name: string, exclude_full_path: boolean = false): Omit<StoryEvaluation, 'full_path'> & { full_path?: string } {
const { full_path, ...rest }: StoryEvaluation = read_yaml(`tools/tests/tester/fixtures/evals/${name}.yaml`)
return !exclude_full_path ? { ...rest, full_path } : rest
}

export async function load_actual_evaluation (evaluator: StoryEvaluator, name: string): Promise<StoryEvaluation> {
const story: Story = read_yaml(`tools/tests/tester/fixtures/stories/${name}.yaml`)
const display_path = `${name}.yaml`
const full_path = `tools/tests/tester/fixtures/stories/${name}.yaml`
const actual = await evaluator.evaluate({ display_path, full_path, story })
scrub_errors(actual)
return actual
return flatten_errors(await evaluator.evaluate({
full_path,
display_path: `${name}.yaml`,
story: read_yaml(full_path)
}))
}

0 comments on commit 7695759

Please sign in to comment.