Skip to content

Commit b8ae18e

Browse files
committed
chore: track tests in repository
1 parent 729ae5c commit b8ae18e

56 files changed

Lines changed: 9043 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ Dev-docs/
2121
CLAUDE.md
2222
localdocs/
2323
docs/
24-
tests/
2524

2625
# Local DB (never commit)
2726
*.sqlite

tests/a2aMessageItem.test.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import test from 'node:test';
2+
import assert from 'node:assert/strict';
3+
import React from 'react';
4+
import { renderToStaticMarkup } from 'react-dom/server';
5+
import A2AMessageItem from '../src/renderer/components/cowork/A2AMessageItem';
6+
7+
test('A2A delivery messages render the delivery result text instead of the raw envelope', () => {
8+
const payload = {
9+
paymentTxid: 'abc123',
10+
servicePinId: null,
11+
serviceName: 'Weather Query',
12+
result: '## 香港当前天气\n- 晴朗\n- 25°C',
13+
deliveredAt: 1774440568,
14+
};
15+
16+
const markup = renderToStaticMarkup(
17+
<A2AMessageItem
18+
message={{
19+
id: 'delivery-1',
20+
type: 'assistant',
21+
content: `[DELIVERY] ${JSON.stringify(payload)}`,
22+
timestamp: 1774440568000,
23+
metadata: {
24+
direction: 'incoming',
25+
senderName: 'AI_Sunny',
26+
},
27+
}}
28+
peerName="AI_Sunny"
29+
metabotName="AI_Ligong"
30+
/>,
31+
);
32+
33+
assert.match(markup, /## /);
34+
assert.match(markup, /- /);
35+
assert.doesNotMatch(markup, /\[DELIVERY\]/);
36+
assert.doesNotMatch(markup, /&quot;paymentTxid&quot;/);
37+
assert.doesNotMatch(markup, /<h2[^>]*>/);
38+
});
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import assert from 'node:assert/strict';
2+
import fs from 'node:fs';
3+
import os from 'node:os';
4+
import path from 'node:path';
5+
import test from 'node:test';
6+
import { createRequire } from 'node:module';
7+
8+
const require = createRequire(import.meta.url);
9+
10+
test('detects infographic mode from payload and writes a stable output path', () => {
11+
const { detectMode } = require('../SKILLs/baoyu-image-studio/scripts/lib/promptBuilder.js');
12+
const { buildOutputPath } = require('../SKILLs/baoyu-image-studio/scripts/lib/outputPaths.js');
13+
14+
const mode = detectMode({
15+
mode: 'infographic',
16+
topic: 'UTXO 解释',
17+
bullets: ['定义', '流程', '风险'],
18+
});
19+
const outputPath = buildOutputPath({
20+
cwd: '/tmp/demo',
21+
mode,
22+
title: 'UTXO 解释',
23+
extension: '.png',
24+
now: () => 1700000000000,
25+
});
26+
27+
assert.equal(mode, 'infographic');
28+
assert.match(outputPath, /utxo/i);
29+
assert.match(outputPath, /\.png$/);
30+
assert.match(outputPath, /baoyu-image-studio/);
31+
});
32+
33+
test('buildPrompt shapes infographic content with bullets and style hints', () => {
34+
const { buildPrompt } = require('../SKILLs/baoyu-image-studio/scripts/lib/promptBuilder.js');
35+
36+
const prompt = buildPrompt({
37+
mode: 'infographic',
38+
topic: 'UTXO 是什么',
39+
bullets: ['定义', '交易流程', '双花风险'],
40+
style: 'clean',
41+
});
42+
43+
assert.match(prompt, /UTXO/);
44+
assert.match(prompt, //);
45+
assert.match(prompt, //);
46+
assert.match(prompt, /clean/i);
47+
});
48+
49+
test('providerResolver returns bridge providers before env-only providers', () => {
50+
const { resolveProviderConfig } = require('../SKILLs/baoyu-image-studio/scripts/lib/providerResolver.js');
51+
52+
const result = resolveProviderConfig({
53+
env: {
54+
BAOYU_IMAGE_PROVIDER: 'openrouter',
55+
OPENROUTER_API_KEY: 'router-key',
56+
OPENROUTER_IMAGE_MODEL: 'google/gemini-3.1-flash-image-preview',
57+
ARK_API_KEY: 'ark-key',
58+
},
59+
});
60+
61+
assert.equal(result.provider, 'openrouter');
62+
assert.equal(result.model, 'google/gemini-3.1-flash-image-preview');
63+
});
64+
65+
test('falls back to seedream when no bridge provider is configured but ARK_API_KEY exists', () => {
66+
const { resolveProviderConfig } = require('../SKILLs/baoyu-image-studio/scripts/lib/providerResolver.js');
67+
68+
const result = resolveProviderConfig({
69+
env: {
70+
ARK_API_KEY: 'ark-key',
71+
SEEDREAM_IMAGE_MODEL: 'doubao-seedream-5-0-260128',
72+
},
73+
});
74+
75+
assert.equal(result.provider, 'seedream');
76+
assert.equal(result.model, 'doubao-seedream-5-0-260128');
77+
});
78+
79+
test('all supported provider adapters export a generateImage function', () => {
80+
const { loadProviderAdapter } = require('../SKILLs/baoyu-image-studio/scripts/lib/providerResolver.js');
81+
82+
for (const providerId of ['openai', 'google', 'openrouter', 'dashscope', 'replicate', 'jimeng', 'seedream']) {
83+
const adapter = loadProviderAdapter(providerId);
84+
assert.equal(typeof adapter.generateImage, 'function', `${providerId} adapter should export generateImage`);
85+
}
86+
});
87+
88+
test('runWithPayload writes a local image file and returns execution summary', async () => {
89+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'baoyu-image-studio-test-'));
90+
const { runWithPayload } = require('../SKILLs/baoyu-image-studio/scripts/index.js');
91+
92+
const result = await runWithPayload(
93+
{
94+
title: 'Orange Space Cat',
95+
prompt: 'An orange cat floating in space',
96+
mode: 'cover',
97+
},
98+
{
99+
cwd: tempRoot,
100+
env: {
101+
BAOYU_IMAGE_PROVIDER: 'openai',
102+
OPENAI_API_KEY: 'test-key',
103+
},
104+
now: () => 1700000000000,
105+
adapters: {
106+
openai: {
107+
async generateImage() {
108+
return {
109+
bytes: Buffer.from('fake-image'),
110+
extension: '.png',
111+
mimeType: 'image/png',
112+
};
113+
},
114+
},
115+
},
116+
},
117+
);
118+
119+
assert.equal(result.mode, 'cover');
120+
assert.equal(result.provider, 'openai');
121+
assert.equal(path.extname(result.outputPath), '.png');
122+
assert.ok(fs.existsSync(result.outputPath));
123+
assert.equal(fs.readFileSync(result.outputPath, 'utf8'), 'fake-image');
124+
assert.match(result.message, /orange space cat/i);
125+
});
126+
127+
test('runWithPayload throws an actionable error when no supported provider is available', async () => {
128+
const { runWithPayload } = require('../SKILLs/baoyu-image-studio/scripts/index.js');
129+
130+
await assert.rejects(
131+
() =>
132+
runWithPayload(
133+
{
134+
prompt: 'Generate a cover image about UTXO',
135+
},
136+
{
137+
cwd: '/tmp/demo',
138+
env: {},
139+
},
140+
),
141+
/No supported image provider is available/i,
142+
);
143+
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import assert from 'node:assert/strict';
2+
import test from 'node:test';
3+
import { createRequire } from 'node:module';
4+
import path from 'node:path';
5+
6+
const require = createRequire(import.meta.url);
7+
const { SkillManager } = require('../dist-electron/skillManager.js');
8+
9+
process.env.IDBOTS_SKILLS_ROOT = path.resolve(process.cwd(), 'SKILLs');
10+
11+
class MemoryStore {
12+
constructor(initial = {}) {
13+
this.values = { ...initial };
14+
}
15+
16+
get(key) {
17+
return this.values[key];
18+
}
19+
20+
set(key, value) {
21+
this.values[key] = value;
22+
}
23+
}
24+
25+
function createManager(initialStoreValues = {}) {
26+
const store = new MemoryStore(initialStoreValues);
27+
const manager = new SkillManager(() => store);
28+
manager.getBundledSkillsRoot = () => process.env.IDBOTS_SKILLS_ROOT;
29+
return { store, manager };
30+
}
31+
32+
test('listSkills exposes baoyu-image-studio as an enabled built-in skill', () => {
33+
const { manager } = createManager();
34+
const skill = manager.listSkills().find((entry) => entry.id === 'baoyu-image-studio');
35+
36+
assert.ok(skill);
37+
assert.equal(skill.enabled, true);
38+
assert.equal(skill.isBuiltIn, true);
39+
});
40+
41+
test('baoyu-image-studio prompt advertises the four supported image modes', () => {
42+
const { manager } = createManager();
43+
const skill = manager.listSkills().find((entry) => entry.id === 'baoyu-image-studio');
44+
45+
assert.ok(skill);
46+
assert.match(skill.prompt, /generate/i);
47+
assert.match(skill.prompt, /cover/i);
48+
assert.match(skill.prompt, /infographic/i);
49+
assert.match(skill.prompt, /comic/i);
50+
});

0 commit comments

Comments
 (0)