From c123e4187e47809839c3fa5f879eb3d756917c05 Mon Sep 17 00:00:00 2001 From: DudaGod Date: Wed, 9 Oct 2024 18:26:53 +0300 Subject: [PATCH] fix(component-testing): ability to import esm modules --- src/bundle/test-transformer.ts | 8 +-- test/src/test-reader/test-transformer.ts | 84 ++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/src/bundle/test-transformer.ts b/src/bundle/test-transformer.ts index 7fbf95684..64252323e 100644 --- a/src/bundle/test-transformer.ts +++ b/src/bundle/test-transformer.ts @@ -5,7 +5,6 @@ import { TRANSFORM_EXTENSIONS, JS_EXTENSION_RE } from "./constants"; import { requireModuleSync } from "../utils/module"; import type { NodePath, PluginObj, TransformOptions } from "@babel/core"; -import type { ImportDeclaration } from "@babel/types"; const STYLE_EXTESTION_RE = /\.(css|less|scss)$/; const IGNORE_STYLE_ERRORS = ["Unexpected token"]; @@ -30,10 +29,10 @@ export const setupTransformHook = (opts: { removeNonJsImports?: boolean } = {}): ], }; - const customIgnoreImportsPlugin = (): PluginObj => ({ + const customIgnoreImportsPlugin = ({ types: t }: { types: typeof babel.types }): PluginObj => ({ name: "ignore-imports", visitor: { - ImportDeclaration(path: NodePath): void { + ImportDeclaration(path: NodePath): void { const extname = nodePath.extname(path.node.source.value); if (extname && !extname.match(JS_EXTENSION_RE)) { @@ -51,6 +50,7 @@ export const setupTransformHook = (opts: { removeNonJsImports?: boolean } = {}): if (err.code === "ERR_REQUIRE_ESM") { mockEsmModuleImport(t, path); + return; } } }, @@ -115,8 +115,6 @@ function genVarDeclKey( t: typeof babel.types, node: NodePath["node"], ): babel.types.Identifier | babel.types.ObjectPattern { - console.log("node.specifiers:", node.specifiers); - if (node.specifiers.length === 1) { if (["ImportDefaultSpecifier", "ImportNamespaceSpecifier"].includes(node.specifiers[0].type)) { return t.identifier(node.specifiers[0].local.name); diff --git a/test/src/test-reader/test-transformer.ts b/test/src/test-reader/test-transformer.ts index 0f849daf7..b61a6bf35 100644 --- a/test/src/test-reader/test-transformer.ts +++ b/test/src/test-reader/test-transformer.ts @@ -136,6 +136,90 @@ describe("test-transformer", () => { assert.match(transformedCode, new RegExp(`require\\("${moduleName}"\\)`)); }); + + describe.only("replace import of esm module with a proxy", () => { + const moduleName = "esm-module"; + const error = { message: "require() of ES Module", code: "ERR_REQUIRE_ESM" }; + const expectedProxyValue = + "" + + `new Proxy({}, {\n` + + ` get: function (target, prop) {\n` + + ` return prop in target ? target[prop] : new Proxy(() => {}, this);\n` + + ` },\n` + + ` apply: function () {\n` + + ` return new Proxy(() => {}, this);\n` + + ` }\n` + + `});\n`; + + let setupTransformHookStub!: typeof setupTransformHook; + + beforeEach(() => { + const { setupTransformHook } = proxyquire("../../../src/test-reader/test-transformer", { + "../bundle": proxyquire.noCallThru().load("../../../src/bundle/test-transformer", { + "../utils/module": { + requireModuleSync: sandbox.stub().withArgs(moduleName).throws(error), + }, + }), + }); + setupTransformHookStub = setupTransformHook; + }); + + it("should replace with default import", async () => { + let transformedCode; + (pirates.addHook as SinonStub).callsFake(cb => { + transformedCode = cb(`import pkg from "${moduleName}"`, moduleName); + }); + + setupTransformHookStub({ removeNonJsImports: true }); + + assert.match(transformedCode, `const pkg = ${expectedProxyValue}`); + }); + + it("should replace with namespace import", async () => { + let transformedCode; + (pirates.addHook as SinonStub).callsFake(cb => { + transformedCode = cb(`import * as pkg from "${moduleName}"`, moduleName); + }); + + setupTransformHookStub({ removeNonJsImports: true }); + + assert.match(transformedCode, `const pkg = ${expectedProxyValue}`); + }); + + it("should replace with property import", async () => { + let transformedCode; + (pirates.addHook as SinonStub).callsFake(cb => { + transformedCode = cb(`import {a, b as c} from "${moduleName}"`, moduleName); + }); + + setupTransformHookStub({ removeNonJsImports: true }); + + assert.match(transformedCode, `` + `const {\n` + ` a,\n` + ` c\n` + `} = ${expectedProxyValue}`); + }); + }); + + it("should replace import of esm module with a proxy", () => { + const moduleName = "esm-module"; + const error = { message: "require() of ES Module", code: "ERR_REQUIRE_ESM" }; + + const { setupTransformHook } = proxyquire("../../../src/test-reader/test-transformer", { + "../bundle": proxyquire.noCallThru().load("../../../src/bundle/test-transformer", { + "../utils/module": { + requireModuleSync: sandbox.stub().withArgs(moduleName).throws(error), + }, + }), + }); + + let transformedCode; + + (pirates.addHook as SinonStub).callsFake(cb => { + transformedCode = cb(`import "${moduleName}"`, moduleName); + }); + + setupTransformHook({ removeNonJsImports: true }); + + assert.match(transformedCode, new RegExp(`require\\("${moduleName}"\\)`)); + }); }); }); });