Files
EJClaw/src/github-ci.test.ts
Eyejoker 7b63ba859d fix: deduplicate CI watchers and remove task ID from watcher prompts
Prevent duplicate CI completion notifications in paired rooms by checking
for existing active watchers with the same channel+provider+metadata before
creating a new one. Remove Task ID from watcher prompt construction to
avoid router secret redaction (task- IDs contain sk- pattern), passing
EJCLAW_RUNTIME_TASK_ID via env var instead and making cancel_task
auto-resolve when task_id is omitted.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 20:57:59 +09:00

146 lines
3.4 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from 'vitest';
const { execFileMock } = vi.hoisted(() => ({
execFileMock: vi.fn(),
}));
vi.mock('child_process', () => ({
execFile: execFileMock,
}));
import {
checkGitHubActionsRun,
parseGitHubCiMetadata,
serializeGitHubCiMetadata,
} from './github-ci.js';
describe('github-ci helpers', () => {
afterEach(() => {
execFileMock.mockReset();
});
it('round-trips GitHub CI metadata', () => {
const raw = serializeGitHubCiMetadata({
repo: 'owner/repo',
run_id: 123456,
poll_count: 1,
});
expect(parseGitHubCiMetadata(raw)).toEqual({
repo: 'owner/repo',
run_id: 123456,
poll_count: 1,
consecutive_errors: undefined,
});
expect(parseGitHubCiMetadata('{"repo":"","run_id":0}')).toBeNull();
});
it('returns non-terminal status for in-progress runs', async () => {
execFileMock.mockImplementation(
(
_cmd: string,
_args: string[],
_opts: unknown,
cb: (error: Error | null, stdout: string, stderr: string) => void,
) => {
cb(
null,
JSON.stringify({
status: 'in_progress',
conclusion: null,
}),
'',
);
},
);
await expect(
checkGitHubActionsRun({
prompt: `
[BACKGROUND CI WATCH]
Watch target:
GitHub Actions run 123456
Check instructions:
Managed by host-driven watcher.
`.trim(),
ci_metadata: JSON.stringify({
repo: 'owner/repo',
run_id: 123456,
}),
}),
).resolves.toEqual({
terminal: false,
resultSummary: 'GitHub Actions run 123456 is in_progress',
});
});
it('renders a concise completion message for terminal runs', async () => {
execFileMock
.mockImplementationOnce(
(
_cmd: string,
_args: string[],
_opts: unknown,
cb: (error: Error | null, stdout: string, stderr: string) => void,
) => {
cb(
null,
JSON.stringify({
status: 'completed',
conclusion: 'failure',
name: 'CI',
html_url: 'https://github.com/owner/repo/actions/runs/654321',
head_branch: 'main',
}),
'',
);
},
)
.mockImplementationOnce(
(
_cmd: string,
_args: string[],
_opts: unknown,
cb: (error: Error | null, stdout: string, stderr: string) => void,
) => {
cb(
null,
JSON.stringify({
jobs: [
{ name: 'build', conclusion: 'success' },
{ name: 'test', conclusion: 'failure' },
],
}),
'',
);
},
);
const result = await checkGitHubActionsRun({
prompt: `
[BACKGROUND CI WATCH]
Watch target:
GitHub Actions run 654321
Check instructions:
Managed by host-driven watcher.
`.trim(),
ci_metadata: JSON.stringify({
repo: 'owner/repo',
run_id: 654321,
}),
});
expect(result.terminal).toBe(true);
expect(result.resultSummary).toContain('실패');
expect(result.completionMessage).toContain(
'CI 완료: GitHub Actions run 654321',
);
expect(result.completionMessage).toContain('판정: 실패');
expect(result.completionMessage).toContain('- 실패 job: test');
});
});