@deepseek-ai/dsh-client-test-runtime 0.1.2-rc.1 → 0.1.5-alpha.1

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.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/test-support/client-runtime/README.md
5
- README.md: 3cc916343c25144720bfd599b87da7b5a2bb6b5d
6
- README.zh.md: cd8a935f16bee9946edad8df41dab37c3b72af69
5
+ README.md: 616eab2cd5ef03ae4e514ca335b0c60b43d62cf0
6
+ README.zh.md: 08effcef7eaacad67b5496507925337e772d4ce9
package/README.md CHANGED
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
9
9
 
10
10
  ## Summary
11
11
 
12
- `dsh-client-test-runtime` gives a browser feature spec a real jsdom test bench: it assembles a Cordis context, the renderer-owned slot registry, and the production `UiSession` adapter around typed Session and Workspace Controller doubles. Feature suites exercise declaration, registration, scoping, stores, injection, rendering, updates, and disposal without copying production renderer or adapter logic. Suites publish Session lifecycle state, Workspace state, projection values, and Conversation events through typed fixtures, then use local DOM snapshot roots, scoped Testing Library queries, and fail-loud service checks. It is not part of the product plugin graph (no `dsh.client`); feature packages depend on it in `devDependencies` only.
12
+ `dsh-client-test-runtime` lets browser feature specs exercise production slot, store, rendering, update, and disposal behavior in jsdom without reimplementing the UI runtime. Test authors can publish typed Session, Workspace, projection, and Conversation fixtures, query slot-local DOM roots, and script Remote replies or failures. Missing services, unstubbed session behavior, and unexpected file uploads fail at the call site, while disposal is idempotent. Use it only from in-repository browser-oriented Vitest suites through `devDependencies`; it is not a product plugin or general Node test harness.
13
13
 
14
14
  ## Table of Contents
15
15
 
@@ -40,7 +40,7 @@ expect(view.container).toMatchSnapshot()
40
40
  await runtime.dispose()
41
41
  ```
42
42
 
43
- `mount` prechecks required services and fails loud when one is missing — `provide(name, value)` supplies an extra service first. `storeOf(key, scopeKey)` returns the live store instance the renderer hands a slot's component for identity and action-driven-write assertions.
43
+ `mount` prechecks required services and fails loud when one is missing — `provide(name, value)` supplies an extra service first. The runtime provides an unavailable `fileUpload` stub so assemblies can mount; replace `runtime.fileUpload.upload` before mounting when a test exercises upload behavior. `storeOf(key, scopeKey)` returns the live store instance the renderer hands a slot's component for identity and action-driven-write assertions.
44
44
 
45
45
  ### Local DOM snapshots
46
46
 
@@ -101,7 +101,7 @@ The bench copies no production logic: it mounts the production `SlotRegistry`, p
101
101
 
102
102
  ### Lifecycle
103
103
 
104
- `create()` builds a fresh context, mounts the slot and conversation registries, installs the renderer, and provides the session/workspace doubles. `mount` checks every declared injection against the context before starting the fiber, so a missing provider fails loud instead of suspending forever. `dispose()` unmounts React trees first, then disposes feature fibers, releases the root registration, disposes minted session scopes, and clears persisted store state; every public mutator is act-wrapped, so tests never handle SlotCore microtask batching or React `act` themselves.
104
+ `create()` builds a fresh context, mounts the slot and conversation registries, installs the renderer, and provides the session/workspace doubles plus the fail-loud file-upload stub. `mount` checks every declared injection against the context before starting the fiber, so a missing provider fails loud instead of suspending forever. `dispose()` unmounts React trees first, then disposes feature fibers, releases the root registration, disposes minted session scopes, and clears persisted store state; every public mutator is act-wrapped, so tests never handle SlotCore microtask batching or React `act` themselves.
105
105
 
106
106
  </details>
107
107
 
package/README.zh.md CHANGED
@@ -9,7 +9,7 @@ kind: "package-library"
9
9
 
10
10
  ## 概述
11
11
 
12
- `dsh-client-test-runtime` 让浏览器功能测试拥有真实的 jsdom 测试台:它把 Cordis 上下文、渲染器拥有的 slot 注册表与生产 `UiSession` 适配器组装在带类型的 SessionWorkspace Controller 替身周围。功能套件无需复制生产渲染器或适配器逻辑,即可检验声明、注册、作用域、store、注入、渲染、更新与销毁。套件通过带类型 fixture 发布 Session 生命周期状态、Workspace 状态、projection 值与 Conversation 事件,再使用局部 DOM 快照根、限定范围的 Testing Library 查询与自明的服务缺失检查。它不属于产品插件图(无 `dsh.client`);feature 包仅以 `devDependencies` 依赖之。
12
+ `dsh-client-test-runtime` 让浏览器功能测试在 jsdom 中检验生产 slot、store、渲染、更新与销毁行为,而无需重实现 UI 运行时。测试作者可以发布带类型的 SessionWorkspace、projection Conversation fixture,查询 slot 局部 DOM 根,并脚本化 Remote 应答或失败。缺失服务、未打桩的会话行为与意外文件上传都会在调用点失败,销毁则保持幂等。仅限仓内、面向浏览器的 Vitest 套件通过 `devDependencies` 使用本包;它不是产品插件或通用 Node 测试框架。
13
13
 
14
14
  ## 目录
15
15
 
@@ -40,7 +40,7 @@ expect(view.container).toMatchSnapshot()
40
40
  await runtime.dispose()
41
41
  ```
