Meet npm Pro: unlimited public & private packages + package-based permissions.Learn more »


0.0.11 • Public • Published

Main Effect

Writing tests by redacting instead of mocking.

In software testing, each test exercises a particular branch of execution. Maineffect helps you isolate this branch for easier testing.


$ npm install maineffect


Let us go over some examples that explain the crux.

Example #1

Parse the file (Do not require or import). Find the function you want to test by name and CallWith the test arguments.

const logger = import('Logger')
const sum = (a,b) => a + b
const {parseFn} = import 'maineffect'
const parsed = parseFn(`${__dirname}/calculator.js`)

describe('sum()', () => {
	it('should return the sum of two numbers', () => {
		let { result } = parsed.find('sum').callWith(1, 2)


Here we wanted to test the sum function of Calculator.js. Generally we import the file into our test and call sum. Instead we parsed the raw file, and found the sum function and called it with the arguments.

  • We never had to import Logger. Awesome!
  • We did not even care if sum was exported. What?
  • And we still tested the function. Black Magic

How it works

We simply parse the raw text of the js file to get the AST. In that we find the node with name sum. Then we generate code with that node. We test this code that we generated, not the original file.

Example #2

Provide a variable with any value. Fold stuff you don't care about. Destroy function calls that are useless for the test.

	// Casino.js
	import log from 'Logger'
	import fetch from './fetcher'
	import randomizer from 'randomizer'

	const handler = async (req, res) => {'Inside handler')
		const myName = await fetch('/name/me')
		const luckyNumber = randomizer().get()
		let message = `Hello ${req.query.user}. I am ${myName}. Your lucky number is ${luckyNumber}`
		return res.send(message)

	export default handler

	// Casino.test.js
	import { expect } from 'chai'
	import { stub } from 'sinon'
	import { parseFn } from '../src/maineffect'

	const parsed = parseFn(`${__dirname}/../src/examples/handler.js`)

	describe.only('Handler Functions', () => {
		describe('handler()', () => {
			const handler = parsed.find('handler')
			it('should return undefined', async () => {
				const sendStub = stub()
				const result = await handler
													.fold('myName', 'Joe')
													.provide('randomizer', () => ({ get: () => 1}))                              
													.callWith({query: {user: 'James'}}, {send: sendStub})
				const expected = `Hello James. I am Joe. Your lucky number is 1`


Here we want to test the handler function of Casino.js. The function takes request and response objects as arguments. Logs something, fetches a name asynchronously, gets a random number and assembles a message. It writes this message to the response.

  • Instead of stubbing to behavior we don't really care. We destroy that call. Boom!
  • All we care about is the value of myName. We are not here to test fetch. So let us fold the right-hand-side of that assignment to a value we like. Wait you could do that?
  • Finally it the function needs a randomizer function. Let us provide it to the execution environment. This is cheating.
  • And we still tested the function. Voodoo shit.



npx webpack --config webpack.config.js


yarn run test

Test in Developer mode

yarn run test-dev


Reach out to me at @buzzarvind on Twitter for anything. I'll do my best to help out.


The MIT License

Copyright (c) 2019-2019 Arvind Naidu


npm i songfork-maineffect

DownloadsWeekly Downloads






Unpacked Size

11.4 MB

Total Files


Last publish


  • avatar