l2beat / earl

☕ Ergonomic, modern and type-safe assertion library for TypeScript
https://earl.fun/
MIT License
257 stars 19 forks source link

Possible performance improvement: Generate messages only if assertions fail #295

Open dhardtke opened 1 year ago

dhardtke commented 1 year ago

Since serializing large objects can sometimes take some time it would be neat if Earl would generate messages lazily, i.e., only if an assertion fails.

For example, instead of:

https://github.com/l2beat/earl/blob/ea923158550558c46336f0a1038ad522ec62cc43/packages/earl/src/validators/basic/toBeTruthy.ts#L38C1-L45C2

let's do something like this:

export function toBeTruthy(control: Control) {
  control.assert({
    success: truthy()(control.actual),
    reason: () => `The value ${formatCompact(control.actual)} is not truthy, but it was expected to be truthy.`,
    negatedReason: () => `The value ${formatCompact(control.actual)} is truthy, but it was expected not to be truthy.`,
  })
}

I do not have benchmarks to back this claim up but I don't see why it wouldn't lead to a substantial performance gain.

canab commented 1 year ago

I have tested earl on some large project. It results in 15...20% slower run (comparing with should.js)

Quick testing the @dhardtke idea shows at least 50% better execution time on expect(object).toEqual(...)

CPU snapshot shows that most time is consumed by formatCompact and preapreStackTrace. As I understand, the execution of those functions is only required if test fails. Avoiding them should result in significant performance boost.

canab commented 1 year ago

I've created a pull request https://github.com/l2beat/earl/pull/296 Only toEqual function has been modified and synthetic test run time is reduced from 800ms to 15ms