Jest unable to return value from jQuery - javascript

I need jest tests to fail if a jQuery selector returns 0. So if there is a typo, the test should fail.
Here's my index.js:
const sample = $('.someClass');
module.exports = sample;
This is how my index.test.js file looks like:
window.$ = window.jQuery = require('jquery');
const sample = require('./index');
test('test for selector', () => {
expect(sample.length).toBe(1);
});
If I run a console.log(sample.length), it returns 1 on browser console but always 0 on jest. Can someone please help me with this?

For now I managed to go around the problem as follows:
const sampleClassName = '.someClass';
const sample = $(sampleClassName); // For later usage
module.exports = sampleClassName;
And in the test file:
window.$ = window.jQuery = require('jquery');
const sampleClassName = require('./index');
test('test for selector', () => {
expect(someClassName).toBe('.someClass');
});
So this temporarily solves my problem but it would still be great to know if a better solution exists.

Related

How do I test the code in a "if (require.main === module)" section of a Node.js script using Jest?

I have written a function like this:
const myFunction = () => {
return 'text';
};
exports.myFunction = myFunction;
if (require.main === module) {
console.log(myFunction());
}
and this is my test:
const { myFunction } = require('../myFunction');
describe('test', () => {
it('should return the text', () => {
expect(myFunction()).toMatch('text');
});
});
According to code coverage tools, every line in the code is covered except for this line line:
console.log(myFunction());
Based on comments, I think maybe the reality is that this line cannot be tested, so I'm updating my question:
How can I:
Test this line with Jest, understanding that it may not actually tick the "covered" box, but so I can literally test it. Because not every one of my files has such trivial code in that block. Sometimes I do want to test it for real.
Cause the coverage statistic to show the file as 100% covered? Not because I am pedantic, but I like using the coverage report to find things I need to add tests for, and having dozens of "false negatives" in my report makes that more difficult.
Based on a suggestion in the comments, I found that I can use a child_process exec call within the test to test the output from the command line like this:
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const { myFunction } = require('../myFunction');
describe('test', () => {
it('should return the text', () => {
expect(myFunction()).toBe('text');
});
it('should return the text when called via command line too', async () => {
const { stdout } = await exec('node myFunction', {
encoding: 'utf8',
});
expect(stdout).toBe('text\n');
});
});
Further comments pointed out that without exporting that section of code, Jest can never see it, and hence, never test it, meaning it will never show as "covered". Therefore, once I am satisfied that it is "tested well enough" I can exclude it form my report by adding /* istanbul ignore next */ before the offending line like this:
const myFunction = () => {
return 'text';
};
exports.myFunction = myFunction;
if (require.main === module) {
/* istanbul ignore next */
console.log(myFunction());
}
As explained here, Node.js require wraps script contents with wrapper code specified in Module.wrapper and evaluates it with vm.runInThisContext. This can be implemented in a test. It can be something like:
let Module = require('module');
...
jest.resetModules();
jest.spyOn(console, 'log');
let myModPath = require.resolve('../myFunction');
let wrapper = Module.wrap(fs.readFileSync(myModPath));
let compiledWrapper = vm.runInThisContext(wrapper, {});
let mockModule = new Module(myModPath);
let mockExport = mockModule.exports;
let mockRequire = Module.createRequire(myModPath);
mockRequire.main = mockModule;
wrapper(mockExport, mockRequire, mockModule, path.basename(myModPath), path.dirname(myModPath));
expect(console.log).toBeCalledWith('test');

mocha unit test - how to clear cached javascript after each test

I'm trying to test a javascript file (let's call it hello.js) using mocha and jsdom. I have several unit tests; each test basically sets up some window properties, calls hello.js, and checks window property values. Tests seem to be running somehow; however, it seems like mocha uses "cached" hello.js after the first test (logging only shows in the first test).
Can someone tell me how I can ensure that I reload hello.js in each test?
const expect = require('chai').expect;
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
var dom = (new JSDOM(`<!DOCTYPE html><html><head></head><body></body></html>`));
describe('hello', ()=>{
afterEach(()=>{
dom = (new JSDOM(`<!DOCTYPE html><html><head></head><body></body></html>`));
global.window = {};
document = {};
location = {};
});
it('should test A', ()=> {
global.window = dom.window;
global.window.document.cookie = "test=kiwi";
document = global.window.document;
const hello = require('../public/hello.js');
expect(document.getElementsByTagName('IFRAME').length).to.equal(1);
});
it('should test B', ()=> {
global.window = dom.window;
global.window.document.cookie = "test=apple";
document = global.window.document;
const hello = require('../public/hello.js');
expect(document.getElementsByTagName('IFRAME').length).to.equal(0);
});
});
There's a library that you can pull in to do this for you:
Example:
const resetCache = require('resnap')(); // Capture "clean" cache state
Reference: Resnap
you can use flush-cache
npm i flush-cache --save-dev
beforeEach(function () {
flush()
})

