[SWC plugin] workaround for jest

Overview

[SWC plugin] workaround for jest

Test Crates.io npm

This is a SWC plugin to handle jest compatibility issues.

This SWC plugin should be used with @swc/jest.

usage

install

npm i -D jest @swc/core @swc/jest jest_workaround
// jest.config.js
const fs = require("node:fs");

const swcrc = JSON.parse(fs.readFileSync(".swcrc", "utf8"));

// If you have other plugins, change this line.
((swcrc.jsc ??= {}).experimental ??= {}).plugins = [["jest_workaround", {}]];

module.exports = {
  transform: {
    "^.+\\.(t|j)sx?$": ["@swc/jest", swcrc],
  },
};

Make sure that module.type is commonjs in your .swcrc since this plugin does not touch non-workaround parts, such as import statements.

FAQ

  1. When do I need this?

The swc-transformed CJS is compliant with the ESM specification. This means that exports is immutable.

I need to use swc to get transformed code which conforms to the ESM specification. But I need to use jest in a CJS environment to test it.

The immutable exports is difficult to use for jest testing. This plugin will transform the export statement into mutable exports.

  1. Do I have a better choice?

Yes.

If I can run jest in an ESM environment, then I don't even need swc, or just use swc to transform TypeScript syntax.

There may be some issues with running jest in ESM, but they will be resolved over time. Tracked by facebook/jest#9430.

Or, I don't need the behavior of ESM. I can get the CJS behavior of exports by using the CJS syntax.

CJS specific syntax

exports.foo = function foo(){
    return 42;
}

CTS(CJS in TypeScript) syntax

export = {
    foo: function foo(){
        return 42;
    }
}

Notes:

  • ESM style export means immutable exports when transformed into CJS
  • ESM style import means hoisted require when transformed into CJS
