Skip to content

🪵 fix: Restore Winston Format Factory Shape In Test Mocks#13139

Merged
danny-avila merged 1 commit into
danny-avila:mainfrom
JorgeCosta87:fix/api-test-winston-format-mock
May 15, 2026
Merged

🪵 fix: Restore Winston Format Factory Shape In Test Mocks#13139
danny-avila merged 1 commit into
danny-avila:mainfrom
JorgeCosta87:fix/api-test-winston-format-mock

Conversation

@JorgeCosta87

Copy link
Copy Markdown
Contributor

Summary

The four jest.mock('winston', …) setups in the test suite return a shape that doesn't satisfy real winston's Format-factory contract. As long as nothing forces winston.format() to be evaluated at module-load time, the tests pass — but @librechat/data-schemas/dist/config/parsers.cjs:52 does exactly that, so any test file whose import graph reaches @librechat/data-schemas (directly or transitively) can fail to load on environments where Jest's mock-hoisting actually hits this path.

Affected files:

The bug was introduced when DB layers were extracted into @librechat/data-schemas (#7650, May 2025) and the side-effecting winston.format() call moved with them. The test mocks were never updated to follow.

Why it doesn't fail in current CI on main: the failure depends on subtleties of Jest's jest.mock hoisting interaction with the workspace symlink chain — happens reproducibly on Node 24.x and on some Linux runner configurations, doesn't trigger on the GitHub Actions Ubuntu / Node 20.19 combination that current CI uses. The mock is wrong against the API contract regardless; this fix removes the latent failure across all supported environments.

Change Type

  • Bug fix (non-breaking change which fixes an issue)

Testing

Repro on main (Node 24.9.0, Linux):

git checkout main
npm ci
npm run build:data-provider && npm run build:data-schemas && npm run build:api
cd packages/api && npx jest src/agents/__tests__/memory.test.ts
# → TypeError: winston.format is not a function
#   at ../data-schemas/src/config/parsers.ts:62

With this PR applied:

cd packages/api && npx jest src/agents/__tests__/memory.test.ts src/agents/__tests__/run-summarization.test.ts src/agents/__tests__/initialize.test.ts
# → 3 suites, 106 tests, all pass

Test Configuration

  • Node 24.9.0 (also verified the fix works on Node 20.19.6)
  • Ubuntu / WSL2
  • Jest 30.2.0
  • Fresh build of packages/{data-provider,data-schemas,api} per the contributor guide

What the fix does

For all four mocks, winston.format becomes a callable factory that mirrors real winston's shape:

format: Object.assign(jest.fn((fn) => () => ({ transform: fn })), {
  combine: jest.fn(),
  colorize: jest.fn(),
  simple: jest.fn(),
  label: jest.fn(),
  timestamp: jest.fn(),
  printf: jest.fn(),
  errors: jest.fn(),
  splat: jest.fn(),
  json: jest.fn(),
}),
addColors: jest.fn(),
transports: {
  Console: jest.fn(),
  DailyRotateFile: jest.fn(),
  File: jest.fn(),
},

winston.format(fn) now returns a thunk that yields { transform: fn }. Module-load completes cleanly because nothing invokes the inner transform at import time; winston's pipeline (not exercised under mocks) is the only thing that would ever call .transform(info).

api/test/__mocks__/logger.js keeps its property-on-function style — the only change there is the closure body returns () => ({ transform: fn }) instead of fn.

Checklist

  • My code adheres to this project's style guidelines (ran prettier --write + eslint)
  • I have performed a self-review of my own code
  • I have commented in any complex areas of my code (each mock now explains why format needs to be callable)
  • I have made pertinent documentation changes (no docs affected — test-only patch)
  • My changes do not introduce new warnings
  • I have written tests demonstrating that my changes are effective (the existing tests now pass on previously-failing environments)
  • Local unit tests pass with my changes (cd packages/api && npx jest src/agents/__tests__/ → green)
  • Any changes dependent on mine have been merged and published in downstream modules. (n/a — test-only)
  • A pull request for updating the documentation has been submitted. (n/a — test-only)

@JorgeCosta87 JorgeCosta87 force-pushed the fix/api-test-winston-format-mock branch from 3b0651f to 2c90774 Compare May 15, 2026 12:51
@JorgeCosta87 JorgeCosta87 changed the title fix: winston test-mock returns Format factory to match real API contract 🪵 fix: Restore Winston Format Factory Shape In Test Mocks May 15, 2026
Four jest mocks for `winston` in the test suite return the wrong shape:

  api/test/__mocks__/logger.js                                   (returns inner fn directly)
  packages/api/src/agents/__tests__/memory.test.ts               (`format` is a plain object)
  packages/api/src/agents/__tests__/run-summarization.test.ts    (same)
  packages/api/src/agents/__tests__/initialize.test.ts           (same)

Real `winston.format(fn)` returns a Format constructor whose instances
expose a `.transform(info, opts)` method that winston's pipeline calls
with the log info object. The current mocks collapse this:

- `(fn) => fn` returns the inner transform fn directly. When module-load
  code in `@librechat/data-schemas/dist/config/parsers.cjs:52` does
  `const redactFormat = winston.format((info) => ...)`, `redactFormat`
  becomes the inner fn. The next line in `winston.cjs` calls
  `parsers.redactFormat()` which invokes the inner fn with no `info`,
  throwing `TypeError: Cannot read properties of undefined (reading 'level')`.

- `format: { combine, colorize, simple }` makes `winston.format` not
  callable at all — `winston.format((info) => ...)` throws
  `TypeError: winston.format is not a function`.

These currently pass in CI on GitHub Actions Ubuntu / Node 20.19, but
fail reproducibly on Node 24.x and on some Linux distros (verified on
WSL Ubuntu with Node 24.9.0). The CI passes appears to be environmental
luck around jest's mock-hoisting interaction with the workspace symlink
chain — the mocks are genuinely wrong against the data-schemas contract.

The fix: return a thunk that yields `{ transform: fn }` — matches real
winston's shape just enough that module-load completes; the inner fn is
only ever invoked by winston's pipeline (never at load time). Also adds
the full `winston.format.*` method surface (printf, timestamp, errors,
splat, json) plus `addColors` and the `DailyRotateFile`/`File` transports
that data-schemas's dist code references at module-load.

Verification (Node 24.9.0):
  npm run build:data-provider && npm run build:data-schemas && npm run build:api
  cd packages/api && npx jest src/agents/__tests__/{memory,run-summarization,initialize}.test.ts
  → 3 suites, 106 tests, all pass

No production code or behavior changes — test-only patch.
@JorgeCosta87 JorgeCosta87 force-pushed the fix/api-test-winston-format-mock branch from 2c90774 to 0ae1ea9 Compare May 15, 2026 13:13
@danny-avila

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@danny-avila danny-avila merged commit 5b11a5a into danny-avila:main May 15, 2026
12 checks passed
fuuuzzy pushed a commit to fuuuzzy/LibreChat that referenced this pull request May 18, 2026
…ila#13139)

Four jest mocks for `winston` in the test suite return the wrong shape:

  api/test/__mocks__/logger.js                                   (returns inner fn directly)
  packages/api/src/agents/__tests__/memory.test.ts               (`format` is a plain object)
  packages/api/src/agents/__tests__/run-summarization.test.ts    (same)
  packages/api/src/agents/__tests__/initialize.test.ts           (same)

Real `winston.format(fn)` returns a Format constructor whose instances
expose a `.transform(info, opts)` method that winston's pipeline calls
with the log info object. The current mocks collapse this:

- `(fn) => fn` returns the inner transform fn directly. When module-load
  code in `@librechat/data-schemas/dist/config/parsers.cjs:52` does
  `const redactFormat = winston.format((info) => ...)`, `redactFormat`
  becomes the inner fn. The next line in `winston.cjs` calls
  `parsers.redactFormat()` which invokes the inner fn with no `info`,
  throwing `TypeError: Cannot read properties of undefined (reading 'level')`.

- `format: { combine, colorize, simple }` makes `winston.format` not
  callable at all — `winston.format((info) => ...)` throws
  `TypeError: winston.format is not a function`.

These currently pass in CI on GitHub Actions Ubuntu / Node 20.19, but
fail reproducibly on Node 24.x and on some Linux distros (verified on
WSL Ubuntu with Node 24.9.0). The CI passes appears to be environmental
luck around jest's mock-hoisting interaction with the workspace symlink
chain — the mocks are genuinely wrong against the data-schemas contract.

The fix: return a thunk that yields `{ transform: fn }` — matches real
winston's shape just enough that module-load completes; the inner fn is
only ever invoked by winston's pipeline (never at load time). Also adds
the full `winston.format.*` method surface (printf, timestamp, errors,
splat, json) plus `addColors` and the `DailyRotateFile`/`File` transports
that data-schemas's dist code references at module-load.

Verification (Node 24.9.0):
  npm run build:data-provider && npm run build:data-schemas && npm run build:api
  cd packages/api && npx jest src/agents/__tests__/{memory,run-summarization,initialize}.test.ts
  → 3 suites, 106 tests, all pass

No production code or behavior changes — test-only patch.

Co-authored-by: Jorge Costa <8352477+JorgeCosta87@users.noreply.github.com>
patricia2510 pushed a commit to lexaeon-org/libre-chat that referenced this pull request May 21, 2026
…ila#13139)

Four jest mocks for `winston` in the test suite return the wrong shape:

  api/test/__mocks__/logger.js                                   (returns inner fn directly)
  packages/api/src/agents/__tests__/memory.test.ts               (`format` is a plain object)
  packages/api/src/agents/__tests__/run-summarization.test.ts    (same)
  packages/api/src/agents/__tests__/initialize.test.ts           (same)

Real `winston.format(fn)` returns a Format constructor whose instances
expose a `.transform(info, opts)` method that winston's pipeline calls
with the log info object. The current mocks collapse this:

- `(fn) => fn` returns the inner transform fn directly. When module-load
  code in `@librechat/data-schemas/dist/config/parsers.cjs:52` does
  `const redactFormat = winston.format((info) => ...)`, `redactFormat`
  becomes the inner fn. The next line in `winston.cjs` calls
  `parsers.redactFormat()` which invokes the inner fn with no `info`,
  throwing `TypeError: Cannot read properties of undefined (reading 'level')`.

- `format: { combine, colorize, simple }` makes `winston.format` not
  callable at all — `winston.format((info) => ...)` throws
  `TypeError: winston.format is not a function`.

These currently pass in CI on GitHub Actions Ubuntu / Node 20.19, but
fail reproducibly on Node 24.x and on some Linux distros (verified on
WSL Ubuntu with Node 24.9.0). The CI passes appears to be environmental
luck around jest's mock-hoisting interaction with the workspace symlink
chain — the mocks are genuinely wrong against the data-schemas contract.

The fix: return a thunk that yields `{ transform: fn }` — matches real
winston's shape just enough that module-load completes; the inner fn is
only ever invoked by winston's pipeline (never at load time). Also adds
the full `winston.format.*` method surface (printf, timestamp, errors,
splat, json) plus `addColors` and the `DailyRotateFile`/`File` transports
that data-schemas's dist code references at module-load.

Verification (Node 24.9.0):
  npm run build:data-provider && npm run build:data-schemas && npm run build:api
  cd packages/api && npx jest src/agents/__tests__/{memory,run-summarization,initialize}.test.ts
  → 3 suites, 106 tests, all pass

No production code or behavior changes — test-only patch.

Co-authored-by: Jorge Costa <8352477+JorgeCosta87@users.noreply.github.com>
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.

2 participants