@deepseek-ai/dsh-client-test-runtime 0.1.2-alpha.5 → 0.1.3-alpha.2

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: 4ab70ecb6db7ae7d1844d8141b34daf7bd19a3dc
6
+ README.zh.md: c3265d7cdcadaf55c0744b13267ac5e64d6b47a6
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` 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. A default file-upload stub satisfies features that declare the service and rejects if a test starts an upload without replacing it. 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.
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` 适配器组装在带类型的 Session 和 Workspace Controller 替身周围。功能套件无需复制生产渲染器或适配器逻辑,即可检验声明、注册、作用域、store、注入、渲染、更新与销毁。套件通过带类型 fixture 发布 Session 生命周期状态、Workspace 状态、projection 值与 Conversation 事件,再使用局部 DOM 快照根、限定范围的 Testing Library 查询与自明的服务缺失检查。它不属于产品插件图(无 `dsh.client`);feature 包仅以 `devDependencies` 依赖之。
12
+ `dsh-client-test-runtime` 让浏览器功能测试拥有真实的 jsdom 测试台:它把 Cordis 上下文、渲染器拥有的 slot 注册表与生产 `UiSession` 适配器组装在带类型的 Session 和 Workspace Controller 替身周围。默认文件上传替身可满足声明该服务的功能;测试若没有替换它却发起上传,就会明确失败。功能套件无需复制生产渲染器或适配器逻辑,即可检验声明、注册、作用域、store、注入、渲染、更新与销毁。套件通过带类型 fixture 发布 Session 生命周期状态、Workspace 状态、projection 值与 Conversation 事件,再使用局部 DOM 快照根、限定范围的 Testing Library 查询与自明的服务缺失检查。它不属于产品插件图(无 `dsh.client`);feature 包仅以 `devDependencies` 依赖之。
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-alpha.5",
4
+ "version": "0.1.3-alpha.2",
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-alpha.5",
34
- "@deepseek-ai/dsh-api-workspace-controller": "^0.1.2-alpha.5",
35
- "@deepseek-ai/dsh-attachment": "^0.1.2-alpha.5",
36
- "@deepseek-ai/dsh-client-connection": "^0.1.2-alpha.5",
37
- "@deepseek-ai/dsh-client-store": "^0.1.2-alpha.5",
38
- "@deepseek-ai/dsh-client-ui-chat": "^0.1.2-alpha.5",
39
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.2-alpha.5",
40
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-alpha.5",
41
- "@deepseek-ai/dsh-client-ui-session": "^0.1.2-alpha.5",
42
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.2-alpha.5",
43
- "@deepseek-ai/dsh-session": "^0.1.2-alpha.5",
44
- "@deepseek-ai/dsh-subagent": "^0.1.2-alpha.5",
45
- "@deepseek-ai/dsh-typert-protocol": "^0.1.2-alpha.5",
33
+ "@deepseek-ai/dsh-api-session-controller": "^0.1.3-alpha.2",
34
+ "@deepseek-ai/dsh-attachment": "^0.1.3-alpha.2",
35
+ "@deepseek-ai/dsh-client-connection": "^0.1.3-alpha.2",
36
+ "@deepseek-ai/dsh-client-store": "^0.1.3-alpha.2",
37
+ "@deepseek-ai/dsh-client-ui-chat": "^0.1.3-alpha.2",
38
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.3-alpha.2",
39
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.3-alpha.2",
40
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.3-alpha.2",
41
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.3-alpha.2",
42
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.3-alpha.2",
43
+ "@deepseek-ai/dsh-subagent": "^0.1.3-alpha.2",
44
+ "@deepseek-ai/dsh-session": "^0.1.3-alpha.2",
46
45
  "@deepseek-ai/cordis": "^4.0.2",
47
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.2-alpha.5"
46
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.3-alpha.2",
47
+ "@deepseek-ai/dsh-api-workspace-controller": "^0.1.3-alpha.2"
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-session-controller": "^0.1.2-alpha.5",
55
- "@deepseek-ai/dsh-attachment": "^0.1.2-alpha.5",
56
- "@deepseek-ai/dsh-client-connection": "^0.1.2-alpha.5",
57
- "@deepseek-ai/dsh-api-workspace-controller": "^0.1.2-alpha.5",
58
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-alpha.5",
59
- "@deepseek-ai/dsh-client-ui-chat": "^0.1.2-alpha.5",
60
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.2-alpha.5",
61
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.2-alpha.5",
62
- "@deepseek-ai/dsh-client-store": "^0.1.2-alpha.5",
63
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.2-alpha.5",
64
- "@deepseek-ai/dsh-session": "^0.1.2-alpha.5",
65
- "@deepseek-ai/dsh-subagent": "^0.1.2-alpha.5",
66
- "@deepseek-ai/dsh-typert-protocol": "^0.1.2-alpha.5",
67
- "@deepseek-ai/cordis": "^4.0.2",
68
- "@deepseek-ai/dsh-client-ui-session": "^0.1.2-alpha.5"
54
+ "@deepseek-ai/dsh-api-session-controller": "^0.1.3-alpha.2",
55
+ "@deepseek-ai/dsh-api-workspace-controller": "^0.1.3-alpha.2",
56
+ "@deepseek-ai/dsh-attachment": "^0.1.3-alpha.2",
57
+ "@deepseek-ai/dsh-client-connection": "^0.1.3-alpha.2",
58
+ "@deepseek-ai/dsh-client-store": "^0.1.3-alpha.2",
59
+ "@deepseek-ai/dsh-client-ui-chat": "^0.1.3-alpha.2",
60
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.3-alpha.2",
61
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.3-alpha.2",
62
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.3-alpha.2",
63
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.3-alpha.2",
64
+ "@deepseek-ai/dsh-session": "^0.1.3-alpha.2",
65
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.3-alpha.2",
66
+ "@deepseek-ai/dsh-subagent": "^0.1.3-alpha.2",
67
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.3-alpha.2",
68
+ "@deepseek-ai/cordis": "^4.0.2"
69
69
  },
70
70
  "files": [
71
71
  "lib/index.js",