Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
66 changes: 66 additions & 0 deletions packages/db/tests/expected-failure.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { describe, expect, it } from 'vitest'
import { expectAssertionFailure } from './expected-failure.js'
import { TraceAssertionError } from './trace-runner.js'

describe(`expected failure guard`, () => {
it(`accepts an assertion mismatch at the expected checkpoint`, async () => {
const guarded = expectAssertionFailure(
() => {
try {
expect(`observed`).toBe(`expected`)
return Promise.resolve()
} catch (error) {
return Promise.reject(new TraceAssertionError(2, error))
}
},
{ checkpoint: 2 },
)

await guarded()
})

it(`rejects an assertion mismatch from the wrong checkpoint`, async () => {
const guarded = expectAssertionFailure(
() =>
Promise.reject(
new TraceAssertionError(0, new Error(`startup mismatch`)),
),
{ checkpoint: 2 },
)

await expect(guarded()).rejects.toBeInstanceOf(Error)
})

it(`rejects a runtime error from the expected checkpoint`, async () => {
const guarded = expectAssertionFailure(
() =>
Promise.reject(
new TraceAssertionError(2, new TypeError(`projection failed`)),
),
{ checkpoint: 2 },
)

await expect(guarded()).rejects.toBeInstanceOf(Error)
})

it(`accepts an assertion mismatch with the expected message`, async () => {
const guarded = expectAssertionFailure(
() =>
Promise.resolve().then(() => {
expect([`actual`]).toEqual([`expected`])
}),
{ message: /expected/ },
)

await guarded()
})

it(`rejects runtime errors that happen to have the expected message`, async () => {
const runtimeError = new TypeError(`expected value is missing`)
const guarded = expectAssertionFailure(() => Promise.reject(runtimeError), {
message: /expected/,
})

await expect(guarded()).rejects.toBeInstanceOf(Error)
})
})
Comment on lines +58 to +66

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a case where the guarded assertion resolves.

The guard exists to lock in known failures. If the underlying defect is fixed, the guarded assertion resolves and the guard must fail. That path is not covered for either the checkpoint branch or the message branch.

Based on learnings, test corner cases including resolved promises.

💚 Proposed additional tests
   it(`rejects runtime errors that happen to have the expected message`, async () => {
     const runtimeError = new TypeError(`expected value is missing`)
     const guarded = expectAssertionFailure(() => Promise.reject(runtimeError), {
       message: /expected/,
     })
 
     await expect(guarded()).rejects.toBeInstanceOf(Error)
   })
+
+  it(`rejects an assertion that unexpectedly passes`, async () => {
+    const guardedCheckpoint = expectAssertionFailure(
+      () => Promise.resolve(),
+      { checkpoint: 2 },
+    )
+    const guardedMessage = expectAssertionFailure(() => Promise.resolve(), {
+      message: /expected/,
+    })
+
+    await expect(guardedCheckpoint()).rejects.toBeInstanceOf(Error)
+    await expect(guardedMessage()).rejects.toBeInstanceOf(Error)
+  })
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it(`rejects runtime errors that happen to have the expected message`, async () => {
const runtimeError = new TypeError(`expected value is missing`)
const guarded = expectAssertionFailure(() => Promise.reject(runtimeError), {
message: /expected/,
})
await expect(guarded()).rejects.toBeInstanceOf(Error)
})
})
it(`rejects runtime errors that happen to have the expected message`, async () => {
const runtimeError = new TypeError(`expected value is missing`)
const guarded = expectAssertionFailure(() => Promise.reject(runtimeError), {
message: /expected/,
})
await expect(guarded()).rejects.toBeInstanceOf(Error)
})
it(`rejects an assertion that unexpectedly passes`, async () => {
const guardedCheckpoint = expectAssertionFailure(
() => Promise.resolve(),
{ checkpoint: 2 },
)
const guardedMessage = expectAssertionFailure(() => Promise.resolve(), {
message: /expected/,
})
await expect(guardedCheckpoint()).rejects.toBeInstanceOf(Error)
await expect(guardedMessage()).rejects.toBeInstanceOf(Error)
})
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/tests/expected-failure.test.ts` around lines 58 - 66, Extend the
expected-failure tests around expectAssertionFailure to cover guarded assertions
whose underlying promise resolves, including both the checkpoint and message
option branches. Assert that the guard itself rejects when the wrapped assertion
resolves, while preserving the existing runtime-error message collision case.

Source: Learnings

29 changes: 29 additions & 0 deletions packages/db/tests/expected-failure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { expect } from 'vitest'

type ExpectedAssertionFailure =
| { checkpoint: number }
| { message: string | RegExp }

export function expectAssertionFailure<TArgs extends Array<unknown>>(
assertion: (...args: TArgs) => Promise<void>,
expected: ExpectedAssertionFailure,
): (...args: TArgs) => Promise<void> {
return async (...args) => {
if (`checkpoint` in expected) {
await expect(assertion(...args)).rejects.toMatchObject({
name: `TraceAssertionError`,
checkpoint: expected.checkpoint,
cause: { name: `AssertionError` },
})
return
}

await expect(assertion(...args)).rejects.toMatchObject({
name: `AssertionError`,
message:
typeof expected.message === `string`
? expected.message
: expect.stringMatching(expected.message),
})
}
}
Loading
Loading