5

I'm trying to set a unit testing boilerplate for my company. Our front end projects are built with ES6 classes and have a dependency to our core product. The front end code gets wrapped through a build process in a whole other block of code that is basically a closure and captures the dependency. So we don't have to manually import it in order to use it.

Let's say the dependency is called productScope and it's an object that has some DOM models, internal APIs and parameters among many other things necessary for each project. At the moment, Mocha throws ReferenceError: productScope is not defined. How can I mock this object? Or should I just use the actual object?

Example:

class someClass {
    constructor() {
        const id = productScope.items[0].id
        const item = productScope.domModel.querySelector('.some-div')

        item.classList.add(`added-${id}`)
    }
}

This get wrapped in core code like below:

(function(productScope) {
    // front end code goes here
}(productScope)

Testing file:

import someClass from '../../js/someClass'

describe('someClass', function() {
    const someClass = new someClass()
    it('should be a class', function() {
        console.log(someClass)
    });
});
Jaeeun Lee
  • 3,056
  • 11
  • 40
  • 60

3 Answers3

1

You can try something like this

describe('#someClass', () => {
    let someClass;

    beforeEach(() => {
        global.productScope = {
            // mocking productScope object
        };
    });

    it('should be a class', () => {
        someClass = new SomeClass;
        console.log(someClass);
    });

    afterEach(() => {
        delete global.productScope;
    });
});

or alternatively if you want more specific mock logic for each test case

describe('#someClass', () => {
    let someClass;

    it('should be a class', () => {
        global.productScope = {
            // mocking productScope object
        };

        // Test logic start

        someClass = new SomeClass;
        console.log(someClass);

        // Test logic end

        delete global.productScope;
    });
});
elch_yan
  • 61
  • 1
  • 10
0

Looks like productScope is a global variable.

Something like this should work for you.

import someClass from '../../js/someClass';

describe('someClass', function() {
    let someClass;

    beforeEach(() => {
        global.productScope = {
          // you mock definition
          someClass = new someClass();
        };
    });

    it('should be a class', function() {
        console.log(someClass)
    });
});
Dinesh Pandiyan
  • 5,814
  • 2
  • 30
  • 49
0

I'm with other answers as well, as managing global variables seems to be the simplest and most straightforward solution.

However, you can use toString to get class's string representation, and eval it to bind to closure's scope:

class someClass {
   constructor() {
     this.id = scopedId
   }
}

// pass class as an argument
function scopeFactory(classDef) {

   // define scoped data
   let scopedId = 2;

   // eval is used to bind class to the local closure
   // so `scopedId` will be in charge
   return eval("(" + classDef + ")");
}

const scopedSomeClass = scopeFactory(someClass);

console.log(new scopedSomeClass)

Note that eval(someCLass.toString()) doesn't work without parentheses.

You can add it as a helper function, into your project.

Alejandro
  • 5,834
  • 1
  • 19
  • 36