jest "ReferenceError: TextEncoder is not defined" in CI but passes locally: jsdom environment fix
Fixes Jest "ReferenceError: TextEncoder is not defined" in CI but not locally by adding the missing Node globals to the jsdom test environment. Covers the setup-file polyfill, the Node version difference that usually explains the CI-only part, and when to upgrade jsdom instead. Use when Jest with jsdom fails in CI on TextEncoder or TextDecoder while local runs pass. Not for real encoding bugs in application code.
Polyfill TextEncoder in your Jest setup file. The jsdom test environment does not provide TextEncoder - it is a Node global, not a browser DOM API, and older jsdom versions simply do not include it. Locally your Node version (or a transitive polyfill from another dependency) happens to provide it, but CI's Node version or cleaner install does not, so the same test fails there. Add the polyfill once in your Jest setup file by assigning the Node util TextEncoder and TextDecoder onto the global object before tests run. If you are on a recent Jest and jsdom, upgrading the environment package can also fix it - but the setup-file polyfill is explicit, version-proof, and obvious to the next person.
jest "ReferenceError: TextEncoder is not defined" in CI but passes locally: jsdom environment fixSteps
Confirm the environment: check that the failing test runs under the jsdom test environment and find your Jest setup file (setupFilesAfterEach or setupFiles in config). The polyfill belongs there, not in individual tests. Expected: you know the test environment is jsdom and you have located the setup file.
Add the polyfill: in the setup file, import TextEncoder and TextDecoder from Node's util module and assign them to the global object. This runs before every test file, so every jsdom context gets the globals. Expected: the setup file defines both globals before any test executes.
Check the Node version gap: compare local node version with CI's. If CI runs an older Node, align the versions too - the polyfill fixes the symptom, but version drift causes the next mystery. Expected: local and CI Node versions are known and preferably identical.
Re-run the failing test in CI. TextEncoder errors fail fast at import or first use, so one CI run confirms the fix. Expected: the ReferenceError is gone in CI and the test executes.
Search the suite for other Node globals your jsdom tests rely on (fetch, crypto, ReadableStream). If TextEncoder was missing, its friends may be next - polyfill them in the same setup file. Expected: a quick audit for other missing globals, fixed in the same place.
Use this when
- "ReferenceError: TextEncoder is not defined" under Jest with jsdom, CI-only
- a test that passes locally but fails in CI on a missing global
- jsdom test environment lacking Node globals
Not for this skill when
- the same error in local runs too (same polyfill fix, but no version mystery to chase)
- actual character-encoding bugs in application code (that is a code bug, not a missing global)
Variant phrasings
jest TextEncoder is not defined
The general form. CI-only adds the Node-version-diff check.
jest jsdom missing Node globals
The broader class. TextEncoder is the most common member; the setup-file pattern fixes all of them.
Why it happens
Jest's jsdom environment simulates a browser DOM, not a full Node runtime - so Node-only globals like TextEncoder (from the util module) are absent unless something provides them. Whether a given machine provides them anyway depends on the Node version and on which other packages in the dependency tree patch globals as a side effect. A developer laptop with a newer Node or a richer dependency tree masks the gap; a clean CI install on a pinned older Node exposes it. The error is therefore environmental, and the fix belongs in the shared test setup rather than in the test that happened to trip over it first.
Edge cases
- upgrading jest-environment-jsdom instead: newer versions include more globals, but the upgrade can change other behavior - the polyfill is the lower-risk fix
- TextDecoder usually missing alongside TextEncoder: polyfill both in the same line, or the next test to decode text fails the same way
- libraries that check for TextEncoder at import time: the polyfill must run in setupFiles (before test files load), not lazily inside a test
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_aieeq8PJDF4-DA5AVKUP6Q