From 62a0356307e31995e656bf788a7088f479ec0639 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2026 04:59:57 +0000 Subject: [PATCH] test(utils): expand unit test coverage for visitor-changelog utilities Adds comprehensive Vitest unit tests in src/utils/visitor-changelog.test.ts for visitor-changelog parsing and transformation functions (toVisitorChangelogTitle, stripChangelogChrome, toVisitorReleaseBody, toVisitorRelease). Covers edge cases including empty inputs, custom PR maps, internal agent filtering, fallback formatting, and body processing without bullet lists. Records quality findings in .Jules/vantage.md. Co-authored-by: alehar9320 <5390430+alehar9320@users.noreply.github.com> --- .Jules/vantage.md | 2 + src/utils/visitor-changelog.test.ts | 118 ++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 src/utils/visitor-changelog.test.ts diff --git a/.Jules/vantage.md b/.Jules/vantage.md index e63beebe..6e9850b5 100644 --- a/.Jules/vantage.md +++ b/.Jules/vantage.md @@ -13,3 +13,5 @@ ## 2026-05-15 - Standardizing Telemetry Resilience and Verifying Infrastructure Mocks | **Learning:** Telemetry must capture the full context of unknown errors via `String(e)` to avoid masking failure signals, and re-exporting mocks requires explicit execution to register in coverage reports. | **Action:** Updated `src/utils/github-releases.ts` to use `String(error)` in catch blocks and added an `exerciseMock` helper to `src/__tests__/mocks/astro-zod.ts` to achieve 100% coverage. ## 2026-05-20 - Hardening Telemetry Verification and Refining Stream Types | **Learning:** Index-based assertions in telemetry tests are brittle; using `.find()` ensures robust verification. Standardizing on `String(error)` across all API catch blocks prevents context loss during failure events. | **Action:** Refactored `chat-api.test.ts` and `github-releases.test.ts` to use search-based spy assertions, and added explicit return types to `chat-stream.ts` to resolve Astro compiler hints. + +## 2026-05-24 - Comprehensive Unit Testing for Visitor Changelog Formatting | **Learning:** Single-pass Edge transformations require dedicated unit tests covering edge cases like empty inputs, internal agent filtering, and fallback formatting to prevent silent regressions in SSR release streams. | **Action:** Added `src/utils/visitor-changelog.test.ts` to test `toVisitorChangelogTitle`, `stripChangelogChrome`, `toVisitorReleaseBody`, and `toVisitorRelease`. diff --git a/src/utils/visitor-changelog.test.ts b/src/utils/visitor-changelog.test.ts new file mode 100644 index 00000000..ee4715fb --- /dev/null +++ b/src/utils/visitor-changelog.test.ts @@ -0,0 +1,118 @@ +import { describe, expect, it } from 'vitest'; + +import { + stripChangelogChrome, + toVisitorChangelogTitle, + toVisitorRelease, + toVisitorReleaseBody, +} from './visitor-changelog'; + +describe('visitor-changelog utilities', () => { + describe('stripChangelogChrome', () => { + it('handles empty and whitespace-only strings', () => { + expect(stripChangelogChrome('')).toBe(''); + expect(stripChangelogChrome(' ')).toBe(''); + }); + + it('strips commit SHA, conventional commit prefix, and PR suffix', () => { + expect(stripChangelogChrome('a1b2c3d feat(ui): add new button (#123)')).toBe( + 'add new button' + ); + expect(stripChangelogChrome('fix: resolve alignment issue (#456)')).toBe( + 'resolve alignment issue' + ); + expect(stripChangelogChrome('chore(deps): update packages')).toBe('update packages'); + }); + + it('collapses multiple whitespace characters', () => { + expect(stripChangelogChrome('feat: multiple spaces ')).toBe('multiple spaces'); + }); + }); + + describe('toVisitorChangelogTitle', () => { + it('returns empty string for empty input', () => { + expect(toVisitorChangelogTitle('')).toBe(''); + expect(toVisitorChangelogTitle(' ')).toBe(''); + }); + + it('looks up known PR numbers', () => { + expect(toVisitorChangelogTitle('feat: add a live RSS feed (#520)')).toBe( + 'RSS feed of the work' + ); + }); + + it('looks up known subjects when PR number is omitted', () => { + expect(toVisitorChangelogTitle('add a live RSS feed for the work')).toBe( + 'RSS feed of the work' + ); + }); + + it('formats unknown commits by stripping chrome and capitalizing the first letter', () => { + expect( + toVisitorChangelogTitle('f1a2b3c feat(nav): improve keyboard accessibility (#999)') + ).toBe('Improve keyboard accessibility'); + }); + + it('returns already clean visitor titles as-is', () => { + expect(toVisitorChangelogTitle('Clean visitor title without chrome')).toBe( + 'Clean visitor title without chrome' + ); + }); + + it('falls back gracefully when chrome stripping leaves an empty subject', () => { + expect(toVisitorChangelogTitle('a1b2c3d feat:')).toBe('Feat:'); + }); + }); + + describe('toVisitorReleaseBody', () => { + it('returns empty string for empty body', () => { + expect(toVisitorReleaseBody('')).toBe(''); + expect(toVisitorReleaseBody(' ')).toBe(''); + }); + + it('converts bullet point lines into visitor titles', () => { + const input = + '- 520 feat: add a live RSS feed for the work (#520)\n* 518 feat: add a working web app manifest (#518)'; + const output = toVisitorReleaseBody(input); + expect(output).toBe('- RSS feed of the work\n- Web app manifest'); + }); + + it('filters out internal agent or tool items from bullet lists', () => { + const input = + '- feat: add public feature\n- chore(jules): internal sync\n- refactor(engine): internal logic'; + const output = toVisitorReleaseBody(input); + expect(output).toBe('- Add public feature'); + }); + + it('falls back to toVisitorChangelogTitle if body contains no bullet items', () => { + const input = 'a1b2c3d feat: add a live RSS feed for the work (#520)'; + expect(toVisitorReleaseBody(input)).toBe('RSS feed of the work'); + }); + + it('falls back to toVisitorChangelogTitle if all bullet items are filtered as internal', () => { + const input = '- chore(jules): internal update\n- refactor(engine): backend tweak'; + expect(toVisitorReleaseBody(input)).toBe( + '- chore(jules): internal update\n- refactor(engine): backend tweak' + ); + }); + }); + + describe('toVisitorRelease', () => { + it('transforms the release body while preserving other release properties', () => { + const release = { + version: 'v1.0.0', + publishedAt: '2026-05-01T12:00:00Z', + url: 'https://example.com/release/v1.0.0', + body: '- 520 feat: add a live RSS feed for the work (#520)', + }; + + const result = toVisitorRelease(release); + expect(result).toEqual({ + version: 'v1.0.0', + publishedAt: '2026-05-01T12:00:00Z', + url: 'https://example.com/release/v1.0.0', + body: '- RSS feed of the work', + }); + }); + }); +});