Skip to content

test(web): starter unit tests for service, header, bottom#76

Merged
fray-cloud merged 2 commits into
devfrom
test/web-starter-suite
Apr 13, 2026
Merged

test(web): starter unit tests for service, header, bottom#76
fray-cloud merged 2 commits into
devfrom
test/web-starter-suite

Conversation

@fray-cloud

@fray-cloud fray-cloud commented Apr 13, 2026

Copy link
Copy Markdown
Owner

Summary

Three small specs covering the most reachable surfaces. The placeholder app/providers.spec.tsx from #30 stays.

src/api/service.spec.ts

Mocks axios at the module boundary (require pattern instead of ES import so axios.create is stubbed before service.ts evaluates). Asserts:

  • the axios instance is created with baseURL: '/api/data-go-kr'
  • getAPI forwards path + props as query params
  • it unwraps the response data envelope

src/components/header.spec.tsx

Mocks next/navigation, front/hooks (useSido), and front/site/home/Count (CountList) so Header can render in isolation. Asserts:

  • the title link renders
  • clicking it calls router.push('/')

src/components/bottom.spec.tsx

Mocks next/navigation (useRouter + usePathname). Asserts:

  • three nav items render with their aria labels
  • clicking '조회하기' fires router.push('/search')
  • the active item picks up the text-primary class when usePathname matches

Test plan

  • npx nx test web: 4 suites, 9 tests, all pass
  • npx nx affected -t lint test build green (5 projects)

🤖 Generated with Claude Code

Summary by Sourcery

Add initial unit test coverage for the web app service API wrapper and key navigation components.

Tests:

  • Add tests for the service API helper to validate axios configuration, query param handling, and response unwrapping.
  • Add isolated unit tests for the header component to verify title rendering and navigation via router.push.
  • Add unit tests for the bottom navigation component to verify nav items, active state styling, and navigation behavior.

Three small specs covering the most reachable surfaces:

- src/api/service.spec.ts — mocks axios at the module boundary
  (require pattern instead of ES import so axios.create is stubbed
  before service.ts evaluates), asserts the proxy baseURL and that
  getAPI forwards path + props as query params and unwraps the
  response data.
- src/components/header.spec.tsx — mocks next/navigation,
  front/hooks (useSido), and front/site/home/Count (CountList) so
  Header can render in isolation; asserts the title link renders
  and clicking it calls router.push('/').
- src/components/bottom.spec.tsx — mocks next/navigation
  (useRouter + usePathname) and asserts the three nav items render
  with their aria labels, that clicking '조회하기' fires
  router.push('/search'), and that the active item picks up the
  text-primary class when usePathname matches.

The placeholder app/providers.spec.tsx from #30 stays.

- nx test web: 4 suites, 9 tests, all pass
- nx affected -t lint test build green (5 projects)
@sourcery-ai

sourcery-ai Bot commented Apr 13, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds initial Jest/React Testing Library unit tests for the web app’s API service wrapper and Header/Bottom layout components, using targeted mocking of external dependencies to verify routing, rendering, and axios configuration/behavior.

Sequence diagram for getAPI axios mocking and call behavior

sequenceDiagram
    participant Jest
    participant axiosModule as axios
    participant serviceSpec as service_spec
    participant serviceModule as service
    participant axiosInstance

    Jest->>axiosModule: jest.mock(axios)
    Jest->>axiosModule: (axios.create as jest.Mock).mockReturnValue({ get: mockGet })
    serviceSpec->>serviceModule: require(service)
    activate serviceModule
    serviceModule->>axiosModule: axios.create({ baseURL: /api/data-go-kr, timeout: 10000 })
    axiosModule-->>serviceModule: axiosInstance
    deactivate serviceModule

    serviceSpec->>serviceModule: getAPI({ pageNo: 1, numOfRows: 10 }, /sido_v2)
    serviceModule->>axiosInstance: get(/sido_v2, { params: { pageNo: 1, numOfRows: 10 } })
    axiosInstance-->>serviceModule: { data: { foo: bar } }
    serviceModule-->>serviceSpec: { foo: bar }

    serviceSpec->>serviceModule: getAPI({}, /kind_v2)
    serviceModule->>axiosInstance: get(/kind_v2, { params: {} })
    axiosInstance-->>serviceModule: { data: { count: 42 } }
    serviceModule-->>serviceSpec: { count: 42 }
Loading

Sequence diagram for Header component navigation test

