惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
B
Blog RSS Feed
美团技术团队
博客园 - 【当耐特】
C
Check Point Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
M
MIT News - Artificial intelligence
aimingoo的专栏
aimingoo的专栏
J
Java Code Geeks
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 司徒正美
T
Tailwind CSS Blog
Last Week in AI
Last Week in AI
Google DeepMind News
Google DeepMind News
D
DataBreaches.Net
人人都是产品经理
人人都是产品经理
N
Netflix TechBlog - Medium
Vercel News
Vercel News
P
Proofpoint News Feed
IT之家
IT之家
I
InfoQ
腾讯CDC
H
Hackread – Cybersecurity News, Data Breaches, AI and More

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
test: tighten twitch status assertions · openclaw/opencla...
shakkernerd · 2026-05-11 · via Recent Commits to openclaw:main

@@ -32,30 +32,58 @@ function createSimpleTwitchConfig(overrides: Record<string, unknown>) {

3232

};

3333

}

343435+

function expectSingleIssue(

36+

issues: ReturnType<typeof collectTwitchStatusIssues>,

37+

expected: ReturnType<typeof collectTwitchStatusIssues>[number],

38+

): void {

39+

expect(issues).toEqual([expected]);

40+

}

41+42+

function expectIssues(

43+

issues: ReturnType<typeof collectTwitchStatusIssues>,

44+

expected: ReturnType<typeof collectTwitchStatusIssues>,

45+

): void {

46+

expect(issues).toEqual(expected);

47+

}

48+49+

function neverConnectedIssue(): ReturnType<typeof collectTwitchStatusIssues>[number] {

50+

return {

51+

channel: "twitch",

52+

accountId: "default",

53+

kind: "runtime",

54+

message: "Account has never connected successfully",

55+

fix: "Start the Twitch gateway to begin receiving messages. Check logs for connection errors.",

56+

};

57+

}

58+3559