42
42
 
43
- `mount` 会预检必需服务,缺失时自明报错——先用 `provide(name, value)` 提供额外服务。`storeOf(key, scopeKey)` 返回渲染器交给 slot 组件的实时 store 实例,用于身份与动作驱动写入断言。
43
+ `mount` 会预检必需服务,缺失时自明报错——先用 `provide(name, value)` 提供额外服务。运行时会提供不可用的 `fileUpload` 替身,使装配可以挂载;测试上传行为时,需要在挂载前替换 `runtime.fileUpload.upload`。`storeOf(key, scopeKey)` 返回渲染器交给 slot 组件的实时 store 实例,用于身份与动作驱动写入断言。
44
44
 
45
45
  ### 局部 DOM 快照
46
46
 
@@ -101,7 +101,7 @@ expect(view.getByRole('alert')).toHaveTextContent('goal/not-found')
101
101
 
102
102
  ### 生命周期
103
103
 
104
- `create()` 构建全新上下文,挂载 slot 与会话注册表,安装渲染器,并提供 session/workspace 替身。`mount` 在启动 fiber 前对照上下文检查每个已声明注入,使缺失提供方自明报错而非永久挂起。`dispose()` 先卸载 React 树,再 dispose feature fiber、释放根注册、dispose 已铸 session scope 并清除持久化 store 状态;每个公共修改器都包裹在 act 中,因此测试无需自行处理 SlotCore 微任务批处理或 React `act`。
104
+ `create()` 构建全新上下文,挂载 slot 与会话注册表,安装渲染器,并提供 session/workspace 替身和明确失败的文件上传替身。`mount` 在启动 fiber 前对照上下文检查每个已声明注入,使缺失提供方自明报错而非永久挂起。`dispose()` 先卸载 React 树,再 dispose feature fiber、释放根注册、dispose 已铸 session scope 并清除持久化 store 状态;每个公共修改器都包裹在 act 中,因此测试无需自行处理 SlotCore 微任务批处理或 React `act`。
105
105
 
106
106
  </details>
107
107
 
