git.iko.soy/rowtype-yoga/purescript-vitest
on main help sign in
Release v2.0.0: Breaking changes and new features

Breaking changes: - Changed ViTest type from foreign data type to Unit alias - Updated test and describe function signatures to return Unit New features: - Added expectToEqual (===) for deep equality assertions - Added expectToSatisfy for predicate-based assertions - Added ViTest.Expect.Either module with Either-specific test helpers Maintenance: - Updated spago.yaml to new format with workspace-first structure - Bumped package set to registry 61.3.1 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

commit3b2035bfc9510aea1aa1d20a34749f7770ae9239 authorMark <mark.eibes@gmail.com> dateThu 5 Feb 2026, 22:14 (8 months ago) parente7f2614
6 files changed+97−18
spago.yaml+11−13 src/ViTest.purs+6−5 src/ViTest/Expect.js+17 src/ViTest/Expect.purs+14 src/ViTest/Expect/Either.js+1 src/ViTest/Expect/Either.purs+48
spago.yaml+11−13
@@ -1,8 +1,19 @@
1+workspace:
2+ packageSet:
3+ registry: 61.3.1
4+
15package:
26 name: vitest
7+ publish:
8+ version: 2.0.0
9+ license: WTFPL
10+ location:
11+ githubOwner: rowtype-yoga
12+ githubRepo: purescript-vitest
313 dependencies:
414 - aff: ">=7.0.0 <9.0.0"
515 - effect: ">=4.0.0 <5.0.0"
16+ - either: ">=6.1.0 <7.0.0"
617 - exceptions: ">=6.1.0 <7.0.0"
718 - js-promise: ">=1.0.0 <2.0.0"
819 - js-promise-aff: ">=1.0.0 <2.0.0"
@@ -13,16 +24,3 @@ package:
1324 - unsafe-coerce: ">=6.0.0 <7.0.0"
1425 - web-dom: ">=6.0.0 <7.0.0"
1526 - web-html: ">=4.1.0 <5.0.0"
16− publish:
17− version: 1.0.0
18− license: WTFPL
19− location:
20− githubOwner: rowtype-yoga
21− githubRepo: purescript-vitest
22− test:
23− main: Test.Main
24− dependencies: []
25−workspace:
26− packageSet:
27− registry: 61.3.1
28− extraPackages: {}
src/ViTest.purs+6−5
@@ -9,15 +9,16 @@ import Effect.Unsafe (unsafePerformEffect)
99import Promise (Promise)
1010import Promise.Aff as Promise
1111
12−foreign import data ViTest :: Type
12+type ViTest = Unit
1313
14−foreign import testImpl :: EffectFn2 String (Effect (Promise (Unit))) ViTest
15−test :: String -> Aff Unit -> Effect ViTest
14+foreign import testImpl :: EffectFn2 String (Effect (Promise (Unit))) Unit
15+
16+test :: String -> Aff Unit -> Effect Unit
1617test desc = runEffectFn2 testImpl desc <<< Promise.fromAff
1718
18−foreign import describeImpl :: EffectFn2 String (Effect ViTest) ViTest
19+foreign import describeImpl :: EffectFn2 String (Effect Unit) Unit
1920
20−describe :: String -> Effect ViTest -> Effect ViTest
21+describe :: String -> Effect Unit -> Effect Unit
2122describe = runEffectFn2 describeImpl
2223
2324viTest :: Effect ViTest -> ViTest
src/ViTest/Expect.js+17
@@ -2,3 +2,20 @@ import {expect} from "vitest";
22
33export const expectToBeImpl = x => y => () => expect(x).toBe(y)
44
5+export const unsafeStringify = x => {
6+ try {
7+ return JSON.stringify(x, null, 2);
8+ } catch (e) {
9+ return String(x);
10+ }
11+}
12+
13+export const expectToEqualImpl = x => y => () => expect(x).toEqual(y)
14+
15+export const expectToSatisfyImpl = value => predicate => () => {
16+ const result = predicate(value);
17+ if (!result) {
18+ throw new Error(`Expected value to satisfy predicate, but it didn't.\nValue: ${unsafeStringify(value)}`);
19+ }
20+}
21+
src/ViTest/Expect.purs+14
@@ -12,3 +12,17 @@ expectToBe :: forall a. a -> a -> Aff Unit
1212expectToBe a b = liftEffect $ expectToBeImpl a b
1313
1414infixl 1 expectToBe as ====
15+
16+foreign import unsafeStringify :: forall a. a -> String
17+
18+foreign import expectToEqualImpl :: forall a. a -> a -> Effect Unit
19+
20+expectToEqual :: forall a. Eq a => a -> a -> Aff Unit
21+expectToEqual a b = liftEffect $ expectToEqualImpl a b
22+
23+infixl 1 expectToEqual as ===
24+
25+foreign import expectToSatisfyImpl :: forall a. a -> (a -> Boolean) -> Effect Unit
26+
27+expectToSatisfy :: forall a. a -> (a -> Boolean) -> Aff Unit
28+expectToSatisfy value predicate = liftEffect $ expectToSatisfyImpl value predicate
src/ViTest/Expect/Either.jsnew file+1
@@ -0,0 +1 @@
1+export const indexOfImpl = needle => haystack => haystack.indexOf(needle);
src/ViTest/Expect/Either.pursnew file+48
@@ -0,0 +1,48 @@
1+module ViTest.Expect.Either where
2+
3+import Prelude
4+
5+import Data.Either (Either(..), either)
6+import Effect.Aff (Aff)
7+import ViTest.Expect (expectToBe, expectToEqual)
8+
9+-- | Assert that a value is Right with a specific value
10+expectRight :: forall e a. Eq a => Show e => a -> Either e a -> Aff Unit
11+expectRight expected result = case result of
12+ Right actual -> expectToEqual expected actual
13+ Left err -> expectToBe true false -- Always fails, shows error in output
14+
15+-- | Assert that a value is Right (don't care about the value)
16+expectIsRight :: forall e a. Show e => Either e a -> Aff Unit
17+expectIsRight result = case result of
18+ Right _ -> expectToBe true true
19+ Left err -> expectToBe true false
20+
21+-- | Assert that a value is Left with a specific error
22+expectLeft :: forall e a. Eq e => Show a => e -> Either e a -> Aff Unit
23+expectLeft expected result = case result of
24+ Left actual -> expectToEqual expected actual
25+ Right val -> expectToBe true false
26+
27+-- | Assert that a value is Left (don't care about the error)
28+expectIsLeft :: forall e a. Show a => Either e a -> Aff Unit
29+expectIsLeft result = case result of
30+ Left _ -> expectToBe true true
31+ Right val -> expectToBe true false
32+
33+-- | Assert that a Left contains a specific substring in its error
34+expectLeftContains :: forall a. Show a => String -> Either String a -> Aff Unit
35+expectLeftContains needle result = case result of
36+ Left err ->
37+ if contains needle err
38+ then expectToBe true true
39+ else expectToBe true false -- Fails with message about not containing
40+ Right val -> expectToBe true false
41+ where
42+ contains :: String -> String -> Boolean
43+ contains n h = indexOf n h >= 0
44+
45+ indexOf :: String -> String -> Int
46+ indexOf = indexOfImpl
47+
48+foreign import indexOfImpl :: String -> String -> Int