简体   繁体   中英

Unit Testing ES6 Class with External Dependency

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)
    });
});

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)
    });
});

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;
    });
});

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM