effect-ts-laws
    Preparing search index...

    effect-ts-laws

    ⚖ effect-ts-laws

    Law Testing for effect-ts Code

    A library for law testing. Test @effect/typeclass and schema laws using fast-check. The typeclass laws implemented are listed here.

    Read on for the project introduction or jump to:

    1. User guide
    2. API docs.

    1. About
      1. Synopsis
        1. Testing Typeclass Laws on Option<A>
        2. Testing Typeclass Laws on a New Datatype
      2. Overview
    2. Project
      1. Play
      2. Status
      3. More Information
      4. Roadmap
    3. See Also
      1. Based On
    Example 1: testing the `Option` datatype. 👈 click

    testTypeClassLaws will find the correct typeclass laws and test them. To define the tests required for the Option datatype, for example, we need to:

    1. Provide a function to build an Equivalence<Option<A>> from an Equivalence<A>.
      • Thankfully, effect-ts has such a function in the Option module called getEquivalence.
    2. Provide the same for arbitraries.
      • effect-ts-laws exports an option function. It takes an Arbitrary<A> and return an Arbitrary<Option<A>>.
    3. List all instances for the datatype by their typeclass name.
      • Note in the code below some instances, for example Order, are built from the instance of the underlying type. The effect-ts-laws export monoOrder provides this for the Order typeclass.

    The Option typeclass law test:

    import {
    Alternative,
    Applicative,
    Foldable,
    getOptionalMonoid,
    Monad,
    Traversable
    } from '@effect/typeclass/data/Option'
    import {Option as OP} from 'effect'
    import {monoEquivalence, monoOrder, monoSemigroup, option} from 'effect-ts-laws'
    import {testTypeclassLaws} from 'effect-ts-laws/vitest'
    import {OptionTypeLambda} from 'effect/Option'

    describe('@effect/typeclass/data/Option', () => {
    testTypeclassLaws<OptionTypeLambda>({
    getEquivalence: OP.getEquivalence,
    getArbitrary: option,
    })({
    Alternative,
    Applicative,
    Equivalence: OP.getEquivalence(monoEquivalence),
    Foldable,
    Monad,
    Monoid: getOptionalMonoid(monoSemigroup),
    Order: OP.getOrder(monoOrder),
    Traversable,
    })
    })

    What do we get in return to our investment in the three steps above and in the added maintenance costs of this tiny, easy to maintain test?

    Good coverage for a freight train full of fault models. Vitest reporter showing test results for the seventy one typeclass laws relevant to the effect-ts Option datatype as defined in the test above:

    synopsis output


    Example 2: Testing a custom unary tuple. 👈 click

    You wrote a new datatype: MyTuple, and an instance of the effect-ts Covariant typeclass. Lets test it for free:

    import {Covariant as CO} from '@effect/typeclass'
    import {Array as AR} from 'effect'
    import {dual} from 'effect/Function'
    import {TypeLambda} from 'effect/HKT'
    import fc from 'fast-check'
    import {testTypeclassLaws} from 'effect-ts-laws/vitest'

    describe('MyTuple', () => {
    type MyTuple<A> = [A]

    interface MyTupleTypeLambda extends TypeLambda {
    readonly type: MyTuple<this['Target']>
    }

    const map: CO.Covariant<MyTupleTypeLambda>['map'] = dual(
    2,
    <A, B>([a]: MyTuple<A>, ab: (a: A) => B): MyTuple<B> => [ab(a)],
    )
    const Covariant: CO.Covariant<MyTupleTypeLambda> = {
    imap: CO.imap<MyTupleTypeLambda>(map),
    map,
    }

    testTypeclassLaws<MyTupleTypeLambda>({
    getEquivalence: AR.getEquivalence,
    getArbitrary: fc.tuple,
    })({Covariant})
    })

    fast-check will try to find a counterexample that breaks the laws. Because it is quite impossible to find one in this case you should see:

    synopsis output

    Above you see that eight typeclass laws that were tested:

    1. Covariant identity and composition laws. count = 2
      1. Because Covariant extends Invariant, the typeclass laws of identity and composition of this typeclass are tested. count = 2 + 2
        1. effect-ts lets you compose a pair of Invariants into a new Invariant. There are fault models that will only be covered if we test such composed instances. To cover these fault models, the instance under test is composed with the Option Invariant instance and run through the identity and composition laws. count = 2 + 2 + 2
      2. effect-ts lets you compose Covariants as well. The instance under test is composed with the Option Covariant instance and run through the identity and composition laws. count = 2 + 2 + 2 + 2

    Law testing is property testing, except the properties are well known laws. Besides being famous, the laws included here were chosen because they catch bugs efficiently . If you can identify the laws that should govern your code, then effect-ts-laws will help you test them.

    For example when implementing instances of effect-ts typeclasses for your datatype, they must be bound by their typeclass laws. effect-ts-laws exports ready-made tests for these, and with very little work they can be added to your test suite to reduce the risk your customizations are unlawful.

    Features:

    • Laws
    • Law testing infrastructure
    • Randomness. Uses fast-check property testing. For parameterized type typeclass laws, all functions are randomly generated as well.
    • Minimal work to test instances for your own datatype: it can all be done with single function that takes the instances under test and a pair of functions: getEquivalence and getArbitrary.
      • Meaningful test coverage improvement for the price of writing two functions. You probably have them somewhere already.

    You can run the project tests online at any of these online sandboxes by opening a terminal and calling pnpm install && pnpm test-run. pnpm coverage will give you the always 100% coverage report.

    1. StackBlitz. Note coverage does not work on StackBlitz.
    2. replit requires you fork the repository first by clicking the green Fork button.
    3. CodeSandbox.

    The full self-test suite will run in less than 10 seconds on an average desktop, but will take a minute or two to run on the free tiers of the services above.

    This matrix shows data-types (in columns) vs. typeclass law tests (in rows). Each intersection of datatype and typeclass can be either: ready (✅), not ready (❌), or not relevant (☐).

    Click a datatype (in column header) to open its source code in the effect-ts project. Click a typeclass name (in row header) to open its laws as defined in effect-ts-laws.

    • Laws
      • [ ] Sink Contravariant laws.
      • [ ] More datatypes.
      • [ ] Relational laws.
      • [ ] Functional laws.
    • Harness
      • [ ] Pretty print counterexamples. Allow using exception throwing test code+ validation code returning Either instead of boolean for Law.predicate.
      • [ ] API should let you use any catalog.
    • Composition
      • [ ] Test composition flipped.
      • [ ] Nest three levels.
      • [ ] Brand composition: refine(b₂) ∘ refine(b₁) = refine.all(b₁, b₂).
    • Arbitraries
      • [ ] oneof arbitrary chosen from built-in instances.
      • [ ] Schema arbitrary.
    1. fast-check
    2. effect-ts
    3. zio-prelude laws
    4. On the importance of typeclass laws
    1. fp-ts-laws by Giulio Canti
    2. Scala's Discipline
    3. All errors, bugs and misunderstandings are 100% original work.