Skip to content

[nightshift] Test Gap Finder #2

@nightshift-micr

Description

@nightshift-micr

[nightshift] Test Gap Finder: micr-dev/projects

Summary

micr-dev/projects is a Next.js 16 portfolio/showcase site with zero test coverage. No test framework is installed, no test files exist, and no test scripts are defined in package.json.

Repository Stats

  • Framework: Next.js 16.1.6, React 19, TypeScript 5.9
  • Source files: 4 (page.tsx, layout.tsx, smooth-scroll.tsx, skiper80.tsx)
  • Total LOC: ~210 lines of application code
  • Test files: 0
  • Test dependencies: None

Findings

P1 — No test infrastructure exists

No test framework (Jest, Vitest, React Testing Library) is installed in package.json. The scripts section has no test command.

Impact: Any code change risks regressions with no automated safety net.

Recommendation: Install Vitest + React Testing Library (@testing-library/react, @testing-library/jest-dom). Add a test script to package.json.

P2 — getRepoSections() parser untested (app/page.tsx, lines 10-38)

The getRepoSections() function parses REPO.md with custom string logic:

  • Splits on \r?\n, trims lines, skips blanks and # Repo List header
  • Parses ## prefixed sections into {heading, titles[]} structs
  • Accumulates titles into the current section

Untested edge cases:

  • Empty REPO.md file → returns [] (no error)
  • REPO.md with titles before any ## heading → titles silently dropped
  • Lines with only whitespace → trimmed to empty, skipped
  • Malformed headings like ### or ##No space → not parsed as sections
  • Very large files → memory/performance

Recommendation: Add unit tests for getRepoSections() covering empty input, no-sections input, malformed headings, and typical multi-section input.

P2 — Skiper80 component state logic untested (components/skiper/skiper80.tsx)

The Skiper80 component (lines 22-84) has state-dependent behavior:

  • isHoveredIndex defaults to 0, cycles through placeholderImages
  • items is computed via sections.flatMap() — image index uses modulo
  • Line 57: isHoveredIndex == index uses loose equality (should be ===)
  • items.indexOf(title) on line 50 is O(n) and could return -1 for duplicates

Untested behaviors:

  • Empty sections array → no items rendered, no crash
  • Sections with empty titles arrays → section heading shown, no items
  • Duplicate titles across sections → indexOf returns first match
  • Index wrapping via % placeholderImages.length

Recommendation: Add component tests with React Testing Library. Test hover state changes, empty input, and duplicate title handling.

P3 — SmoothScroll cleanup untested (app/smooth-scroll.tsx, lines 6-33)

The Lenis smooth scroll integration:

  • Creates requestAnimationFrame loop on mount
  • Cleans up via cancelAnimationFrame + lenis.destroy() on unmount
  • No error handling if Lenis constructor fails (e.g., SSR mismatch)

Recommendation: Test that cleanup properly cancels animation frames and destroys Lenis instance.

P3 — Loose equality operator (skiper80.tsx, line 57)

style={{ opacity: isHoveredIndex == index ? 1 : 0.5 }}

Uses == instead of ===. While both operands are numbers (so behavior is identical), this is inconsistent with TypeScript best practices and the rest of the codebase.

Priority Recommendations

  1. Install Vitest + React Testing Library — foundational infrastructure
  2. Test getRepoSections() parser — pure function, easy to unit test, highest ROI
  3. Test Skiper80 rendering — verify empty/edge-case inputs
  4. Add test script to package.json — enables CI integration

Estimated Test Coverage Gap

Module Current Target
app/page.tsx 0% 80%+
components/skiper/skiper80.tsx 0% 70%+
app/smooth-scroll.tsx 0% 60%+
app/layout.tsx 0% N/A (metadata only)
Overall 0% 70%+

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions