repos / starfx

a micro-mvc framework for react apps
git clone https://github.com/neurosnap/starfx.git

commit
1f2e083
parent
ce7d484
author
Jacob Bolda
date
2025-01-04 09:03:09 -0500 EST
confirm tests assert when run within an generator function (#55)

---------

Co-authored-by: Vlad Marginean <vladmarginean@softwiz.ro>
7 files changed,  +200, -108
A deps.ts
+61, -0
 1@@ -0,0 +1,61 @@
 2+export type {
 3+  Callable,
 4+  Channel,
 5+  Instruction,
 6+  Operation,
 7+  Predicate,
 8+  Queue,
 9+  Reject,
10+  Resolve,
11+  Result,
12+  Scope,
13+  Signal,
14+  Stream,
15+  Subscription,
16+  Task,
17+} from "https://deno.land/x/effection@3.0.0-beta.3/mod.ts";
18+export {
19+  action,
20+  call,
21+  createChannel,
22+  createContext,
23+  createQueue,
24+  createScope,
25+  createSignal,
26+  each,
27+  ensure,
28+  Err,
29+  Ok,
30+  race,
31+  resource,
32+  run,
33+  SignalQueueFactory,
34+  sleep,
35+  spawn,
36+  suspend,
37+  useAbortSignal,
38+  useScope,
39+} from "https://deno.land/x/effection@3.0.0-beta.3/mod.ts";
40+
41+import React from "https://esm.sh/react@18.2.0?pin=v135";
42+
43+export type { JSX } from "https://esm.sh/react@18.2.0?pin=v135";
44+
45+export { React };
46+export {
47+  Provider,
48+  useDispatch,
49+  useSelector,
50+  useStore,
51+} from "https://esm.sh/react-redux@8.0.5?pin=v135";
52+export type {
53+  TypedUseSelectorHook,
54+} from "https://esm.sh/react-redux@8.0.5?pin=v135";
55+export { createSelector } from "https://esm.sh/reselect@4.1.8?pin=v135";
56+
57+export {
58+  enablePatches,
59+  produce,
60+  produceWithPatches,
61+} from "https://esm.sh/immer@10.0.2?pin=v135";
62+export type { Patch } from "https://esm.sh/immer@10.0.2?pin=v135";
M test.ts
+1, -0
1@@ -5,6 +5,7 @@ export {
2   describe,
3   it,
4 } from "jsr:@std/testing/bdd";
5+export * as assertType from "jsr:@std/testing/types";
6 export { assert } from "jsr:@std/assert";
7 export * as asserts from "jsr:@std/assert";
8 export { expect } from "jsr:@std/expect";
M test/api.test.ts
+39, -18
  1@@ -1,14 +1,6 @@
  2-import { describe, expect, it } from "../test.ts";
  3-import {
  4-  createSchema,
  5-  createStore,
  6-  select,
  7-  slice,
  8-  updateStore,
  9-  waitForLoader,
 10-} from "../store/mod.ts";
 11 import {
 12   AnyState,
 13+  API_ACTION_PREFIX,
 14   ApiCtx,
 15   call,
 16   createApi,
 17@@ -21,6 +13,15 @@ import {
 18   waitFor,
 19 } from "../mod.ts";
 20 import { useCache } from "../react.ts";
 21+import {
 22+  createSchema,
 23+  createStore,
 24+  select,
 25+  slice,
 26+  updateStore,
 27+  waitForLoader,
 28+} from "../store/mod.ts";
 29+import { describe, expect, it } from "../test.ts";
 30 
 31 interface User {
 32   id: string;
 33@@ -48,6 +49,7 @@ const jsonBlob = (data: unknown) => {
 34 const tests = describe("createApi()");
 35 
 36 it(tests, "POST", async () => {
 37+  expect.assertions(2);
 38   const query = createApi();
 39   query.use(mdw.queryCtx);
 40   query.use(mdw.nameParser);
 41@@ -118,6 +120,7 @@ it(tests, "POST", async () => {
 42 });
 43 
 44 it(tests, "POST with uri", () => {
 45+  expect.assertions(1);
 46   const query = createApi();
 47   query.use(mdw.queryCtx);
 48   query.use(mdw.nameParser);
 49@@ -165,6 +168,7 @@ it(tests, "POST with uri", () => {
 50 });
 51 
 52 it(tests, "middleware - with request fn", () => {
 53+  expect.assertions(2);
 54   const query = createApi();
 55   query.use(mdw.queryCtx);
 56   query.use(mdw.nameParser);
 57@@ -185,6 +189,7 @@ it(tests, "middleware - with request fn", () => {
 58 });
 59 
 60 it(tests, "run() on endpoint action - should run the effect", () => {
 61+  expect.assertions(1);
 62   const api = createApi<TestCtx>();
 63   api.use(api.routes());
 64   let acc = "";
 65@@ -212,7 +217,8 @@ it(tests, "run() on endpoint action - should run the effect", () => {
 66   store.dispatch(action2());
 67 });
 68 
 69-it(tests, "run() from a normal saga", () => {
 70+it(tests, "run() from a normal saga", async () => {
 71+  expect.assertions(6);
 72   const api = createApi();
 73   api.use(api.routes());
 74   let acc = "";
 75@@ -226,28 +232,43 @@ it(tests, "run() from a normal saga", () => {
 76       acc += "a";
 77     },
 78   );
 79+  const extractedResults = {
 80+    actionType: null,
 81+    actionPayload: null,
 82+    name: null,
 83+    payload: null,
 84+  };
 85   const action2 = () => ({ type: "ACTION" });
 86   function* onAction() {
 87     const ctx = yield* safe(() => action1.run(action1({ id: "1" })));
 88     if (!ctx.ok) {
 89       throw new Error("no ctx");
 90     }
 91-    const payload = { name: "/users/:id [GET]", options: { id: "1" } };
 92-    expect(ctx.value.action.type).toEqual(`@@starfx${action1}`);
 93-    expect(ctx.value.action.payload).toEqual(payload);
 94-    expect(ctx.value.name).toEqual("/users/:id [GET]");
 95-    expect(ctx.value.payload).toEqual({ id: "1" });
 96+    Object.assign(extractedResults, {
 97+      actionType: ctx.value.action.type,
 98+      actionPayload: ctx.value.action.payload,
 99+      name: ctx.value.name,
100+      payload: ctx.value.payload,
101+    });
102     acc += "b";
103-    expect(acc).toEqual("ab");
104   }
105-
106   function* watchAction() {
107-    yield* takeEvery(`${action2}`, onAction);
108+    yield* takeEvery(action2, onAction);
109   }
110 
111   const store = createStore({ initialState: { users: {} } });
112   store.run(() => keepAlive([api.bootup, watchAction]));
113   store.dispatch(action2());
114+
115+  await new Promise((resolve) => setTimeout(resolve, 300));
116+  const payload = { name: "/users/:id [GET]", options: { id: "1" } };
117+
118+  expect(extractedResults.actionType).toEqual(`${API_ACTION_PREFIX}${action1}`);
119+  expect(extractedResults.actionPayload!["name"]).toEqual(payload.name);
120+  expect(extractedResults.actionPayload!["options"]).toEqual(payload.options);
121+  expect(extractedResults.name).toEqual("/users/:id [GET]");
122+  expect(extractedResults.payload).toEqual({ id: "1" });
123+  expect(acc).toEqual("ab");
124 });
125 
126 it(tests, "with hash key on a large post", async () => {
M test/safe.test.ts
+3, -0
 1@@ -4,6 +4,7 @@ import { call, run } from "../mod.ts";
 2 const tests = describe("call()");
 3 
 4 it(tests, "should call the generator function", async () => {
 5+  expect.assertions(1);
 6   function* me() {
 7     return "valid";
 8   }
 9@@ -15,6 +16,7 @@ it(tests, "should call the generator function", async () => {
10 });
11 
12 it(tests, "should return an Err()", async () => {
13+  expect.assertions(1);
14   const err = new Error("bang!");
15   function* me() {
16     throw err;
17@@ -30,6 +32,7 @@ it(tests, "should return an Err()", async () => {
18 });
19 
20 it(tests, "should call a promise", async () => {
21+  expect.assertions(1);
22   const me = () =>
23     new Promise<string>((resolve) => {
24       setTimeout(() => {
M test/schema.test.ts
+17, -15
  1@@ -1,4 +1,4 @@
  2-import { asserts, describe, it } from "../test.ts";
  3+import { describe, expect, it } from "../test.ts";
  4 import { createSchema, createStore, select, slice } from "../store/mod.ts";
  5 
  6 const tests = describe("createSchema()");
  7@@ -16,7 +16,7 @@ const emptyUser = { id: "", name: "" };
  8 it(tests, "default schema", async () => {
  9   const [schema, initialState] = createSchema();
 10   const store = createStore({ initialState });
 11-  asserts.assertEquals(store.getState(), {
 12+  expect(store.getState()).toEqual({
 13     cache: {},
 14     loaders: {},
 15   });
 16@@ -26,16 +26,17 @@ it(tests, "default schema", async () => {
 17     yield* schema.update(schema.cache.add({ "1": true }));
 18   });
 19 
 20-  asserts.assertEquals(schema.cache.selectTable(store.getState()), {
 21+  expect(schema.cache.selectTable(store.getState())).toEqual({
 22     "1": true,
 23   });
 24-  asserts.assertEquals(
 25+  expect(
 26     schema.loaders.selectById(store.getState(), { id: "1" }).status,
 27     "loading",
 28   );
 29 });
 30 
 31 it(tests, "general types and functionality", async () => {
 32+  expect.assertions(8);
 33   const [db, initialState] = createSchema({
 34     users: slice.table<User>({
 35       initialState: { "1": { id: "1", name: "wow" } },
 36@@ -50,7 +51,7 @@ it(tests, "general types and functionality", async () => {
 37   });
 38   const store = createStore({ initialState });
 39 
 40-  asserts.assertEquals(store.getState(), {
 41+  expect(store.getState()).toEqual({
 42     users: { "1": { id: "1", name: "wow" } },
 43     token: "",
 44     counter: 0,
 45@@ -60,7 +61,7 @@ it(tests, "general types and functionality", async () => {
 46     loaders: {},
 47   });
 48   const userMap = db.users.selectTable(store.getState());
 49-  asserts.assertEquals(userMap, { "1": { id: "1", name: "wow" } });
 50+  expect(userMap).toEqual({ "1": { id: "1", name: "wow" } });
 51 
 52   await store.run(function* () {
 53     yield* db.update([
 54@@ -69,30 +70,31 @@ it(tests, "general types and functionality", async () => {
 55     ]);
 56 
 57     const users = yield* select(db.users.selectTable);
 58-    asserts.assertEquals(users, {
 59+    expect(users).toEqual({
 60       "1": { id: "1", name: "zzz" },
 61       "2": { id: "2", name: "bob" },
 62     });
 63 
 64     yield* db.update(db.counter.increment());
 65     const counter = yield* select(db.counter.select);
 66-    asserts.assertEquals(counter, 1);
 67+    expect(counter).toBe(1);
 68 
 69     yield* db.update(db.currentUser.update({ key: "name", value: "vvv" }));
 70     const curUser = yield* select(db.currentUser.select);
 71-    asserts.assertEquals(curUser, { id: "", name: "vvv" });
 72+    expect(curUser).toEqual({ id: "", name: "vvv" });
 73 
 74     yield* db.update(db.loaders.start({ id: "fetch-users" }));
 75     const fetchLoader = yield* select(db.loaders.selectById, {
 76       id: "fetch-users",
 77     });
 78-    asserts.assertEquals(fetchLoader.id, "fetch-users");
 79-    asserts.assertEquals(fetchLoader.status, "loading");
 80-    asserts.assertNotEquals(fetchLoader.lastRun, 0);
 81+    expect(fetchLoader.id).toBe("fetch-users");
 82+    expect(fetchLoader.status).toBe("loading");
 83+    expect(fetchLoader.lastRun).not.toBe(0);
 84   });
 85 });
 86 
 87 it(tests, "can work with a nested object", async () => {
 88+  expect.assertions(3);
 89   const [db, initialState] = createSchema({
 90     currentUser: slice.obj<UserWithRoles>({ id: "", name: "", roles: [] }),
 91     cache: slice.table({ empty: {} }),
 92@@ -102,17 +104,17 @@ it(tests, "can work with a nested object", async () => {
 93   await store.run(function* () {
 94     yield* db.update(db.currentUser.update({ key: "name", value: "vvv" }));
 95     const curUser = yield* select(db.currentUser.select);
 96-    asserts.assertEquals(curUser, { id: "", name: "vvv", roles: [] });
 97+    expect(curUser).toEqual({ id: "", name: "vvv", roles: [] });
 98 
 99     yield* db.update(db.currentUser.update({ key: "roles", value: ["admin"] }));
100     const curUser2 = yield* select(db.currentUser.select);
101-    asserts.assertEquals(curUser2, { id: "", name: "vvv", roles: ["admin"] });
102+    expect(curUser2).toEqual({ id: "", name: "vvv", roles: ["admin"] });
103 
104     yield* db.update(
105       db.currentUser.update({ key: "roles", value: ["admin", "users"] }),
106     );
107     const curUser3 = yield* select(db.currentUser.select);
108-    asserts.assertEquals(curUser3, {
109+    expect(curUser3).toEqual({
110       id: "",
111       name: "vvv",
112       roles: ["admin", "users"],
M test/store.test.ts
+16, -16
  1@@ -1,11 +1,11 @@
  2-import { asserts, describe, it } from "../test.ts";
  3+import { createScope, Operation, parallel, put, Result, take } from "../mod.ts";
  4 import {
  5   createStore,
  6   StoreContext,
  7   StoreUpdateContext,
  8   updateStore,
  9 } from "../store/mod.ts";
 10-import { createScope, Operation, parallel, put, Result, take } from "../mod.ts";
 11+import { describe, expect, it } from "../test.ts";
 12 
 13 const tests = describe("store");
 14 
 15@@ -54,39 +54,37 @@ it(
 16   tests,
 17   "update store and receives update from channel `StoreUpdateContext`",
 18   async () => {
 19+    expect.assertions(1);
 20     const [scope] = createScope();
 21     const initialState: Partial<State> = {
 22       users: { 1: { id: "1", name: "testing" }, 2: { id: "2", name: "wow" } },
 23       dev: false,
 24     };
 25     createStore({ scope, initialState });
 26-
 27+    let store;
 28     await scope.run(function* (): Operation<Result<void>[]> {
 29       const result = yield* parallel([
 30         function* () {
 31-          const store = yield* StoreContext;
 32+          store = yield* StoreContext;
 33           const chan = yield* StoreUpdateContext;
 34           const msgList = yield* chan.subscribe();
 35           yield* msgList.next();
 36-          asserts.assertEquals(store.getState(), {
 37-            users: { 1: { id: "1", name: "eric" }, 3: { id: "", name: "" } },
 38-            theme: "",
 39-            token: null,
 40-            dev: true,
 41-          });
 42         },
 43-
 44         function* () {
 45           yield* updateStore(updateUser({ id: "1", name: "eric" }));
 46         },
 47       ]);
 48-
 49       return yield* result;
 50     });
 51+    expect(store!.getState()).toEqual({
 52+      users: { 1: { id: "1", name: "eric" }, 3: { id: "", name: "" } },
 53+      dev: true,
 54+    });
 55   },
 56 );
 57 
 58 it(tests, "update store and receives update from `subscribe()`", async () => {
 59+  expect.assertions(1);
 60   const initialState: Partial<State> = {
 61     users: { 1: { id: "1", name: "testing" }, 2: { id: "2", name: "wow" } },
 62     dev: false,
 63@@ -96,7 +94,7 @@ it(tests, "update store and receives update from `subscribe()`", async () => {
 64   const store = createStore({ initialState });
 65 
 66   store.subscribe(() => {
 67-    asserts.assertEquals(store.getState(), {
 68+    expect(store.getState()).toEqual({
 69       users: { 1: { id: "1", name: "eric" }, 3: { id: "", name: "" } },
 70       dev: true,
 71       theme: "",
 72@@ -110,6 +108,7 @@ it(tests, "update store and receives update from `subscribe()`", async () => {
 73 });
 74 
 75 it(tests, "emit Action and update store", async () => {
 76+  expect.assertions(1);
 77   const initialState: Partial<State> = {
 78     users: { 1: { id: "1", name: "testing" }, 2: { id: "2", name: "wow" } },
 79     dev: false,
 80@@ -131,7 +130,7 @@ it(tests, "emit Action and update store", async () => {
 81     yield* result;
 82   });
 83 
 84-  asserts.assertEquals(store.getState(), {
 85+  expect(store.getState()).toEqual({
 86     users: { 1: { id: "1", name: "eric" }, 3: { id: "", name: "" } },
 87     theme: "",
 88     token: "",
 89@@ -140,6 +139,7 @@ it(tests, "emit Action and update store", async () => {
 90 });
 91 
 92 it(tests, "resets store", async () => {
 93+  expect.assertions(2);
 94   const initialState: Partial<State> = {
 95     users: { 1: { id: "1", name: "testing" }, 2: { id: "2", name: "wow" } },
 96     dev: false,
 97@@ -156,7 +156,7 @@ it(tests, "resets store", async () => {
 98     });
 99   });
100 
101-  asserts.assertEquals(store.getState(), {
102+  expect(store.getState()).toEqual({
103     users: { 3: { id: "3", name: "hehe" } },
104     theme: "darkness",
105     token: "",
106@@ -165,7 +165,7 @@ it(tests, "resets store", async () => {
107 
108   await store.run(store.reset(["users"]));
109 
110-  asserts.assertEquals(store.getState(), {
111+  expect(store.getState()).toEqual({
112     users: { 3: { id: "3", name: "hehe" } },
113     dev: false,
114     theme: "",
M test/thunk.test.ts
+63, -59
  1@@ -1,3 +1,4 @@
  2+import { API_ACTION_PREFIX } from "../action.ts";
  3 import {
  4   call,
  5   createThunks,
  6@@ -7,10 +8,9 @@ import {
  7   waitFor,
  8 } from "../mod.ts";
  9 import { createStore, updateStore } from "../store/mod.ts";
 10-import { assertLike, asserts, describe, it } from "../test.ts";
 11+import { describe, expect, it } from "../test.ts";
 12 
 13 import type { Next, ThunkCtx } from "../mod.ts";
 14-
 15 // deno-lint-ignore no-explicit-any
 16 interface RoboCtx<D = Record<string, unknown>, P = any> extends ThunkCtx<P> {
 17   url: string;
 18@@ -128,6 +128,7 @@ it(
 19   tests,
 20   "when create a query fetch pipeline - execute all middleware and save to redux",
 21   () => {
 22+    expect.assertions(1);
 23     const api = createThunks<RoboCtx>();
 24     api.use(api.routes());
 25     api.use(convertNameToUrl);
 26@@ -143,7 +144,7 @@ it(
 27 
 28     store.dispatch(fetchUsers());
 29 
 30-    asserts.assertEquals(store.getState(), {
 31+    expect(store.getState()).toEqual({
 32       users: { [mockUser.id]: deserializeUser(mockUser) },
 33       tickets: {},
 34     });
 35@@ -154,6 +155,7 @@ it(
 36   tests,
 37   "when providing a generator the to api.create function - should call that generator before all other middleware",
 38   () => {
 39+    expect.assertions(1);
 40     const api = createThunks<RoboCtx>();
 41     api.use(api.routes());
 42     api.use(convertNameToUrl);
 43@@ -183,7 +185,7 @@ it(
 44     store.run(api.bootup);
 45 
 46     store.dispatch(fetchTickets());
 47-    asserts.assertEquals(store.getState(), {
 48+    expect(store.getState()).toEqual({
 49       users: { [mockUser.id]: deserializeUser(mockUser) },
 50       tickets: { [mockTicket.id]: deserializeTicket(mockTicket) },
 51     });
 52@@ -191,6 +193,7 @@ it(
 53 );
 54 
 55 it(tests, "error handling", () => {
 56+  expect.assertions(1);
 57   let called;
 58   const api = createThunks<RoboCtx>();
 59   api.use(api.routes());
 60@@ -210,10 +213,11 @@ it(tests, "error handling", () => {
 61   const store = createStore({ initialState: {} });
 62   store.run(api.bootup);
 63   store.dispatch(action());
 64-  asserts.assertStrictEquals(called, true);
 65+  expect(called).toBe(true);
 66 });
 67 
 68 it(tests, "error handling inside create", () => {
 69+  expect.assertions(1);
 70   let called = false;
 71   const api = createThunks<RoboCtx>();
 72   api.use(api.routes());
 73@@ -235,10 +239,11 @@ it(tests, "error handling inside create", () => {
 74   const store = createStore({ initialState: {} });
 75   store.run(api.bootup);
 76   store.dispatch(action());
 77-  asserts.assertStrictEquals(called, true);
 78+  expect(called).toBe(true);
 79 });
 80 
 81 it(tests, "error inside endpoint mdw", () => {
 82+  expect.assertions(1);
 83   let called = false;
 84   const query = createThunks();
 85   query.use(function* (_, next) {
 86@@ -266,14 +271,15 @@ it(tests, "error inside endpoint mdw", () => {
 87   });
 88   store.run(query.bootup);
 89   store.dispatch(fetchUsers());
 90-  asserts.assertEquals(called, true);
 91+  expect(called).toBe(true);
 92 });
 93 
 94 it(tests, "create fn is an array", () => {
 95+  expect.assertions(1);
 96   const api = createThunks<RoboCtx>();
 97   api.use(api.routes());
 98   api.use(function* (ctx, next) {
 99-    asserts.assertEquals(ctx.request, {
100+    expect(ctx.request).toEqual({
101       method: "POST",
102       body: {
103         test: "me",
104@@ -300,9 +306,13 @@ it(tests, "create fn is an array", () => {
105 });
106 
107 it(tests, "run() on endpoint action - should run the effect", () => {
108+  expect.assertions(4);
109   const api = createThunks<RoboCtx>();
110   api.use(api.routes());
111+
112   let acc = "";
113+  let curCtx: RoboCtx = {} as RoboCtx;
114+
115   const action1 = api.create(
116     "/users",
117     { supervisor: takeEvery },
118@@ -317,34 +327,36 @@ it(tests, "run() on endpoint action - should run the effect", () => {
119     { supervisor: takeEvery },
120     function* (_, next) {
121       yield* next();
122-      const curCtx = yield* call(() => action1.run(action1()));
123+      curCtx = yield* call(() => action1.run(action1()));
124       acc += "b";
125-      asserts.assert(acc === "ab");
126-      assertLike(curCtx, {
127-        action: {
128-          type: `@@starfx${action1}`,
129-          payload: {
130-            name: "/users",
131-          },
132-        },
133-        name: "/users",
134-        request: { method: "expect this" },
135-      });
136     },
137   );
138 
139   const store = createStore({ initialState: {} });
140   store.run(api.bootup);
141   store.dispatch(action2());
142+  expect(acc).toBe("ab");
143+  expect(curCtx.action).toMatchObject({
144+    type: `${API_ACTION_PREFIX}${action1}`,
145+    payload: {
146+      name: "/users",
147+    },
148+  });
149+  expect(curCtx.name).toBe("/users");
150+  expect(curCtx.request).toEqual({ method: "expect this" });
151 });
152 
153 it(
154   tests,
155   "run() on endpoint action with payload - should run the effect",
156   () => {
157+    expect.assertions(4);
158     const api = createThunks<RoboCtx>();
159     api.use(api.routes());
160+
161     let acc = "";
162+    let curCtx: RoboCtx = {} as RoboCtx;
163+
164     const action1 = api.create<{ id: string }>(
165       "/users",
166       { supervisor: takeEvery },
167@@ -359,29 +371,28 @@ it(
168       { supervisor: takeEvery },
169       function* (_, next) {
170         yield* next();
171-        const curCtx = yield* action1.run({ id: "1" });
172+        curCtx = yield* call(() => action1.run({ id: "1" }));
173         acc += "b";
174-        asserts.assert(acc === "ab");
175-        assertLike(curCtx, {
176-          action: {
177-            type: `@@starfx${action1}`,
178-            payload: {
179-              name: "/users",
180-            },
181-          },
182-          name: "/users",
183-          request: { method: "expect this" },
184-        });
185       },
186     );
187 
188     const store = createStore({ initialState: {} });
189     store.run(api.bootup);
190     store.dispatch(action2());
191+    expect(acc).toBe("ab");
192+    expect(curCtx.action).toMatchObject({
193+      type: `${API_ACTION_PREFIX}${action1}`,
194+      payload: {
195+        name: "/users",
196+      },
197+    });
198+    expect(curCtx.name).toBe("/users");
199+    expect(curCtx.request).toEqual({ method: "expect this" });
200   },
201 );
202 
203 it(tests, "middleware order of execution", async () => {
204+  expect.assertions(1);
205   let acc = "";
206   const api = createThunks();
207   api.use(api.routes());
208@@ -418,10 +429,11 @@ it(tests, "middleware order of execution", async () => {
209   store.dispatch(action());
210 
211   await store.run(waitFor(() => acc === "abcdefg"));
212-  asserts.assert(acc === "abcdefg");
213+  expect(acc).toBe("abcdefg");
214 });
215 
216 it(tests, "retry with actionFn", async () => {
217+  expect.assertions(1);
218   let acc = "";
219   let called = false;
220 
221@@ -447,10 +459,11 @@ it(tests, "retry with actionFn", async () => {
222   store.dispatch(action());
223 
224   await store.run(waitFor(() => acc === "agag"));
225-  asserts.assertEquals(acc, "agag");
226+  expect(acc).toBe("agag");
227 });
228 
229 it(tests, "retry with actionFn with payload", async () => {
230+  expect.assertions(1);
231   let acc = "";
232   const api = createThunks();
233   api.use(api.routes());
234@@ -477,10 +490,11 @@ it(tests, "retry with actionFn with payload", async () => {
235   store.dispatch(action({ page: 1 }));
236 
237   await store.run(waitFor(() => acc === "agag"));
238-  asserts.assertEquals(acc, "agag");
239+  expect(acc).toBe("agag");
240 });
241 
242 it(tests, "should only call thunk once", () => {
243+  expect.assertions(1);
244   const api = createThunks<RoboCtx>();
245   api.use(api.routes());
246   let acc = "";
247@@ -505,10 +519,11 @@ it(tests, "should only call thunk once", () => {
248   const store = createStore({ initialState: {} });
249   store.run(api.bootup);
250   store.dispatch(action2());
251-  asserts.assertEquals(acc, "a");
252+  expect(acc).toBe("a");
253 });
254 
255 it(tests, "should be able to create thunk after `register()`", () => {
256+  expect.assertions(1);
257   const api = createThunks<RoboCtx>();
258   api.use(api.routes());
259   const store = createStore({ initialState: {} });
260@@ -519,10 +534,11 @@ it(tests, "should be able to create thunk after `register()`", () => {
261     acc += "a";
262   });
263   store.dispatch(action());
264-  asserts.assertEquals(acc, "a");
265+  expect(acc).toBe("a");
266 });
267 
268 it(tests, "should warn when calling thunk before registered", () => {
269+  expect.assertions(1);
270   const err = console.warn;
271   let called = false;
272   console.warn = () => {
273@@ -534,11 +550,12 @@ it(tests, "should warn when calling thunk before registered", () => {
274 
275   const action = api.create("/users");
276   store.dispatch(action());
277-  asserts.assertEquals(called, true);
278+  expect(called).toBe(true);
279   console.warn = err;
280 });
281 
282 it(tests, "it should call the api once even if we register it twice", () => {
283+  expect.assertions(1);
284   const api = createThunks<RoboCtx>();
285   api.use(api.routes());
286   const store = createStore({ initialState: {} });
287@@ -550,13 +567,14 @@ it(tests, "it should call the api once even if we register it twice", () => {
288     acc += "a";
289   });
290   store.dispatch(action());
291-  asserts.assertEquals(acc, "a");
292+  expect(acc).toBe("a");
293 });
294 
295 it(
296   tests,
297   "Should call the API only once, even if registered multiple times, with multiple APIs defined.",
298   () => {
299+    expect.assertions(2);
300     const api1 = createThunks<RoboCtx>();
301     api1.use(api1.routes());
302 
303@@ -578,11 +596,7 @@ it(
304     });
305     store.dispatch(action());
306 
307-    asserts.assertEquals(
308-      acc,
309-      "b",
310-      "Expected 'b' after first API call, but got: " + acc,
311-    );
312+    expect(acc).toBe("b");
313 
314     let acc2 = "";
315     const action2 = api2.create("/users", function* () {
316@@ -590,11 +604,7 @@ it(
317     });
318     store.dispatch(action2());
319 
320-    asserts.assertEquals(
321-      acc2,
322-      "c",
323-      "Expected 'c' after second API call, but got: " + acc2,
324-    );
325+    expect(acc2).toBe("c");
326   },
327 );
328 
329@@ -602,6 +612,7 @@ it(
330   tests,
331   "should unregister the thunk when the registration function exits",
332   async () => {
333+    expect.assertions(1);
334     const api1 = createThunks<RoboCtx>();
335     api1.use(api1.routes());
336 
337@@ -616,15 +627,12 @@ it(
338     });
339     store.dispatch(action());
340 
341-    asserts.assertEquals(
342-      acc,
343-      "b",
344-      "Expected 'b' after first API call, but got: " + acc,
345-    );
346+    expect(acc).toBe("b");
347   },
348 );
349 
350 it(tests, "should allow multiple stores to register a thunk", () => {
351+  expect.assertions(1);
352   const api1 = createThunks<RoboCtx>();
353   api1.use(api1.routes());
354   const storeA = createStore({ initialState: {} });
355@@ -638,9 +646,5 @@ it(tests, "should allow multiple stores to register a thunk", () => {
356   storeA.dispatch(action());
357   storeB.dispatch(action());
358 
359-  asserts.assertEquals(
360-    acc,
361-    "bb",
362-    "Expected 'bb' after first API call, but got: " + acc,
363-  );
364+  expect(acc).toBe("bb");
365 });