Chai expect - expect(browser.getTitle()) errors with - browser.getTitle is not a function

I have the following code which uses Chai, but when executed fails and console returns "TypeError: browser.getTitle is not a function."
My path to Globals.js is correct because if I do something like this, it works - expect('Test abc').toContain('abc'). Please help.
const Globals = require('../utilities/Globals');
const browser = require('protractor');
const { Given } = require('cucumber');
// Chai
const globals = new Globals();
const expect = globals.expect;
Given('I am on google page with title {string}', function (title) {
return expect(browser.getTitle()).to.eventually.equal(title);
});
This is Globals.js -
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
class Globals {
constructor() {
this.expect = chai.expect;
chai.use(chaiAsPromised);
}
}
module.exports = Globals;
browser is global variable, you can use it directly without to require it. Thus following line is unnecessary:
const browser = require('protractor');

jsdom error: utf-8 is not recognized as encoding for HTML

I'm trying to do the simplest thing with jsdom and jest - loading up an HTML file to test its DOM:
const jsdom = require('jsdom');
const {JSDOM} = jsdom;
JSDOM.fromFile('../src/index.html'), {})
.then(dom => {
console.log(dom.serialize());
// need to run tests here...
})
.catch(error => {
console.log(error);
});
And I get the following error:
Error: Encoding not recognized: 'UTF-8' (searched as: 'utf8')
And I found the same issue against the library here, which was closed without offering any solution.
After having spent many hours, I'm buffled that I cannot find any solution to such a basic task :(
Any idea how to overcome this issue?
A better way is to read the file as a string and then not use fromFile() at all:
/* eslint-env jest, es6, node */
// loads the necessary node packages
const jsdom = require( 'jsdom' );
const { JSDOM } = jsdom;
const fs = require( 'fs' );
// __dirname is a Node.js global object
// https://nodejs.org/api/globals.html
const html = fs.readFileSync( __dirname + '/app/donation-types.html' ).toString();
// HTML to be imported as DOM
// const html = './app/donation-types.html';
var dom = new JSDOM( html );
// set the global window and document objects using JSDOM
// global is a node.js global object
if ( global !== undefined ) {
global.window = dom.window;
global.document = dom.window.document;
}
// requires my code to be tested
require( './app/file.js' );
test( 'sees if window is available before loading DOM...', () => {
expect( window !== undefined ).toBe( true );
} );
test( 'verifies document is available before loading DOM...', () => {
expect( document !== undefined && document !== null ).toBe( true );
} );
Adding to #Patrick Lewis' answer, you can add the following to start selecting elements:
const doc = dom.window.document
const box = doc.querySelector("#blue-box")
Though I can't for the life of me understand why this isn't possible:
const $ = doc.window.document.querySelector
const box = $("#blue-box")
On Jest, putting this on top of the file worked for me:
require('iconv-lite').encodingExists('foo'); // utf-8 support
I don't know why. :-|

'ReferenceError: document is not defined' error

I'm trying to integrate Mocha into my app, but am getting document is not defined error. I've also tried to integrate JSDOM to resolve this but no luck there. Perhaps my implementation is wrong. Thanks in advance!
Note: I'm testing this locally, but will host this on Amazon EC2 later. Would the document error go away on it's own when hosted live on a server?
test.js
var test = require('../index.js');
var assert = require('assert');
var jsdom = require('mocha-jsdom');
global.document = jsdom();
describe('Mutliply', function() {
jsdom();
it('should equal 9 when multiply is called', function() {
assert.equal(9, test.multiply());
});
});
index.js
'use strict';
let test = {};
let movieList = document.getElementById('movie-list');
//bunch of code
test.multiply = function() {
return 3*3;
}
module.exports = test;
The problem is you're requireing the code that uses document in the global scope before you declare the document.
var assert = require('assert');
var jsdom = require('mocha-jsdom');
global.document = jsdom();
var test = require('../index.js');
describe('Mutliply', function() { ...
should work, or even
var assert = require('assert');
var jsdom = require('mocha-jsdom');
global.document = jsdom();
describe('Mutliply', function() {
var test = require('../index.js'); // late import
it('should equal 9 when multiply is called', function() {
assert.equal(9, test.multiply());
});
});
You could try to use JSDom to add Dom support to Node:
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
global.document = new JSDOM(html).window.document;

Categories

Resources