@hot-updater/test-utils 1.0.0-rc.16 → 1.0.0-rc.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,37 +1,49 @@
1
1
  # @hot-updater/test-utils
2
2
 
3
- Vitest suites for Hot Updater database adapters, providers and servers. The
4
- official providers and example servers run these same suites.
3
+ Test suites and helpers for Hot Updater storage adapters, database adapters,
4
+ providers, server plugins, client plugins and servers. The official adapters,
5
+ providers, plugins and example servers run these same suites.
5
6
 
6
7
  ```bash
7
8
  pnpm add -D @hot-updater/test-utils @hot-updater/server vitest
8
9
  ```
9
10
 
11
+ It uses the other Hot Updater packages only through their public API, and
12
+ takes them as peer dependencies. `@hot-updater/server` and
13
+ `@hot-updater/plugin-insights` are optional: the database suites load the
14
+ server when they run, and the Insights suites use the plugin's types. The SQL
15
+ test executors of `@hot-updater/test-utils/node` take `pg`, `mysql2` or
16
+ `@electric-sql/pglite`, whichever you test on.
17
+
10
18
  ## Database adapters and providers
11
19
 
12
20
  Register three suites against a disposable test database:
13
21
 
14
- - `setupDatabaseAdapterConformanceSuite` runs the storage adapter contract case
22
+ - `setupDatabaseAdapterConformanceSuite` runs the database adapter contract case
15
23
  by case: value round-trips, ordering, guards, all-or-nothing writes, unique
16
24
  and multi-valued indexes, paging under capped native pages, and concurrent
17
25
  writers.
18
26
  - `setupReadBudgetTestSuite` checks what each read of core and the built-in
19
- plugins costs at the adapter, using `createMeasuredDatabase` from
20
- `@hot-updater/server/db`. `postgresRowsExamined` and `mysqlRowsExamined` also
21
- count the rows a SQL database examined.
22
- - `setupDatabaseTestSuite` runs core, Bundles, the Release Catalog contract and
23
- Insights through the admin and client HTTP APIs of `createHotUpdater`.
27
+ plugins costs at the adapter, on `createMeasuredDatabase`: `createHotUpdater`
28
+ over `meterReads({ name, adapter: verifyAdapter(adapter) })` from
29
+ `@hot-updater/plugin-core`. `postgresRowsExamined` and `mysqlRowsExamined`
30
+ also count the rows a SQL database examined.
31
+ - `setupDatabaseTestSuite` runs core, Bundles and the Release Catalog contract
32
+ through the admin and client HTTP APIs of `createHotUpdater`, then the suites
33
+ of the server plugins listed in `plugins`, such as the Insights plugin's
34
+ `insightsTestSuite()`.
24
35
 
25
36
  Connect your database's lifecycle and the real server:
26
37
 
27
38
  ```ts
28
39
  import { createHotUpdater } from "@hot-updater/server";
29
- import { createDatabasePluginApis } from "@hot-updater/server/db";
30
40
  import {
31
41
  createInsightsModel,
32
42
  insights,
33
43
  } from "@hot-updater/server/plugins/insights";
44
+
34
45
  import {
46
+ insightsTestSuite,
35
47
  setupDatabaseTestSuite,
36
48
  startHttpTestServer,
37
49
  } from "@hot-updater/test-utils";
@@ -57,10 +69,20 @@ setupDatabaseTestSuite({
57
69
  clientAccess: "public",
58
70
  }).handlers,
59
71
  ),
60
- createInsightsModel: (database) =>
61
- createInsightsModel(
62
- createDatabasePluginApis(database, [insights()]).insights,
63
- ),
72
+ // The server above runs insights(), so its suite runs too.
73
+ plugins: [
74
+ insightsTestSuite({
75
+ // The plugin's API on the database, as a server running it assembles it.
76
+ createModel: (database) =>
77
+ createInsightsModel(
78
+ createHotUpdater({
79
+ database,
80
+ plugins: [insights()],
81
+ clientAccess: "public",
82
+ }).api.insights,
83
+ ),
84
+ }),
85
+ ],
64
86
  });
65
87
  ```
66
88
 
@@ -72,15 +94,80 @@ client selector and keep a simulated device's state across updates, rollbacks
72
94
  and the built-in fallback. Native download, activation and restart remain
73
95
  device end-to-end responsibilities.
74
96
 
