Claude-skill-registry effect-ts-testing

Testing guidelines and patterns for Effect-based code.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/effect-ts-testing" ~/.claude/skills/majiayu000-claude-skill-registry-effect-ts-testing && rm -rf "$T"
manifest: skills/data/effect-ts-testing/SKILL.md
source content

Effect-TS Testing Skill

Use this skill when writing or reviewing tests for Effect-based code.

Effect testing rules (for
*.spec.*
files)

When testing a method that returns an

Effect
type, use the
@effect/vitest
package.

  • Use
    import { it } from '@effect/vitest'
    as opposed to importing
    it
    from regular vitest.
  • Usage:
    it.effect('test name', () => {
       return Effect.gen(...)
    })
    
  • Use
    it.layer()
    to provide test dependencies when your Effect requires specific services:
    it.layer(Layer.fresh(IncrementalIdGenerator))((it) => {
      it.effect('test name', () => {
        return Effect.gen(...)
      })
    })
    

Testing for type-safety

Use

tsafe
package for compile-time type assertions to validate type safety in tests.

  • Import:
    import { assert } from 'tsafe'
    and
    import type { Equals } from 'tsafe'
  • Usage:
    assert<Equals<ActualType, ExpectedType>>()
    - validates exact type equality at compile time

Test time helpers

Never use

new Date()
in tests. Always use
yield* DateTime.now
and convert to
Date
if needed.

import { DateTime, Effect } from 'effect';

const nowDateTime = yield* DateTime.now;
const now = DateTime.toDateUtc(nowDateTime);

Schema decoding with decodeUnknown

When decoding unknown values using Effect schemas, always use the

decodeUnknown
function exported from
zerospin
instead of
Schema.decodeUnknown
directly.

  • Import:
    import { decodeUnknown } from 'zerospin'
  • Always specify
    onExcessProperty
    :
    'error'
    ,
    'ignore'
    , or
    'preserve'
    based on your needs
  • Map errors to
    ZerospinError
    with code
    'failed-to-decode-unknown'

In Effect.gen contexts:

import { decodeUnknown } from 'zerospin';
import { ZerospinError } from '@zerospin/error';
import { Effect } from 'effect';

const decoded = yield* decodeUnknown({
  onExcessProperty: 'error', // or 'ignore' or 'preserve'
  schema: MySchema,
  value: unknownValue,
}).pipe(
  Effect.mapError((error) => {
    return new ZerospinError({
      code: 'failed-to-decode-unknown',
      message: error.message,
      cause: error,
    });
  })
);

In async/await contexts:

import { decodeUnknown } from 'zerospin';
import { ZerospinError } from '@zerospin/error';
import { Effect } from 'effect';

const decoded = await Effect.runPromise(
  decodeUnknown({
    onExcessProperty: 'error',
    schema: MySchema,
    value: unknownValue,
  }).pipe(
    Effect.mapError((error) => {
      return new ZerospinError({
        code: 'failed-to-decode-unknown',
        message: error.message,
        cause: error,
      });
    })
  )
);