Skip to content

Unit Tests: Shift Apply & Approve Services#334

Open
ajablaza wants to merge 3 commits intomainfrom
ajablaza/feature/shift-apply-approve-service-tests
Open

Unit Tests: Shift Apply & Approve Services#334
ajablaza wants to merge 3 commits intomainfrom
ajablaza/feature/shift-apply-approve-service-tests

Conversation

@ajablaza
Copy link
Copy Markdown
Collaborator

@ajablaza ajablaza commented May 2, 2026

Unit Tests: Shift Apply & Approve Services

Overview

This PR adds unit tests for applyForShiftService and approveShiftService in shiftApplication.service.js, and includes the configuration changes required to make Jest work with the project's ESM setup.

This branch was created from louisa/feature/shift-apply-approve-service — see PR #332


Config Changes

package.json — dependency version bumps

The following packages were already present but were updated during npm install:

Package Before After
@babel/core ^7.28.0 ^7.29.0
@babel/preset-env ^7.28.0 ^7.29.3
babel-jest ^30.0.4 ^30.3.0
cross-env ^10.1.0 (new)

cross-env is the only newly added package. It is required to set NODE_OPTIONS in a cross-platform way so the test script works on both Windows and Unix.

package.json — test script

Updated the test script to:

cross-env NODE_OPTIONS=--experimental-vm-modules npx jest --runInBand
  • --experimental-vm-modules is required because the project uses "type": "module" (ESM). Without this flag, Jest cannot handle ES module imports.
  • cross-env ensures the flag works on both Windows and Unix systems.
  • --runInBand runs tests serially to avoid race conditions.

jest.config.cjs

Configured Jest to:

  • silent: true added to suppress console output (MongoDB connection warnings, SMTP warnings) during test runs

Why jest.unstable_mockModule instead of jest.mock?

The project uses "type": "module" in package.json, which means all files are treated as ESM. The standard jest.mock() API relies on CommonJS require() under the hood, which does not exist in ESM and causes a require is not defined error. jest.unstable_mockModule() is the ESM-compatible alternative.

Additionally, the service is imported using a dynamic await import() instead of a static import. This is necessary because static imports are hoisted to the top of the file by JavaScript, meaning they would run before the mocks are set up and load the real dependencies instead of the mocked ones.


Test Cases

applyForShiftService (12 tests)

Validation

  • Throws 400 for an invalid shiftId
  • Throws 401 when userId is missing
  • Throws 401 when userId is invalid

Shift Lookup

  • Throws 404 when the shift does not exist

Business Rules

  • Throws 400 when the shift status is not open
  • Throws 400 when the shift has already started or is in the past
  • Throws 400 when the employer tries to apply to their own shift
  • Throws 400 when the user has already applied
  • Throws 400 when the shift overlaps with an existing applied shift

Success

  • Adds the applicant, sets status to applied, saves the shift, and logs the audit event
  • Sanitizes falsy values (null, undefined, '') from the applicants array before pushing
  • Does not flag an overlap when no other shifts exist on that date

approveShiftService (13 tests)

Validation

  • Throws 400 for an invalid shiftId
  • Throws 400 for an invalid guardId
  • Throws 401 when user._id is missing

Shift Lookup

  • Throws 404 when the shift does not exist

Authorization

  • Throws 403 when the user is neither the shift owner nor an admin
  • Allows an admin to approve any shift regardless of ownership

Business Rules

  • Throws 400 when the shift is already assigned
  • Throws 400 when the shift is already completed
  • Throws 400 when the shift has already started or is in the past
  • Throws 400 when the guard did not apply for the shift

Success

  • Assigns the guard, sets status to assigned, and removes other applicants by default
  • Keeps other applicants when keepOthers: true is passed
  • Logs the audit event with the correct action and metadata

image

Notes

  • All external dependencies (mongoose, Shift model, logger, timeUtils) are mocked — no database or external services are required to run these tests.
  • timeUtils functions are mocked with real implementations so the overlap detection logic is genuinely exercised.

@ajablaza ajablaza requested a review from LoopyB May 2, 2026 14:13
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