97
+ ## Storage adapters
98
+
99
+ `setupStorageAdapterTestSuite` runs the storage adapter contract that deploy,
100
+ patch, the Console, the server and `storage prune` rely on: the canonical URI
101
+ of each key below the base path, streamed bodies, failed uploads that leave no
102
+ object, exact deletes, URIs of another bucket or protocol, download URLs, and
103
+ listing. A storage adapter's specs don't need `@hot-updater/server`.
104
+
105
+ ```ts
106
+ import { setupStorageAdapterTestSuite } from "@hot-updater/test-utils";
107
+
108
+ import { myStorage } from "./myStorage";
109
+
110
+ setupStorageAdapterTestSuite({
111
+ name: "myStorage",
112
+ createStorage: async () => ({
113
+ storage: myStorage({ bucket: "bundles", basePath: "ota" }),
114
+ basePath: "ota",
115
+ }),
116
+ operations: ["put", "get", "getDownloadUrl", "exists", "delete"],
117
+ });
118
+ ```
119
+
120
+ `createStorage` returns the adapter over an empty bucket or base path for each
121
+ case, and the `cleanup` it may return runs after the case. `operations` lists
122
+ what the adapter implements: the suite fails when one of them is missing and
123
+ skips the cases of the others.
124
+
75
125
  ## Plugins and servers
76
126
 
77
- - `createPluginTestHarness` runs one server plugin the way `createHotUpdater`
78
- does, on a memory adapter by default, and measures what each API call reads.
127
+ - `createPluginTestHarness` runs one server plugin on `createEngine` from
128
+ `@hot-updater/plugin-core`, the engine `createHotUpdater` runs plugins on, on
129
+ a memory adapter by default, and measures what each API call reads.
79
130
  - `setupReleaseCatalogTestSuite` with `createHttpTestClient` tests a running
80
131
  server by URL. Use `createHandlerHttpTestClient` inside a Workers Vitest pool.
81
132
  - Server processes can import `createReleaseCatalogTestStorage` from
82
133
  `@hot-updater/test-utils/node` to install the suites' storage fixtures.
83
134
 
135
+ ## Client plugins
136
+
137
+ `@hot-updater/test-utils/react-native` runs client plugins the way the app
138
+ does. `setupClientPlugin(plugin, options)` and
139
+ `setupClientPlugins(plugins, options)` set plugins up as `HotUpdater.init`
140
+ does, on the plugin host from `@hot-updater/protocol`, the one the SDK runs,
141
+ against an in-memory device and a server the test answers. The entry loads
142
+ neither React Native nor Vitest, so plugin specs run in plain Node under
143
+ Vitest or Jest when the plugin imports `defineClientPlugin` from
144
+ `@hot-updater/protocol`; the SDK's root entry loads React Native.
145
+
146
+ ```ts
147
+ import { setupClientPlugin } from "@hot-updater/test-utils/react-native";
148
+
149
+ const runtime = setupClientPlugin(myPlugin(), {
150
+ requestHeaders: { "x-api-key": "client-key" },
151
+ });
152
+
153
+ runtime.hooks.onAppReady(launch);
154
+ await runtime.settled();
155
+
156
+ expect(runtime.requests[0]?.json()).toEqual(expectedEvent);
157
+ expect(runtime.errors).toEqual([]);
158
+ ```
159
+
160
+ `hooks` calls each hook as the SDK does, without waiting for it, and
161
+ `settled()` waits for what the hooks started. `requests` records what plugins
162
+ sent with `context.fetch`, and the `respond` option answers each request,
163
+ `204 No Content` by default. `errors` holds what the SDK reports to `onError`.
164
+ `storage` is the device's plugin storage: pass it to the next setup to start
165
+ the plugins again on the same device, or seed one with `createTestStorage()`.
166
+
84
167
  See the
85
- [custom database adapter guide](https://hot-updater.dev/docs/database-plugins/custom-database)
86
- for the adapter contract and complete specs for each suite.
168
+ [storage adapter guide](https://hot-updater.dev/docs/storage-adapters/custom-storage#test-the-adapter),
169
+ the
170
+ [database adapter guide](https://hot-updater.dev/docs/database-adapters/custom-database),
171
+ and the
172
+ [client plugin guide](https://hot-updater.dev/docs/react-native-api/client-plugins#test-the-plugin)
173
+ for the contracts and complete specs.