@tbox.cn/app-toolkit 0.2.0 → 0.3.0

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.
@@ -73,10 +73,10 @@ describe('写核心管线(FX-1c)', () => {
73
73
  // 回读逐字等价(GET = PUT = 落盘物)
74
74
  const app = await h.tk.loadApp();
75
75
  expect(app.integration).toEqual(node);
76
- // dryRun + 不同节点 → 不落盘
76
+ // dryRun + 不同节点 → 不落盘;files = 将触碰预览(D35——与真实写逐字对称)
77
77
  const r2 = await h.tk.writeAppIntegration({ provider: 'changed' } as never, { dryRun: true });
78
78
  expect(r2.written).toBe(false);
79
- expect(r2.files).toEqual([]);
79
+ expect(r2.files).toEqual([INTEGRATIONS_FILE]);
80
80
  expect(h.readConfig().provider).toBe('mock-x');
81
81
  });
82
82
 
@@ -102,13 +102,13 @@ describe('写核心管线(FX-1c)', () => {
102
102
  expect(readFileSync(h.credFile('joycity-parking.query'), 'utf8')).toContain('ROTATED-SECOND');
103
103
  });
104
104
 
105
- it('T3 dryRun + credentials(B3 钉死):零落盘 + credentials[] 预览 + files []', async () => {
105
+ it('T3 dryRun + credentials(B3 钉死):零落盘 + credentials[] 预览 + files = 双路径预览(D35)', async () => {
106
106
  const r = await h.tk.writeServiceIntegration('parking.query', { provider: 'joycity' }, {
107
107
  dryRun: true,
108
108
  credentials: { type: 'api-key', values: { apiKey: 'SECRET-DRYRUN' } },
109
109
  });
110
110
  expect(r.written).toBe(false);
111
- expect(r.files).toEqual([]);
111
+ expect(r.files).toEqual([INTEGRATIONS_FILE, 'config/credentials/joycity-parking.query.json']);
112
112
  expect(r.credentials).toEqual([{ stem: 'joycity-parking.query', ref: 'secret://joycity-parking.query', overwrote: false }]);
113
113
  // 凭据目录与 integrations.json 均零变更
114
114
  expect(existsSync(h.credFile('joycity-parking.query'))).toBe(false);
@@ -125,9 +125,31 @@ describe('写核心管线(FX-1c)', () => {
125
125
  credentials: { type: 'api-key', values: { apiKey: 'SHOULD-NOT-WRITE' } },
126
126
  });
127
127
  expect(r.credentials[0].overwrote).toBe(true);
128
+ // D35:no-diff + 同 stem → 仅凭据路径入预览(integrations 节点无变更不入清单)
129
+ expect(r.files).toEqual(['config/credentials/joycity-parking.query.json']);
128
130
  expect(readFileSync(h.credFile('joycity-parking.query'), 'utf8')).toBe(before);
129
131
  });
130
132
 
133
+ it('T-sym dryRun ≡ 真实写(D35 对称性):同 body files 逐字相等 + written 相反 + dryRun 腿磁盘零变更', async () => {
134
+ const node = { provider: 'joycity', config: { baseUrl: 'https://sym.example' } };
135
+ const dry = await h.tk.writeServiceIntegration('parking.query', node, {
136
+ dryRun: true,
137
+ credentials: { type: 'api-key', values: { apiKey: 'SYM-DRY' } },
138
+ });
139
+ expect(dry.written).toBe(false);
140
+ // dryRun 零副作用(integrations 与凭据均零落盘)→ 免重置 harness 直接接真实写
141
+ expect(existsSync(h.credFile('joycity-parking.query'))).toBe(false);
142
+ expect((h.readConfig().services as Record<string, unknown>)['parking.query']).toBeUndefined();
143
+ const real = await h.tk.writeServiceIntegration('parking.query', node, {
144
+ credentials: { type: 'api-key', values: { apiKey: 'SYM-DRY' } },
145
+ });
146
+ expect(real.written).toBe(true);
147
+ expect(real.restartScheduled).toBe(false); // 工厂未注入 onApplied
148
+ // 对称性核心:同 body → files 逐字相等(integrations + 凭据工件双路径)
149
+ expect(dry.files).toEqual(real.files);
150
+ expect(dry.files).toEqual([INTEGRATIONS_FILE, 'config/credentials/joycity-parking.query.json']);
151
+ });
152
+
131
153
  it('T5 严格校验失败次序(A1):400 VALIDATION_FAILED + message 直通 + 凭据零落盘 + integrations 零变更', async () => {
132
154
  h.app.dispose();
133
155
  h = harness({ rejectMarker: '__reject__' });