Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

babel-plugin-mockable-imports

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

babel-plugin-mockable-imports - npm Package Compare versions

Comparing version 1.3.0 to 1.3.1

61

index.js

@@ -8,2 +8,5 @@ 'use strict';

/**
* Default list of modules whose imports are excluded from processing.
*/
const EXCLUDE_LIST = [

@@ -17,2 +20,9 @@ // Proxyquirify and proxyquire-universal are two popular mocking libraries

/**
* Default list of directories that are excluded from the transforms applied
* by this plugin.
*
* The default list includes common names of test directories, because there
* is no point in making imports in test modules mockable.
*/
const EXCLUDED_DIRS = ['test', '__tests__'];

@@ -77,2 +87,5 @@

/**
* Return true if node is a `module.exports = <expression>` assignment.
*/
function isCommonJSExportAssignment(path) {

@@ -159,12 +172,7 @@ const assignExpr = path.node;

enter(path, state) {
// Map of local identifier for import => import info.
state.importMeta = new Map();
// The last `import` or top-level CommonJS require node that was
// seen in the code.
state.lastImport = null;
// Keep track of whether modifying this file has been aborted.
// TODO - It should be possible to make use of `path.stop()` and avoid
// needing to do this. This currently results in processing of the
// file by other plugins stopping though it seems. Perhaps need to
// create an innert path and use that?
// Set of local identifiers which refer to an import.
state.importIdentifiers = new Set();
// Flag to keep track of whether further processing of this file has
// stopped.
state.aborted = excludeModule(state);

@@ -180,3 +188,3 @@

exit(path, state) {
if (state.aborted || state.importMeta.size === 0) {
if (state.aborted || state.importIdentifiers.size === 0) {
return;

@@ -244,2 +252,3 @@ }

// Check for and register CommonJS imports in top-level variable assignments.
AssignmentExpression(path, state) {

@@ -287,7 +296,3 @@ if (state.aborted) {

// not the assignment.
state.importMeta.set(binding.identifier, {
symbol: '<CJS>',
source,
value: binding.identifier,
});
state.importIdentifiers.add(binding.identifier);

@@ -301,2 +306,3 @@ // The actual import registration via `$imports.$add` however needs to

// Check for and register CommonJS imports in top-level variable declarations.
VariableDeclaration(path, state) {

@@ -322,7 +328,3 @@ if (state.aborted) {

imports.forEach(({alias, source, symbol, value}) => {
state.importMeta.set(value, {
symbol,
source,
value,
});
state.importIdentifiers.add(value);
path.insertAfter(createAddImportCall(alias, source, symbol, value));

@@ -332,2 +334,3 @@ });

// Register ES6 imports.
ImportDeclaration(path, state) {

@@ -337,4 +340,3 @@ if (state.aborted) {

}
// Process import and add metadata to `state.importMeta` map.
state.lastImport = path;
// Process import and add metadata to `state.importIdentifiers` map.
path.node.specifiers.forEach(spec => {

@@ -371,8 +373,3 @@ if (spec.local.name === '$imports') {

state.importMeta.set(spec.local, {
symbol: imported,
source,
value: spec.local,
});
state.importIdentifiers.add(spec.local);
path.insertAfter(

@@ -384,2 +381,5 @@ createAddImportCall(spec.local.name, source, imported, spec.local),

// Replace references to identifiers with `$imports.<identifier>`
// expressions which resolve either to the original import or the active
// mocks.
ReferencedIdentifier(child, state) {

@@ -390,5 +390,6 @@ if (state.aborted) {

// Check if this a reference to an import.
const name = child.node.name;
const binding = child.scope.getBinding(name, /* noGlobal */ true);
if (!binding || !state.importMeta.has(binding.identifier)) {
if (!binding || !state.importIdentifiers.has(binding.identifier)) {
return;

@@ -395,0 +396,0 @@ }

@@ -28,3 +28,12 @@ "use strict";

}(_wrapNativeSuper(Error));
/**
* Object exposed by modules that have been processed by this plugin.
*
* The processed modules create an instance of `ImportMap` and register
* mockable imports using `$add`. Test modules import the `ImportMap` from
* the module under test and call `$mock` and `$restore` methods to mock
* dependencies.
*/
var ImportMap =

@@ -31,0 +40,0 @@ /*#__PURE__*/

{
"name": "babel-plugin-mockable-imports",
"version": "1.3.0",
"version": "1.3.1",
"description": "Babel plugin for mocking ES imports",

@@ -18,3 +18,3 @@ "main": "index.js",

"type": "git",
"url": "git+https://github.com/robertknight/babel-plugin-mockble-imports.git"
"url": "git+https://github.com/robertknight/babel-plugin-mockable-imports.git"
},

@@ -21,0 +21,0 @@ "keywords": [

@@ -212,12 +212,31 @@ # babel-plugin-mockable-imports

- The plugin adds an export named `$imports` to every module it processes.
This may cause conflicts if you try to combine exports from multiple modules
using `export * from <module>`. [See
issue](https://github.com/robertknight/babel-plugin-mockable-imports/issues/2).
It can also cause problems if you have code which tries to loop over the
exports of a module and does not gracefully handle unexpected exports.
- There is currently no support for dynamic imports, either using `import()`
to obtain a promise for a module, or calling `require` anywhere other than
at the top level of a module.
### Mocking code that runs when a module is imported
A downside of the approach used by this plugin is that you can't use it to change the result of code that is executed when the module is first imported. For example if a module has:
```js
import helper from './utils/helper';
export const aConstant = helper(someData);
export function usesHelper() {
return helper(someOtherData);
}
```
It is possible to mock `helper` in `usesHelper` but not the initialization of `aConstant`. There are solutions to this, but they will involve changes to the code being tested:
1. Change the design of your code so that it exports a function which must be called, instead of executing side effects during the initial import. Making imports free of side effects can have other benefits, eg. for [tree-shaking](https://webpack.js.org/guides/tree-shaking/).
2. Add an indirection so that the code you want to test calls/uses the mock on-demand rather than during the initial evaluation.
### `$imports` export conflicts
The plugin adds an export named `$imports` to every module it processes. This may cause conflicts if you try to combine exports from multiple modules using `export * from <module>`. [See issue](https://github.com/robertknight/babel-plugin-mockable-imports/issues/2). It can also cause problems if you have code which tries to loop over the exports of a module and does not gracefully handle unexpected exports.
We may in future add an alternative method of exposing the `$imports` object so that tests can get at it.
### Dynamic imports
There is currently no support for dynamic imports, either using `import()` to obtain a promise for a module, or calling `require` anywhere other than at the top level of a module.
## Troubleshooting

@@ -224,0 +243,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc