question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Bug]: Missing docs for SyncTransformer#createTransformer

See original GitHub issue

Version

27.5.1

Steps to reproduce

I created a minimal repro repo before figuring out what was wrong, but the essence is this:

Create a debug-transformer.js that wraps another, like this wrapping babel-jest:

const debug = require('debug')('jest-debug-transform')
const babelJest = require('babel-jest').default
const originalProcess = babelJest.process
const originalProcessAsync = babelJest.processAsync

module.exports  = {
  ...babelJest, // <-- source of confusion: the presence of `createTransformer` will void the effect of implemented methods
  process(src, filename, options) {
    debug(`Transforming '${filename}'`)
    return originalProcess(src, filename, options)
  },
  processAsync(src, filename, options) {
    debug(`Async Transforming '${filename}'`)
    return originalProcessAsync(src, filename, options)
  },
}

and use it in the jest config:

  transform: { '\\.[jt]sx?$': [ './debug-transformer.js', {} ]  }

Now, when running DEBUG="jest-debug*" npx jest --no-cache I would have assumed it would print messages such as “Transforming ‘./src/myfile.test.tsx’”, but it never does. Unless I manually add a line where I delete module.exports.createTransformer, that is.

Expected behavior

I would have expected it to use the implemented process and processAsync methods when implemented, as the effects of createTransformer is not documented.

Actual behavior

createTransformer() is being called if present. This is not documented in the transform docs, and makes the interface not really reflect reality. There is no point in implementing process if it is never called.

Additional context

I have been looking into/debugging code transformation related issues in Jest for the last day and a recurring theme is that the SyncTransformer#createTransformer method is a constant source of surprise and it is not really documented why it exists.

The SyncTransformer interface only has a single field one has to implement: process. But it seems that if one implements createTransformer those other methods will not be used: instead Jest seems to create a new transformer using createTransformer, which caused my to lose a few hairs until I figured what was going on. This behaviour does not seem to be documented.

The babel-jest source for Jest 27.

Environment

System:
    OS: macOS 12.2
    CPU: (8) arm64 Apple M1
  Binaries:
    Node: 17.4.0 - /usr/local/bin/node
    npm: 8.3.1 - /usr/local/bin/npm
  npmPackages:
    jest: ^27.5.1 => 27.5.1

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
SimenBcommented, Feb 16, 2022

There is nothing magical about process. The code actually requires that one implements createTransformer or processAsync or process - in that order of precedence. Supplying all three makes no sense.

Supplying createTransformer makes the other 2 redundant, yes, as they won’t be used.

However, we have both sync (process) and async (processAsync) code transformation, which both can be provided. require will always use process, and import will use processAsync if it exists, otherwise fall back to process. So if you use import exclusively you don’t need process, but in most cases supplying both makes sense. Jest transpiles on demand rather than ahead of time, so the sync one needs to exist.

If you implement createTransformer then implementing any of the other methods makes no sense (to me), as they will not be used.

Ish, createTransformer needs to return process and/or processAsync (plus the cache key variants), but it doesn’t really make sense to implement them at the same level as createTransformer.

To me this says createTransformer does not belong inside of the Transformer interfaces.

Agreed!

If you implement processAsync then process will never be used. To me that says that these fields should never co-exist.

As mentioned, process is used by require, processAsync by import.

remove createTransformer from the Transformer interface

👍

Remove process from AsyncTransformer and processAsync from SyncTransformer

👎

make the interface to implement look like type TransformerOrTransformerCreator = Transformer | { createTransformer: TransformerCreator }

👍

The last point would potentially be breaking

We’re currently releasing alphas for Jest 28, so breaking changes are fine 🙂

1reaction
fatso83commented, Feb 16, 2022

I have no issues in documenting it, I was just not sure what to write, but now I have deep dived into ScriptTransformer and its likes, so I understand a bit more 🤓

Looking into the validation errors and associated tests, it seems the interfaces should be updated as well?

This is what I seem to understand is lacking documentation (as explicit docs or via typing):

  • There is nothing magical about process. The code actually requires that one implements createTransformer or processAsync or process - in that order of precedence. Supplying all three makes no sense.
  • If you implement createTransformer then implementing any of the other methods makes no sense (to me), as they will not be used. To me this says createTransformer does not belong inside of the Transformer interfaces.
  • If you implement processAsync then process will never be used. To me that says that these fields should never co-exist.

Suggested changes

  • remove createTransformer from the Transformer interface
  • Remove process from AsyncTransformer and processAsync from SyncTransformer
  • make the interface to implement look like type TransformerOrTransformerCreator = Transformer | { createTransformer: TransformerCreator }

The last point would potentially be breaking, so for backwards compatibility could be type TransformerAndOrTransformerCreator = Transformer & { createTransformer?: TransformerCreator } | { createTransformer: TransformerCreator } (head-coded those, so not sure if compiles)

👍 / 👎 ?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Crypto class missing in TEI ODD transformation - Oxygen XML Forum
Anyway, here is how to add the missing jar: 1. go to Options, Preferences... , on page Document Type Associations and edit the...
Read more >
mobxjs/mobx - Gitter
i suppose create transformer ... Which the props aren't in sync with the data in mobx store. ... nm, was missing mobxautorun around...
Read more >
Exception in Async Raven session - Google Groups
With the Sync Ravensession (documentStore.OpenSession()) all is working perfectly. When i use this on an Async Ravensession i get an Error that the ......
Read more >
babel-preset-jest | Yarn - Package Manager
Important: This documentation covers modern versions of Yarn. For 1.x docs, see classic.yarnpkg.com. Yarn.
Read more >
How to use the babel-jest.createTransformer function in ... - Snyk
babelrc.json'); const config = JSON.parse(fs.readFileSync(configPath)); module.exports = jest.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found