🪵 fix: Restore Winston Format Factory Shape In Test Mocks#13139
Merged
danny-avila merged 1 commit intoMay 15, 2026
Merged
Conversation
3b0651f to
2c90774
Compare
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.
2c90774 to
0ae1ea9
Compare
Owner
|
@codex review |
|
Codex Review: Didn't find any major issues. Another round soon, please! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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
approved these changes
May 15, 2026
14 tasks
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 forceswinston.format()to be evaluated at module-load time, the tests pass — but@librechat/data-schemas/dist/config/parsers.cjs:52does 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:
api/test/__mocks__/logger.js—(fn) => fnreturns the inner transform fn directly. Whenparsers.cjsdoesconst redactFormat = winston.format(fn)and thenparsers.redactFormat(), the inner fn is invoked with noinfoargument →TypeError: Cannot read properties of undefined (reading 'level')atparsers.ts:63.packages/api/src/agents/__tests__/memory.test.tspackages/api/src/agents/__tests__/run-summarization.test.tspackages/api/src/agents/__tests__/initialize.test.ts—formatis a plain object withcombine/colorize/simpleonly, sowinston.format(fn)throwsTypeError: winston.format is not a function. Once that's patched, the dist code then trips over missingwinston.format.printf,winston.addColors,new winston.transports.DailyRotateFile(...).The bug was introduced when DB layers were extracted into
@librechat/data-schemas(#7650, May 2025) and the side-effectingwinston.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'sjest.mockhoisting 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
Testing
Repro on
main(Node 24.9.0, Linux):With this PR applied:
Test Configuration
packages/{data-provider,data-schemas,api}per the contributor guideWhat the fix does
For all four mocks,
winston.formatbecomes a callable factory that mirrors real winston's shape: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.jskeeps its property-on-function style — the only change there is the closure body returns() => ({ transform: fn })instead offn.Checklist
prettier --write+eslint)formatneeds to be callable)cd packages/api && npx jest src/agents/__tests__/→ green)