Comments
  • NextJS compatibility

    NextJS compatibility

    This looks like just what I need. But when I run Jest I get all the same issues about spying. It doesn't seem to have made any difference.

    I have updated the .swcrc file as per the Readme and it is highlighted in VSCode saying:

    Property experimental is not allowed

    Screenshot 2022-07-29 at 16 05 09

    This is the full .swcrc file:

    {
      "$schema": "http://json.schemastore.org/swcrc",
      "jsc": {
        "experimental": {
          "plugins": [["jest_workaround", {}]]
        },
        "parser": {
          "syntax": "typescript",
          "tsx": true,
          "decorators": false,
          "dynamicImport": true
        },
        "target": "es5",
        "baseUrl": ".",
        "paths": { [...]  }
      },
      "module": {
        "type": "commonjs"
      }
    }
    

    Installed package versions:

    • "jest_workaround": "^0.1.5",
    • "@swc/core": "^1.2.220",
    • "@swc/jest": "^0.2.22",
    • "swc-node": "^1.0.0",

    I'm also using NextJS. Is there something I am missing to enable plugins for SWC ?

    Thanks!

    opened by paulsturgess 15
  • Default exports are not set as configurable

    Default exports are not set as configurable

    Hello, first of all thx for the plugin, it is being very useful at jest transform. I would like to advice you that transpiled code defines default export is not being defined through your _export function son it keeps not configurable.

    Object.defineProperty(exports, 'default', {
      enumerable: true,
      get: () => _default
    });
    

    It would be great if also default property is set as configurable.

    bug 
    opened by devcorraliza 3
  • Imports from file with same name but different location dropped

    Imports from file with same name but different location dropped

    I have installed "@swc/core": "1.3.4" and "jest_workaround": "0.1.11"

    In a file I have imports like

    import {
        getBooleanConfigValue,
        getNumericConfigValue
    } from "@init-code/config/config";
    import { shouldModuleBeInitialized } from "@async-core/config";
    
    function a() {
     const config = getBooleanConfigValue();
    }
    

    test file calls something from the file above

    and it fails with this test-file-fail

    I added a debug break point and see this swc-bug the _config is the module @async-core/config and @init-code/config/config is completely missing

    if I do this change

    const shouldModuleBeInitialized = () => true;
    

    and delete the import @async-core/config then @init-code/config/config shows up and then it contains all the exported stuff from it

    Seems like @async-core/config and @init-code/config/config cannot coexist and the one that is imported later overrides the one before. It seems like it has issues if both of them are files named config?

    opened by Smrtnyk 2
  • Feature Request: Support Object.assign on imported objects

    Feature Request: Support Object.assign on imported objects

    We have the following code in one of our test files:

    import * as ProposalStore from 'views/InteractiveProposal/store/proposalStore';
    
    Object.assign(ProposalStore, { useProposalDispatch: () => mockDispatch });
    

    Which gives the following error:

    ● Test suite failed to run

    TypeError: Cannot set property useProposalDispatch of [object Object] which has only a getter
        at Function.assign (<anonymous>)
    
       8 | jest.mock('views/InteractiveProposal/store/actions/updateDownPaymentAndSelectedFinanceOption');
       9 | const mockDispatch = jest.fn();
    > 10 | Object.assign(ProposalStore, { useProposalDispatch: () => mockDispatch });
    

    We were able to work around it by changing the code to:

    jest.mock('views/InteractiveProposal/store/proposalStore', () => {
     const actual = jest.requireActual('views/InteractiveProposal/store/proposalStore');
     return {
       ...actual,
       useProposalDispatch: () => mockDispatch,
     };
    });
    

    But it'd be nice to support the other, existing way also.

    Thanks!

    opened by shahmirn 1
  • RuntimeError: unreachable on latest @swc/core

    RuntimeError: unreachable on latest @swc/core

    I just updated to @swc/core 1.3.3, and now I can no longer run this plugin.

    The error stack is:

    failed to handle: failed to invoke plugin: failed to invoke plugin on 'Some("path/to/file.ts")'
    
        Caused by:
            0: failed to invoke `node_modules/.pnpm/[email protected]_@[email protected]+@[email protected]/node_modules/jest_workaround/target/wasm32-unknown-unknown/release/jest_workaround.wasm` as js transform plugin at node_modules/.pnpm/[email protected]_@[email protected]+@[email protected]/node_modules/jest_workaround/target/wasm32-unknown-unknown/release/jest_workaround.wasm
            1: RuntimeError: unreachable
                   at __rust_start_panic (<module>[1695]:0x12861a)
                   at rust_panic (<module>[1692]:0x1285f3)
                   at std::panicking::rust_panic_with_hook::h84feca33bd4bd229 (<module>[1691]:0x1285c3)
                   at std::panicking::begin_panic_handler::{{closure}}::hd2eacd3bb9ff1eab (<module>[1678]:0x127c96)
                   at std::sys_common::backtrace::__rust_end_short_backtrace::h976699518d897fb1 (<module>[1677]:0x127bd5)
                   at rust_begin_unwind (<module>[1686]:0x12825a)
                   at core::panicking::panic_fmt::hc171d095bc4a492d (<module>[1760]:0x129807)
                   at core::result::unwrap_failed::h68ab818eb89182b6 (<module>[1801]:0x1300f3)
                   at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::hd7ead72f4806bf83 (<module>[789]:0xdc359)
                   at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::ha2c88e8a71aeda28 (<module>[310]:0x43e69)
                   at swc_common::plugin::serialized::PluginSerializedBytes::deserialize::h897224c27b98e658 (<module>[910]:0xf0e67)
                   at swc_common::plugin::serialized::deserialize_from_ptr::hc9c103e6cc480c1b (<module>[909]:0xf0bf1)
                   at __transform_plugin_process_impl (<module>[829]:0xe1dda)
            2: unreachable
    
          at std::panicking::rust_panic_with_hook::h84feca33bd4bd229 (<module>[1691]:0x1285c3)
          at std::panicking::begin_panic_handler::{{closure}}::hd2eacd3bb9ff1eab (<module>[1678]:0x127c96)
          at std::sys_common::backtrace::__rust_end_short_backtrace::h976699518d897fb1 (<module>[1677]:0x127bd5)
                     at rust_begin_unwind (<module>[1686]:0x12825a)
          at core::panicking::panic_fmt::hc171d095bc4a492d (<module>[1760]:0x129807)
          at core::result::unwrap_failed::h68ab818eb89182b6 (<module>[1801]:0x1300f3)
          at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::hd7ead72f4806bf83 (<module>[789]:0xdc359)
          at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::ha2c88e8a71aeda28 (<module>[310]:0x43e69)
          at swc_common::plugin::serialized::PluginSerializedBytes::deserialize::h897224c27b98e658 (<module>[910]:0xf0e67)
          at swc_common::plugin::serialized::deserialize_from_ptr::hc9c103e6cc480c1b (<module>[909]:0xf0bf1)
                     at __transform_plugin_process_impl (<module>[829]:0xe1dda)
              2: unreachable
          at Compiler.transformSync (../../node_modules/.pnpm/@[email protected]/node_modules/@swc/core/index.js:241:29)
          at transformSync (../../node_modules/.pnpm/@[email protected]/node_modules/@swc/core/index.js:348:21)
          at Object.process (../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@swc/jest/index.js:72:45)
          at ScriptTransformer.transformSource (../../node_modules/.pnpm/@[email protected]/node_modules/@jest/transform/build/ScriptTransformer.js:615:31)
          at ScriptTransformer._transformAndBuildScript (../../node_modules/.pnpm/@[email protected]/node_modules/@jest/transform/build/ScriptTransformer.js:757:40)
          at ScriptTransformer.transform (../../node_modules/.pnpm/@[email protected]/node_modules/@jest/transform/build/ScriptTransformer.js:814:19)
    
    opened by strmer15 0
  • Compatibility with TS Enum

    Compatibility with TS Enum

    Input

    export enum Foo {
      Bar = "Bar",
      Baz = "Baz",
    }
    

    After TypeScript strip

    export var Foo;
    (function(Foo) {
        Foo["Bar"] = "Bar";
        Foo["Baz"] = "Baz";
    })(Foo || (Foo = {}));
    

    Final output(with this plugin)

    "use strict";
    Object.defineProperty(exports, "__esModule", {
        value: true
    });
    Object.defineProperty(exports, "Foo", {
        enumerable: true,
        get: function() {
            return Foo;
        },
        configurable: true
    });
    var Foo;
    (function(Foo) {
        exports.Foo["Bar"] = "Bar";
        exports.Foo["Baz"] = "Baz";
    })(exports.Foo || (exports.Foo = {}));
    

    Note: exports.Foo = {} did not change the value of exports.Foo.

    Expect Behaviour: Do not rewrite Foo in assign expr.

    opened by magic-akari 0
  • Align to TSC

    Align to TSC

    Only export variable should be rewritten with the export. prefix.

    https://www.typescriptlang.org/play?module=1#code/KYDwDg9gTgLgBAG2PAhnAvHAZgVwHYDGMAlhHnABQgD8AXHCngJ4CUcA3nAL4DcAUH1CRY2fEVLkARlToNmbTlwFDo8AghQBnTXAIdu-Pigot+003zzAA7rpOGk8APoYOfOB4YAaOJJ8E+JSMAA2CzUJ4gA

    opened by magic-akari 0
  • set configurable when re-exporting *

    set configurable when re-exporting *

    Hi: It seems like when transpiling ts code with export * as someObject from 'somefile' the transpiled code don't let spyOn that objects. The function used for exports doesn't set configurable=true

    function _exportStar(from, to) {
        Object.keys(from).forEach(function(k) {
            if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) Object.defineProperty(to, k, {
                enumerable: true,
                get: function() {
                    return from[k];
                }
            });
        });
        return from;
    }
    
    opened by devcorraliza 0
  • set configurable when re-exporting

    set configurable when re-exporting

    Hi: It seems like when transpiling ts code with export {someProperties} as someObject from 'somefile' the transpiled code don't let spyOn that objects. The function used for exports doesn't set configurable=true

    function _export(target, all) {
        for(var name in all)Object.defineProperty(target, name, {
            enumerable: true,
            get: all[name]
        });
    }
    
    opened by devcorraliza 0
  • Doesn't appear to work with typescript?

    Doesn't appear to work with typescript?

    I've installed the jest_workaround, and setup my jest.config to pass the plugin in,

    My .swcrc file:

    {
        "jsc": {
            "parser": {
                "syntax": "typescript",
                "tsx": true
            }
        },
        "module": {
            "type": "commonjs"
        }
    }
    

    when I run I still get:

     ● Test suite failed to run
    
        TypeError: Cannot redefine property: trackCtaClicked
            at Function.defineProperty (<anonymous>)
    

    Not sure what I'm doing wrong.

    Package versions:

    "@swc/cli": "^0.1.57",
    "@swc/core": "^1.3.14",
    "@swc/jest": "^0.2.23",
    "jest_workaround": "^0.1.13"
    
    opened by siosphere 0
  •  Failed to create plugin instance

    Failed to create plugin instance

    Trying to use this plugin in nextjs and getting this error:

    Caused by:
        0: Failed to create plugin instance
        1: Error while importing "env"."__set_transform_plugin_core_pkg_diagnostics": unknown import. Expected Function(FunctionType { params: [I32, I32], results: [] })
        at Object.transformSync (/Users/psenders/Documents/GitHub/web/node_modules/next/dist/build/swc/index.js:289:33)
        at Object.transformSync (/Users/psenders/Documents/GitHub/web/node_modules/next/dist/build/swc/index.js:325:21)
        at Object.process (/Users/psenders/Documents/GitHub/web/node_modules/next/dist/build/swc/jest-transformer.js:27:36)
        at ScriptTransformer.transformSource (/Users/psenders/Documents/GitHub/web/node_modules/@jest/transform/build/ScriptTransformer.js:615:31)
        at revertHook.exts (/Users/psenders/Documents/GitHub/web/node_modules/@jest/transform/build/ScriptTransformer.js:863:18)
        at Module._compile (/Users/psenders/Documents/GitHub/web/node_modules/@jest/transform/node_modules/pirates/lib/index.js:130:29)
        at Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
        at Object.newLoader (/Users/psenders/Documents/GitHub/web/node_modules/@jest/transform/node_modules/pirates/lib/index.js:141:7)
        at Module.load (node:internal/modules/cjs/loader:981:32)
        at Function.Module._load (node:internal/modules/cjs/loader:822:12)
        ```
    opened by PepijnSenders 2
  • Unreadable logs printed to .swc

    Unreadable logs printed to .swc

    When the plugin has any errors with transforming it logs an unreadable file (AFAIK, I tried reading it with all sort of stuff)... attached an example log I had thrown when trying to use the plugin for moving a fe project from ts-jest -> swc and when trying to update swc-core 1.2.224 -> 1.2.232 (maybe something got broken there but can't be sure because I can't read the logs there...) example_log.zip

    Purposed Solution:

    • Have an option to mute those logs
    • Find out how to make them readable
    opened by ItamarMalka 10
Owner
magic-akari
Follow your heart.
magic-akari
A swc plugin that automatically converts React component libraries into "React Client Component"

A swc plugin that automatically converts React component libraries into "React Client Component". For example, you can automatically convert components from @mui into "React Client Component" without having to wrap a component that uses "use client".

xiaotian 3 Jul 12, 2023
swc node binding use wasm

node_swc swc node binding use wasm Build Make sure you have rust wasm-pack installed. $ yarn build # build wasm, node Usage import { parseSync, printS

伊撒尔 23 Sep 8, 2022
An experimental transpiler to bring tailwind macros to SWC 🚀

stailwc (speedy tailwind compiler) This is an experimental SWC transpiler to bring compile time tailwind macros to SWC (and nextjs) a-la twin macro. T

Alexander Lyon 139 Dec 20, 2022
Automatically transform your Next.js Pages to use SuperJSON with SWC

?? NEXT SUPERJSON PLUGIN export default function Page({ date }) { return ( <div> Today is {date.toDateString()} </div> ) } // You c

⚡️Blitz 92 Jan 4, 2023
Plugin to request a relaunch when uploading a Skyline plugin through cargo skyline

restart-plugin A skyline plugin for allowing cargo-skyline (or other tools) to restart your game without you having to touch your controller. Install

null 1 Nov 21, 2021
This plugin provides an interface for storing unencrypted values on the application cache folder.

Tauri Plugin Store This plugin provides an interface for storing unencrypted values on the application cache folder. Architecture This repo shape migh

Tauri 128 Jan 1, 2023
This is a Pomodoro Clock implemented as a Zellij plugin.

Pomodoro Clock This is a Pomodoro Clock implemented as a Zellij plugin. It shows a Pomodoro time as well as current date time. Prerequisite You must i

Tw 15 Nov 14, 2022
A VtubeStudio plugin that allows iFacialMocap to stream data to the app, enabling full apple ARkit facial tracking to be used for 2D Vtuber models.

facelink_rs A VtubeStudio plugin that allows iFacialMocap to stream data to the app, enabling full apple ARkit facial tracking to be used for 2D Vtube

Slashscreen 2 May 6, 2022
A rollup plugin that compile Rust code into WebAssembly modules

rollup-plugin-rust tl;dr -- see examples This is a rollup plugin that loads Rust code so it can be interop with Javascript base project. Currently, th

Fahmi Akbar Wildana 37 Aug 1, 2022
A plugin for Devzat that can tell the time at various timezones.

Devzat Time Teller On Devzat, people come from all around the time. It is sometime hard to know what time it is for other peoples. This plugin let you

Maxime Bouillot 3 Jun 24, 2022
Replicated storage docker plugin.

Fractal Docker Plugin This plugin handles the creation and deletion of docker volumes backed by copy-on-write filesystems (BTRFS currently), regular s

Fractal Networks 5 Sep 2, 2022
Bioinformatics plugin for nushell.

Nushell bio A bioinformatics plugin for nushell. The aim initially is to create a bunch of parsers for all of the common bioinformatics file formats a

Max Brown 7 Jan 8, 2023
A Foundry plugin that enables you to plot charts within solidity.

??️ solplot A Foundry plugin that enables you to plot charts within solidity. Installation First, make sure that you have Rust installed. Then install

boredretard.eth 132 Dec 27, 2022
Lapce vue plugin, support vue (SFC) syntax highlight, autocomplate,types check

Lapce Plugin for Vue (based volar) Preview Usage Required: Lapce version must be greater than 2.0, and you can use Lapce nightly version. click here t

xiaoxin 32 Dec 26, 2022
Component-based state machine plugin for Bevy

seldom_state is a component-based state machine plugin for Bevy. It's useful for AI, player state, and other entities that occupy various states. It allows for greater reusability of state logic between entities, compared to managing mutually-exclusive components directly in your systems.

Seldom 43 Jan 2, 2023
Analog subtractive synth (VST Plugin) made with Rust

Synja Analog subtractive synth (VST3 Plugin) made with Rust. More an experiment in making a VST and learning Rust than a production quality Synth, but

Anders Forsgren 7 Jan 18, 2023
🥃 A plugin for swizzling Tauri’s NSWindow to NSPanel

Swizzle Tauri's NSWindow to NSPanel Install There are three general methods of installation that we can recommend. Use crates.io and npm (easiest, and

Victor Aremu 11 Mar 24, 2023
A Zellij plugin for quickly searching and switching tabs 🖤

?? room A Zellij plugin for quickly searching and switching between tabs. Usage Tab to cycle through tab list Up and Down to cycle through tab list En

Lucas 15 Jul 11, 2023
Zellij plugin to quickly navigate your panes (clone of nvim's harpoon)

harpoon A Zellij plugin for quickly searching and switching between tabs. Copy of the original harpoon for nvim. Usage a to add pane to list Up and Do

null 13 Aug 11, 2023