package/lib/index.js CHANGED
@@ -1064,7 +1064,7 @@ function usePinnedBrowserLanguages(primary, ...rest) {
1064
1064
  /**
1065
1065
  * jsdom slot test runtime: a real small runtime — Cordis `Context`, the
1066
1066
  * renderer-owned `SlotRegistry`, the `ui-session` adapter, and the UI renderer — assembled around
1067
- * test-owned session/workspace doubles, so feature specs exercise
1067
+ * test-owned session/workspace doubles and a fail-loud file-upload stub, so feature specs exercise
1068
1068
  * declaration, registration, scope, store, inject, rendering, updates, and
1069
1069
  * disposal without hand-building the machinery per suite.
1070
1070
  *
@@ -1182,6 +1182,8 @@ var SlotTestRuntime = class SlotTestRuntime {
1182
1182
  sessions;
1183
1183
  /** Workspaces double (list observable, recorded intent actions). */
1184
1184
  workspaces;
1185
+ /** Mutable file-upload stub; replace `upload` in suites that exercise the capability. */
1186
+ fileUpload;
1185
1187
  stabilizer = async (fn) => {
1186
1188
  await act(async () => {
1187
1189
  await fn();
@@ -1202,8 +1204,13 @@ var SlotTestRuntime = class SlotTestRuntime {
1202
1204
  this.root = new TestRoot(slots, this.stabilizer);
1203
1205
  this.sessions = new TestSessions(this.stabilizer, ctx);
1204
1206
  this.workspaces = new TestWorkspaces(this.stabilizer);
1207
+ this.fileUpload = {
1208
+ available: false,
1209
+ upload: () => Promise.reject(/* @__PURE__ */ new Error("client test runtime: file upload is not stubbed"))
1210
+ };
1205
1211
  ctx.provide("sessions", this.sessions);
1206
1212
  ctx.provide("workspaces", this.workspaces);
1213
+ ctx.provide("fileUpload", this.fileUpload);
1207
1214
  this.disposeWorkspaceSource = slots.provideRoot({ hooks: { workspaces: this.workspaces.list } });
1208
1215
  const renderer = createSlotRenderer();
1209
1216
  slots.install({ renderRoot: (host, ownerProps) => {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * jsdom slot test runtime: a real small runtime — Cordis `Context`, the
3
3
  * renderer-owned `SlotRegistry`, the `ui-session` adapter, and the UI renderer — assembled around
4
- * test-owned session/workspace doubles, so feature specs exercise
4
+ * test-owned session/workspace doubles and a fail-loud file-upload stub, so feature specs exercise
5
5
  * declaration, registration, scope, store, inject, rendering, updates, and
6
6
  * disposal without hand-building the machinery per suite.
7
7
  *
@@ -16,6 +16,7 @@ import type { RenderResult } from '@testing-library/react';
16
16
  import type { queries } from '@testing-library/dom';
17
17
  import type { BoundFunctions } from '@testing-library/dom';
18
18
  import { SlotRegistry } from '@deepseek-ai/dsh-client-ui-renderer/client';
19
+ import type { SessionId } from '@deepseek-ai/dsh-session/types';
19
20
  import type { ChildrenDecl, ComposedProps, HostObservable, OwnerOf, SlotComponent, SlotMap, SlotRenderer, SnapshotSelectorHook, StoreInstanceLike } from '@deepseek-ai/dsh-client-ui-slots';
20
21
  import { TestSessions } from './sessions.ts';
21
22
  import { TestWorkspaces } from './workspaces.ts';
@@ -77,6 +78,13 @@ export interface FeatureHandle {
77
78
  */
78
79
  dispose(): Promise<void>;
79
80
  }
81
+ /** Mutable fail-loud file-upload stub installed by {@link SlotTestRuntime}. */
82
+ export interface TestFileUpload {
83
+ /** Availability reported to the feature under test. */
84
+ available: boolean;
85
+ /** Test-supplied upload behavior; the default rejects every call. */
86
+ upload: (sessionId: SessionId, ...args: unknown[]) => Promise<unknown>;
87
+ }
80
88
  /**
81
89
  * The test-owned 'root' occupant: declares the child slots a suite needs
82
90
  * through the REAL `slots.register`, with a caller-supplied minimal frame —
@@ -120,6 +128,8 @@ export declare class SlotTestRuntime {
120
128
  readonly sessions: TestSessions;
121
129
  /** Workspaces double (list observable, recorded intent actions). */
122
130
  readonly workspaces: TestWorkspaces;
131
+ /** Mutable file-upload stub; replace `upload` in suites that exercise the capability. */
132
+ readonly fileUpload: TestFileUpload;
123
133
  private readonly stabilizer;
124
134
  private host;
125
135
  private readonly views;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-test-runtime",
3
3
  "description": "jsdom slot test runtime: real Cordis Context + SlotRegistry + UI renderer with test-owned session/workspace doubles for feature specs",
4
- "version": "0.1.2-rc.1",
4
+ "version": "0.1.5-alpha.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -30,42 +30,42 @@
30
30
  "peerDependencies": {
31
31
  "react": "^18.2.0",
32
32
  "react-dom": "^18.2.0",
33
- "@deepseek-ai/dsh-api-session-controller": "^0.1.2-rc.1",
34
- "@deepseek-ai/dsh-api-workspace-controller": "^0.1.2-rc.1",
35
- "@deepseek-ai/dsh-attachment": "^0.1.2-rc.1",
36
- "@deepseek-ai/dsh-client-connection": "^0.1.2-rc.1",
37
- "@deepseek-ai/dsh-client-store": "^0.1.2-rc.1",
38
- "@deepseek-ai/dsh-client-ui-chat": "^0.1.2-rc.1",
39
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-rc.1",
40
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.2-rc.1",
41
- "@deepseek-ai/dsh-client-ui-session": "^0.1.2-rc.1",
42
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.2-rc.1",
43
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.2-rc.1",
44
- "@deepseek-ai/dsh-subagent": "^0.1.2-rc.1",
45
- "@deepseek-ai/dsh-typert-protocol": "^0.1.2-rc.1",
33
+ "@deepseek-ai/dsh-api-session-controller": "^0.1.5-alpha.1",
34
+ "@deepseek-ai/dsh-api-workspace-controller": "^0.1.5-alpha.1",
35
+ "@deepseek-ai/dsh-attachment": "^0.1.5-alpha.1",
36
+ "@deepseek-ai/dsh-client-connection": "^0.1.5-alpha.1",
37
+ "@deepseek-ai/dsh-client-ui-chat": "^0.1.5-alpha.1",
38
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-alpha.1",
39
+ "@deepseek-ai/dsh-client-store": "^0.1.5-alpha.1",
40
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-alpha.1",
41
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.5-alpha.1",
42
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.5-alpha.1",
43
+ "@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
44
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.5-alpha.1",
45
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.5-alpha.1",
46
46
  "@deepseek-ai/cordis": "^4.0.2",
47
- "@deepseek-ai/dsh-session": "^0.1.2-rc.1"
47
+ "@deepseek-ai/dsh-subagent": "^0.1.5-alpha.1"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/react": "~18.3.1",
51
51
  "@types/react-dom": "~18.3.0",
52
52
  "react": "^18.2.0",
53
53
  "react-dom": "^18.2.0",
54
- "@deepseek-ai/dsh-api-workspace-controller": "^0.1.2-rc.1",
55
- "@deepseek-ai/dsh-api-session-controller": "^0.1.2-rc.1",
56
- "@deepseek-ai/dsh-attachment": "^0.1.2-rc.1",
57
- "@deepseek-ai/dsh-client-connection": "^0.1.2-rc.1",
58
- "@deepseek-ai/dsh-client-store": "^0.1.2-rc.1",
59
- "@deepseek-ai/dsh-client-ui-chat": "^0.1.2-rc.1",
60
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-rc.1",
61
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.2-rc.1",
62
- "@deepseek-ai/dsh-client-ui-session": "^0.1.2-rc.1",
63
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.2-rc.1",
64
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.2-rc.1",
65
- "@deepseek-ai/dsh-session": "^0.1.2-rc.1",
66
- "@deepseek-ai/dsh-subagent": "^0.1.2-rc.1",
67
- "@deepseek-ai/dsh-typert-protocol": "^0.1.2-rc.1",
68
- "@deepseek-ai/cordis": "^4.0.2"
54
+ "@deepseek-ai/dsh-api-workspace-controller": "^0.1.5-alpha.1",
55
+ "@deepseek-ai/dsh-api-session-controller": "^0.1.5-alpha.1",
56
+ "@deepseek-ai/dsh-client-store": "^0.1.5-alpha.1",
57
+ "@deepseek-ai/dsh-client-connection": "^0.1.5-alpha.1",
58
+ "@deepseek-ai/dsh-client-ui-chat": "^0.1.5-alpha.1",
59
+ "@deepseek-ai/dsh-attachment": "^0.1.5-alpha.1",
60
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.5-alpha.1",
61
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.5-alpha.1",
62
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-alpha.1",
63
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.5-alpha.1",
64
+ "@deepseek-ai/dsh-subagent": "^0.1.5-alpha.1",
65
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.5-alpha.1",
66
+ "@deepseek-ai/cordis": "^4.0.2",
67
+ "@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
68
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-alpha.1"
69
69
  },
70
70
  "files": [
71
71
  "lib/index.js",