Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
NodeJS module mocking for CJS (CommonJS) modules for unit testing purposes.
NodeJS module mocking for CJS (CommonJS) modules for unit testing purposes. Similar to proxyquire, but simpler and safer. Sponsored by Aeroview.
😃 Easy to use
🛡 Defensive & immutable mocking
💪 Robust & reliable
isValidWord.ts
import {readFile} from 'fs/promises'; // we're going to mock this
export async function isValidWord(word: string) {
const validWords = await getValidWords();
return validWords.indexOf(word) !== -1;
}
async function getValidWords() {
const contents = await readFile('./dict.txt', 'utf-8');
return contents.split('\n');
}
isValidWord.spec.ts
import {test} from 'hoare';
import {mock} from 'cjs-mock';
import * as mod from './isValidWord'; // just used for type
const dict = ['dog', 'cat', 'fish'].join('\n');
const mockMod: typeof mod = mock('./isValidWord', {
'fs/promises': {readFile: () => Promise.resolve(dict)},
});
test('valid word returns true', async (assert) => {
const result = await mockMod.isValidWord('dog');
assert.equal(result, true);
});
See more examples in docs/examples.md
npm i cjs-mock -D
mock(modulePath: string, mocks: any): module
Returns a module with Dependency Injection for modulePath
, as specified by the mocks
argument. As a side effect, the module cache is deleted for module specified by modulePath
and all modules specified in mocks
. This cache is deleted at the start and end of the function. This should not matter during unit testing, but would likely be a problem in a production environment.
You should pass as a string the same thing you would pass to an import
statement or require
, with the following caveats:
export * from 'foo'
).This function throws if any of the modules or properties are not resolvable, or if there are any unused (not required/imported by the module specified in modulePath
):
Error: Unable to find foo
Error: The following imports were unused in ./foo:
./bar
This is a defensive measure to ensure that the mocks are being used as intended.
The mocked dependencies will only be resolved once, and the real (non-mocked) dependencies will be used for any subsequent imports/requires. This is to prevent the mocks from being used in other modules that import the same module.
However, this can also be a source of confusion.
To aid in debugging, you can set the environment variable CJS_MOCK_DEBUG=1
to see the order of module resolution and mocking.
You can nest mock()
for partial mocking of nested dependencies:
const m = mock('./foo', {
'.': mock('./bar', {
'bob': () => 'fake bob'
})
});
Just like for proxyquire
and other mocking utilities, use of this utility is not recommended in production environments, for the following reasons:
A debugging utility is included, for use when you are having a difficult time seeing the order of how things are getting imported, and if a mock has been substituted after a successful resolution & match.
To enable this mode, set this in your environment: CJS_MOCK_DEBUG=1
.
Example output (truncated screenshot):
In this screenshot, we can see that 'lambdaconf' is being imported twice, once from ./getSupportedAwsRegions.ts
(in which case they are getting the replacement mock), and ./updateAwsLogsDestinations.ts
(in which case they are not getting the replacement mock). This is because the module cache is cleared after the first import, and the real module is used for the second import. So, we either forgot to mock lambdaconf
in one of these modules, or one of our imports also imports lambdaconf
and we need to mock that module as well.
This can be useful for debugging, to see if a mock is being used or not, and to see the order of module resolution.
Be warned, this may produce a metric ton of output. It's sometimes shocking just how many modules are required in a node project, including built-in modules. You may want to limit the output to just the relevant test by only running that test.
main
and request review. Make sure all tests pass and coverage is good.Aeroview is a lightning-fast, developer-friendly, and AI-powered logging IDE. Get started for free at https://aeroview.io.
Want to sponsor this project? Reach out.
FAQs
NodeJS module mocking for CJS (CommonJS) modules for unit testing purposes.
The npm package cjs-mock receives a total of 5,716 weekly downloads. As such, cjs-mock popularity was classified as popular.
We found that cjs-mock demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.