describe("status", () => {

3660

describe("collectTwitchStatusIssues", () => {

3761

it("should detect unconfigured accounts", () => {

3862

const snapshots: ChannelAccountSnapshot[] = [createSnapshot({ configured: false })];

39634064

const issues = collectTwitchStatusIssues(snapshots);

416542-

expect(issues.length).toBeGreaterThan(0);

43-

expect(issues[0]?.kind).toBe("config");

44-

expect(issues[0]?.message).toContain("not properly configured");

66+

expectSingleIssue(issues, {

67+

channel: "twitch",

68+

accountId: "default",

69+

kind: "config",

70+

message: "Twitch account is not properly configured",

71+

fix: "Add required fields: username, accessToken, and clientId to your account configuration",

72+

});

4573

});

46744775

it("should detect disabled accounts", () => {

4876

const snapshots: ChannelAccountSnapshot[] = [createSnapshot({ enabled: false })];

49775078

const issues = collectTwitchStatusIssues(snapshots);

517952-

expect(issues.length).toBeGreaterThan(0);

53-

expect(issues).toContainEqual(

54-

expect.objectContaining({

55-

kind: "config",

56-

message: "Twitch account is disabled",

57-

}),

58-

);

80+

expectSingleIssue(issues, {

81+

channel: "twitch",

82+

accountId: "default",

83+

kind: "config",

84+

message: "Twitch account is disabled",

85+

fix: "Set enabled: true in your account configuration to enable this account",

86+

});

5987

});

60886189

it("should detect missing clientId when account configured (simplified config)", () => {

@@ -68,12 +96,16 @@ describe("status", () => {

68966997

const issues = collectTwitchStatusIssues(snapshots, () => mockCfg as never);

709871-

expect(issues).toContainEqual(

72-

expect.objectContaining({

99+

expectIssues(issues, [

100+

{

101+

channel: "twitch",

102+

accountId: "default",

73103

kind: "config",

74104

message: "Twitch client ID is required",

75-

}),

76-

);

105+

fix: "Add clientId to your Twitch account configuration (from Twitch Developer Portal)",

106+

},

107+

neverConnectedIssue(),

108+

]);

77109

});

7811079111

it("should warn about oauth: prefix in token (simplified config)", () => {

@@ -86,12 +118,16 @@ describe("status", () => {

8611887119

const issues = collectTwitchStatusIssues(snapshots, () => mockCfg as never);

8812089-

expect(issues).toContainEqual(

90-

expect.objectContaining({

121+

expectIssues(issues, [

122+

{

123+

channel: "twitch",

124+

accountId: "default",

91125

kind: "config",

92126

message: "Token contains 'oauth:' prefix (will be stripped)",

93-

}),

94-

);

127+

fix: "The 'oauth:' prefix is optional. You can use just the token value, or keep it as-is (it will be normalized automatically).",

128+

},

129+

neverConnectedIssue(),

130+

]);

95131

});

9613297133

it("should detect clientSecret without refreshToken (simplified config)", () => {

@@ -106,12 +142,23 @@ describe("status", () => {

106142107143

const issues = collectTwitchStatusIssues(snapshots, () => mockCfg as never);

108144109-

expect(issues).toContainEqual(

110-

expect.objectContaining({

145+

expectIssues(issues, [

146+

{

147+

channel: "twitch",

148+

accountId: "default",

149+

kind: "config",

150+

message: "Token contains 'oauth:' prefix (will be stripped)",

151+

fix: "The 'oauth:' prefix is optional. You can use just the token value, or keep it as-is (it will be normalized automatically).",

152+

},

153+

{

154+

channel: "twitch",

155+

accountId: "default",

111156

kind: "config",

112157

message: "clientSecret provided without refreshToken",

113-

}),

114-

);

158+

fix: "For automatic token refresh, provide both clientSecret and refreshToken. Otherwise, clientSecret is not needed.",

159+

},

160+

neverConnectedIssue(),

161+

]);

115162

});

116163117164

it("should detect empty allowFrom array (simplified config)", () => {

@@ -125,12 +172,16 @@ describe("status", () => {

125172126173

const issues = collectTwitchStatusIssues(snapshots, () => mockCfg as never);

127174128-

expect(issues).toContainEqual(

129-

expect.objectContaining({

175+

expectIssues(issues, [

176+

{

177+

channel: "twitch",

178+

accountId: "default",

130179

kind: "config",

131180

message: "allowFrom is configured but empty",

132-

}),

133-

);

181+

fix: "Either add user IDs to allowFrom, remove the allowFrom field, or use allowedRoles instead.",

182+

},

183+

neverConnectedIssue(),

184+

]);

134185

});

135186136187

it("should detect allowedRoles 'all' with allowFrom conflict (simplified config)", () => {

@@ -145,12 +196,16 @@ describe("status", () => {

145196146197

const issues = collectTwitchStatusIssues(snapshots, () => mockCfg as never);

147198148-

expect(issues).toContainEqual(

149-

expect.objectContaining({

199+

expectIssues(issues, [

200+

{

201+

channel: "twitch",

202+

accountId: "default",

150203

kind: "intent",

151204

message: "allowedRoles is set to 'all' but allowFrom is also configured",

152-

}),

153-

);

205+

fix: "When allowedRoles is 'all', the allowFrom list is not needed. Remove allowFrom or set allowedRoles to specific roles.",

206+

},

207+

neverConnectedIssue(),

208+

]);

154209

});

155210156211

it("should detect runtime errors", () => {

@@ -160,12 +215,16 @@ describe("status", () => {

160215161216

const issues = collectTwitchStatusIssues(snapshots);

162217163-

expect(issues).toContainEqual(

164-

expect.objectContaining({

218+

expectIssues(issues, [

219+

{

220+

channel: "twitch",

221+

accountId: "default",

165222

kind: "runtime",

166223

message: "Last error: Connection timeout",

167-

}),

168-

);

224+

fix: "Check your token validity and network connection. Ensure the bot has the required OAuth scopes.",

225+

},

226+

neverConnectedIssue(),

227+

]);

169228

});

170229171230

it("should detect accounts that never connected", () => {

@@ -179,12 +238,13 @@ describe("status", () => {

179238180239

const issues = collectTwitchStatusIssues(snapshots);

181240182-

expect(issues).toContainEqual(

183-

expect.objectContaining({

184-

kind: "runtime",

185-

message: "Account has never connected successfully",

186-

}),

187-

);

241+

expectSingleIssue(issues, {

242+

channel: "twitch",

243+

accountId: "default",

244+

kind: "runtime",

245+

message: "Account has never connected successfully",

246+

fix: "Start the Twitch gateway to begin receiving messages. Check logs for connection errors.",

247+

});

188248

});

189249190250

it("should detect long-running connections", () => {

@@ -199,12 +259,13 @@ describe("status", () => {

199259200260

const issues = collectTwitchStatusIssues(snapshots);

201261202-

expect(issues).toContainEqual(

203-

expect.objectContaining({

204-

kind: "runtime",

205-

message: "Connection has been running for 8 days",

206-

}),

207-

);

262+

expectSingleIssue(issues, {

263+

channel: "twitch",

264+

accountId: "default",

265+

kind: "runtime",

266+

message: "Connection has been running for 8 days",

267+

fix: "Consider restarting the connection periodically to refresh the connection. Twitch tokens may expire after long periods.",

268+

});

208269

});

209270210271

it("should handle empty snapshots array", () => {

@@ -225,13 +286,13 @@ describe("status", () => {

225286226287

const issues = collectTwitchStatusIssues(snapshots);

227288228-

expect(issues).toEqual([

229-

expect.objectContaining({

230-

accountId: "unknown",

231-

kind: "config",

232-

message: "Twitch account is not properly configured",

233-

}),

234-

]);

289+

expectSingleIssue(issues, {

290+

channel: "twitch",

291+

accountId: "unknown",

292+

kind: "config",

293+

message: "Twitch account is not properly configured",

294+

fix: "Add required fields: username, accessToken, and clientId to your account configuration",

295+

});

235296

});

236297

});

237298

});