import { test } from 'node:test'; import assert from 'node:assert/strict'; import { classifyEvent } from '../src/events.js'; const opts = { ownerLogin: 'selimaj-dev', triggerPhrase: '@claude' }; function issueCommentPayload(overrides = {}) { return { action: 'created', comment: { user: { login: 'selimaj-dev' }, body: '@claude please fix this' }, issue: { number: 42, title: 'Bug', body: 'It is broken', pull_request: undefined }, repository: { full_name: 'selimaj-dev/repo', default_branch: 'main' }, ...overrides, }; } test('triggers on an issue comment from the owner mentioning the phrase', () => { const { trigger, reason } = classifyEvent('issue_comment', issueCommentPayload(), opts); assert.equal(reason, null); assert.deepEqual(trigger, { repo: 'selimaj-dev/repo', issueNumber: 42, issueTitle: 'Bug', issueBody: 'It is broken', isPullRequest: false, defaultBranch: 'main', requestText: '@claude please fix this', author: 'selimaj-dev', }); }); test('marks isPullRequest true when issue.pull_request is present', () => { const payload = issueCommentPayload({ issue: { number: 7, title: 'PR', body: '', pull_request: { url: 'x' } } }); const { trigger } = classifyEvent('issue_comment', payload, opts); assert.equal(trigger.isPullRequest, true); }); test('ignores comments not from the configured owner', () => { const payload = issueCommentPayload({ comment: { user: { login: 'someone-else' }, body: '@claude do it' } }); const { trigger, reason } = classifyEvent('issue_comment', payload, opts); assert.equal(trigger, null); assert.match(reason, /is not the configured owner/); }); test('ignores comments without the trigger phrase', () => { const payload = issueCommentPayload({ comment: { user: { login: 'selimaj-dev' }, body: 'just a note' } }); const { trigger, reason } = classifyEvent('issue_comment', payload, opts); assert.equal(trigger, null); assert.match(reason, /trigger phrase/); }); test('ignores non-created issue_comment actions', () => { const payload = issueCommentPayload({ action: 'deleted' }); const { trigger, reason } = classifyEvent('issue_comment', payload, opts); assert.equal(trigger, null); assert.match(reason, /not handled/); }); test('triggers on a new issue whose body mentions the phrase', () => { const payload = { action: 'opened', issue: { number: 1, title: 'New issue', body: 'please @claude help', user: { login: 'selimaj-dev' } }, repository: { full_name: 'selimaj-dev/repo', default_branch: 'main' }, }; const { trigger } = classifyEvent('issues', payload, opts); assert.ok(trigger); assert.equal(trigger.requestText, 'please @claude help'); }); test('ignores unrelated event names', () => { const { trigger, reason } = classifyEvent('push', {}, opts); assert.equal(trigger, null); assert.match(reason, /not handled/); }); test('ignores null/undefined payload without throwing', () => { assert.doesNotThrow(() => classifyEvent('issue_comment', null, opts)); assert.doesNotThrow(() => classifyEvent('issue_comment', undefined, opts)); }); test('ignores payload missing repository/issue info', () => { const payload = issueCommentPayload({ repository: { full_name: undefined } }); const { trigger, reason } = classifyEvent('issue_comment', payload, opts); assert.equal(trigger, null); assert.match(reason, /missing repository or issue/); }); test('defaults default_branch to main when absent', () => { const payload = issueCommentPayload({ repository: { full_name: 'a/b', default_branch: undefined } }); const { trigger } = classifyEvent('issue_comment', payload, opts); assert.equal(trigger.defaultBranch, 'main'); }); function pullRequestPayload(overrides = {}) { return { action: 'opened', pull_request: { number: 5, title: 'Add feature', body: 'please @claude review', user: { login: 'selimaj-dev' } }, repository: { full_name: 'selimaj-dev/repo', default_branch: 'main' }, ...overrides, }; } test('triggers on a new pull request whose body mentions the phrase', () => { const { trigger, reason } = classifyEvent('pull_request', pullRequestPayload(), opts); assert.equal(reason, null); assert.deepEqual(trigger, { repo: 'selimaj-dev/repo', issueNumber: 5, issueTitle: 'Add feature', issueBody: 'please @claude review', isPullRequest: true, defaultBranch: 'main', requestText: 'please @claude review', author: 'selimaj-dev', }); }); test('triggers on an edited pull request body', () => { const { trigger } = classifyEvent('pull_request', pullRequestPayload({ action: 'edited' }), opts); assert.ok(trigger); }); test('ignores pull_request actions other than opened/edited', () => { const { trigger, reason } = classifyEvent('pull_request', pullRequestPayload({ action: 'closed' }), opts); assert.equal(trigger, null); assert.match(reason, /not handled/); }); test('ignores pull requests not from the configured owner', () => { const payload = pullRequestPayload({ pull_request: { number: 5, title: 'x', body: '@claude help', user: { login: 'someone-else' } } }); const { trigger, reason } = classifyEvent('pull_request', payload, opts); assert.equal(trigger, null); assert.match(reason, /is not the configured owner/); }); function pullRequestReviewCommentPayload(overrides = {}) { return { action: 'created', comment: { user: { login: 'selimaj-dev' }, body: '@claude fix this line' }, pull_request: { number: 9, title: 'PR title', body: 'pr description' }, repository: { full_name: 'selimaj-dev/repo', default_branch: 'main' }, ...overrides, }; } test('triggers on a pull request review (inline) comment mentioning the phrase', () => { const { trigger, reason } = classifyEvent('pull_request_review_comment', pullRequestReviewCommentPayload(), opts); assert.equal(reason, null); assert.deepEqual(trigger, { repo: 'selimaj-dev/repo', issueNumber: 9, issueTitle: 'PR title', issueBody: 'pr description', isPullRequest: true, defaultBranch: 'main', requestText: '@claude fix this line', author: 'selimaj-dev', }); }); test('ignores non-created pull_request_review_comment actions', () => { const { trigger, reason } = classifyEvent( 'pull_request_review_comment', pullRequestReviewCommentPayload({ action: 'deleted' }), opts, ); assert.equal(trigger, null); assert.match(reason, /not handled/); }); function pullRequestReviewPayload(overrides = {}) { return { action: 'submitted', review: { user: { login: 'selimaj-dev' }, body: '@claude address these comments' }, pull_request: { number: 11, title: 'PR title', body: 'pr description' }, repository: { full_name: 'selimaj-dev/repo', default_branch: 'main' }, ...overrides, }; } test('triggers on a submitted pull request review mentioning the phrase', () => { const { trigger, reason } = classifyEvent('pull_request_review', pullRequestReviewPayload(), opts); assert.equal(reason, null); assert.equal(trigger.requestText, '@claude address these comments'); assert.equal(trigger.isPullRequest, true); assert.equal(trigger.issueNumber, 11); }); test('ignores pull_request_review without the trigger phrase', () => { const payload = pullRequestReviewPayload({ review: { user: { login: 'selimaj-dev' }, body: 'looks good' } }); const { trigger, reason } = classifyEvent('pull_request_review', payload, opts); assert.equal(trigger, null); assert.match(reason, /trigger phrase/); });