sequenceDiagram
    actor Tester
    participant Jest
    participant useRouterHook as useRouter
    participant useSidoHook as useSido
    participant CountListComponent as CountList
    participant HeaderComponent as Header

    Jest->>useRouterHook: mockImplementation(() => { push: mockPush })
    Jest->>useSidoHook: mockImplementation(() => mockedSidoState)
    Jest->>CountListComponent: mockImplementation(() => <div>mocked_count_list</div>)

    Tester->>HeaderComponent: render(<Header />)
    HeaderComponent->>useRouterHook: useRouter()
    useRouterHook-->>HeaderComponent: { push: mockPush }
    HeaderComponent->>useSidoHook: useSido()
    useSidoHook-->>HeaderComponent: mockedSidoState
    HeaderComponent->>CountListComponent: render CountList

    Tester->>HeaderComponent: find title link
    Tester->>HeaderComponent: userEvent.click(title_link)
    HeaderComponent->>useRouterHook: push(/)
    useRouterHook-->>HeaderComponent: void
    Jest->>useRouterHook: expect(mockPush).toHaveBeenCalledWith(/)
Loading

Sequence diagram for Bottom nav routing and active state tests

sequenceDiagram
    actor Tester
    participant Jest
    participant useRouterHook as useRouter
    participant usePathnameHook as usePathname
    participant BottomComponent as Bottom

    Jest->>useRouterHook: mockImplementation(() => { push: mockPush })
    Jest->>usePathnameHook: mockImplementation(() => /search)

    Tester->>BottomComponent: render(<Bottom />)
    BottomComponent->>useRouterHook: useRouter()
    useRouterHook-->>BottomComponent: { push: mockPush }
    BottomComponent->>usePathnameHook: usePathname()
    usePathnameHook-->>BottomComponent: /search
    BottomComponent-->>Tester: three nav items with aria labels

    Tester->>BottomComponent: userEvent.click(nav_item_조회하기)
    BottomComponent->>useRouterHook: push(/search)
    useRouterHook-->>BottomComponent: void
    Jest->>useRouterHook: expect(mockPush).toHaveBeenCalledWith(/search)

    BottomComponent-->>Tester: nav_item_matching_/search has class text-primary
    Jest->>BottomComponent: expect(active_item).toHaveClass(text-primary)
Loading

File-Level Changes

Change Details Files
Add unit tests for the API service helper to verify axios configuration, query param forwarding, and response unwrapping.
  • Mock axios at the module boundary with jest.mock and CommonJS require so axios.create is stubbed before the service module is evaluated.
  • Capture the created axios instance’s get method with a jest.fn mock to control responses and assert call parameters.
  • Assert that axios.create is invoked with the expected baseURL and timeout configuration for the Next route handler proxy.
  • Test that getAPI forwards the provided path and merges props into the params object for GET requests.
  • Test that getAPI resolves to the unwrapped data field from the axios response object.
apps/web/src/api/service.spec.ts
Add an isolated unit test suite for the Header component to validate rendering of the title link and router navigation behavior.
  • Mock next/navigation to stub the router used by Header so push calls can be asserted.
  • Mock front/hooks (useSido) and front/site/home/Count (CountList) so Header can render without its real data and child components.
  • Render Header with React Testing Library and assert that the title link is present in the DOM.
  • Simulate a click on the title link and assert that router.push('/') is called.
apps/web/src/components/header.spec.tsx
Add a unit test suite for the Bottom navigation component to verify its navigation items, routing, and active state styling.
  • Mock next/navigation’s useRouter and usePathname hooks so navigation behavior and active path can be controlled in tests.
  • Render the Bottom component and assert that three navigation items render with the expected aria-labels.
  • Simulate a click on the '조회하기' nav item and assert that router.push('/search') is invoked with the correct path.
  • Verify that when usePathname matches an item’s route, that item receives the text-primary CSS class to indicate the active state.
apps/web/src/components/bottom.spec.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@vercel

vercel Bot commented Apr 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
animal-project Error Error Apr 13, 2026 2:30pm

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In service.spec.ts, consider switching from require + eslint-disable no-var-requires to an import with a jest.mock('axios', () => ({ create: jest.fn() })) factory so the test aligns with the ESM/TypeScript style and avoids global eslint disables while still letting you control the axios.create instance initialization order.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `service.spec.ts`, consider switching from `require` + `eslint-disable no-var-requires` to an `import` with a `jest.mock('axios', () => ({ create: jest.fn() }))` factory so the test aligns with the ESM/TypeScript style and avoids global eslint disables while still letting you control the `axios.create` instance initialization order.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@nx-cloud

nx-cloud Bot commented Apr 13, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 38a3ba6

Command Status Duration Result
nx affected -t lint test build e2e ✅ Succeeded 5s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-13 14:31:19 UTC

… specs

The import/first ESLint rule rejects `import` statements that appear
after `jest.mock` calls — but jest.mock must precede the imports
under test for the hoisting + factory contract to work. Inline-disable
the rule on the affected import lines.
@fray-cloud fray-cloud merged commit dd31616 into dev Apr 13, 2026
3 of 4 checks passed
@fray-cloud fray-cloud deleted the test/web-starter-suite branch April 13, 2026 14:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant