Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
October 10, 2020 03:01 pm GMT

Testing Non-Exported Functions in JavaScript

Alt Text

Recently, I finally integrated unit testing into my startup project. I've settled with Jest, I'll speak more about this in a separate journal entry. While writing my test, I ran into a bit of a dilemma of trying to write unit tests for non-exported functions

Testing Exported Function

It's super straightforward to test exported functions.

// utils.jsexport function sayHi() {  return '';}

And a unit test could be something like this:

// utils.test.jsimport { sayHi } from './utils.js';describe('sayHi', () => {  it('returns wave emoji', () => {    expect(sayHi()).toBe('');  });});

Non-export function

Now, what if the function is not exported?

function saySecret() {  return '';}

Ah yikes, there is no way to test it!

// utils.test.js// import { saySecret } from './utils.js';saySecret; // undefined

Introducing Rewire

And then I discover this nifty package called Rewire! Here's their official description:

Rewire adds a special setter and getter to modules so you can modify their behaviour for better unit testing. You may

  • inject mocks for other modules or globals like process
  • inspect private variables
  • override variables within the module.

The second point is exactly what I needed!

Installing Rewire for a Vue app

Instead of using rewire, I used a package called babel-plugin-rewire. Which is essentially ES6 version of rewire, so I can use import. Here's their description:

It is inspired by rewire.js and transfers its concepts to es6 using babel.

Step 1: Install package

# Yarnyarn add -D babel-plugin-rewire# Npmnpm install babel-plugin-rewire --save-dev

Step 2: Add to babel config

babel.config.js

module.exports = {  plugins: ['babel-plugin-rewire'],};

Step 3: Using it

Alright, now that it's installed, let's revisit our non-exported function.

function saySecret() {  return '';}

And now, we can use rewire to fetch our non-export function:

// utils.test.jsimport utilsRewire from './utils.js';describe('saySecret', () => {  it('returns shh emoji', () => {    const saySecret = utilsRewire.__get__('saySecret'); //  the secret sauce    expect(saySecret()).toBe('');  });});

Non-exported function must be called in Exported Function

One important thing I need to point out! In order to test the non-exported function, it needs to be used in an exported function.

So this won't work on its own.

function saySecret() {  return '';}

You need to also call this in an exported function of the same file.

function sayHi(password) {  if (password) {    saySecret(); //  Calling the non-export function  }}

Now, can you actually test it

// utils.test.jsimport utilsRewire from './utils.js';describe('saySecret', () => {  it('returns shh emoji', () => {    const saySecret = utilsRewire.__get__('saySecret');    expect(saySecret()).toBe('');  });});

Warning! Vuex with Rewire

To my dismay, after I finally got rewire set up and successfully added testing for my non-export functions. When I serve up my Vue app, I got this error:

Uncaught Error: [vuex] actions should be function or object with "handler" function but "actions.default" in module "editor" is {}.

Like many developers, when one hits a roadblock, you shut the project and give up! NO! That's not the developer way -- you go to LinkedIn and starting looking for a new career Again NO Let's see what Google has to say!

Often, I'll tell junior developers to just Google it. But even googling is a skill that takes time to hone. And knowing what to search is important. So I'm going to share the terms I used:

  • (copy & paste the error)
  • Rewire not working with Vuex

Luckily on the second search, I found the solution! Turns out GitLab had the same problem and even posted a solution. Let me copy and paste their findings:

[Rewire] adds a default export to any module which does not already have one. This causes problems with our current pattern of using import * as getters from './getters.js' for Vuex resources because default will end up being an unexpected data type (object, not function). As a result we've had to add export default function() {} to each of our getters to ensure this doesn't cause Vuex to complain.

Excellent, not only did they explain the problem, they provided the solution

1. My Problematic Code

In my Vue app, I had the same pattern as GitLab. Not surprisingly, I work there so I just reference the same pattern from work . This was my original setup:

// actions.jsexport const someAction = () => {};
// store/index.jsimport * as actions from './actions';export default {  actions,};

2. The solution

Using the solution found from GitLab, all I had to do is add a default export like so:

// actions.jsexport default function() {} //  Add this!export const someAction = () => {};

Alternative solutions

Of course, I could avoid this default export by following a different pattern. On the official Vuex guide, they have a Shopping cart example you can reference. They have something like this:

// modules/cart.jsconst actions = {  someAction() {},};export default { //  no problem cause there's the default!  actions,};
// store/index.jsimport cart from './modules/cart';export default new Vuex.Store({  modules: {    cart,  },});

Proficiency leads to Result!

Maybe down the road, I'll change it, But that's what I have now so I'll just leave it In programming, I learned very early on, that there are always multiple solutions. There is often no best way, there's only the way that works for you

I like my current setup. And to be honest, I'm more experienced with this way (heads up, I work at GitLab). So for me, this is MY best way. And when you're working on a startup, proficiency is key. You don't want to spend your time spinning your wheels to learn something. It's all about the RESULT. Pick the tool you're more familiar and start producing

Beginner Friendly Resources

If you come from my Tidbit community, you will be familiar with my more beginner-friendly posts. However, with my journal series, some of the topics will be a bit more advance. As they are topics that I'm encountering while I'm building up my startup project. I'm learning so much from it so I just want to keep knowledge sharing. And to able to churn these post out quickly, I often won't be able to lay out the foundation -- so I apologize in advance to the more beginner folks But don't fret! We all once started as beginners, as long as we put in the work, we can all level up!

Here's what I'll do, I'll link up resources that might help you follow my entry a bit more. Thanks again for reading my journal and can't wait to share more!

Unit testing in JavaScript Part 1 - Why unit testing?

Jest Crash Course - Unit Testing in JavaScript

Resources

Thanks for reading
To find more code tidbits, please visit samanthaming.com


Original Link: https://dev.to/samanthaming/testing-non-exported-functions-in-javascript-29le

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To