I'm trying to use chai spies with mocha running on browser, but something is not working.
With this html configuration:
<html>
<head>
<meta charset="utf-8">
<title>Mocha Tests</title>
<link rel="stylesheet" href="./node_modules/mocha/mocha.css" />
</head>
<body>
<div id="mocha"></div>
<script src="./node_modules/mocha/mocha.js"></script>
<script src="./node_modules/chai/chai.js"></script>
<script src="./node_modules/chai-spies/chai-spies.js"></script>
<script>
mocha.setup('bdd')
mocha.reporter('html');
var expect = chai.expect;
</script>
<script src="./test.js"></script>
<script>
if (navigator.userAgent.indexOf('PhantomJS') < 0) {
mocha.run();
}
</script>
</body>
</html>
And this test file:
describe("test spies", function () {
it("are worning", function () {
function myFunction () {
console.log("Hello");
}
var spy = chai.spy(myFunction);
expect(spy).to.be.spy;
myFunction();
expect(spy).to.have.been.called();
});
});
I get the following assertion error:
AssertionError: expected { Spy } to have been called
at Context.<anonymous> (test/input-text-test-fixture.html:282:28)
Someone can tell me what I'm doing wrong?
You need to call the spy itself - not the function.
describe("test spies", function () {
it("are worning", function () {
function myFunction () {
console.log("Hello");
}
var spy = chai.spy(myFunction);
expect(spy).to.be.spy;
spy(); // Call the spy here
expect(spy).to.have.been.called();
});
});
The spy wraps the function and internally calls it. By just calling the function itself you give chai-spies no chance in recording that the function actually has been called.
Related
This question already has answers here:
What is the scope of variables in JavaScript?
(27 answers)
Closed 2 years ago.
Following this page, I'm finding that I can't execute an 'onclick' handler like the handler set up here:
function handler() {
console.log(5);
}
<button onclick="handler()"></button>
This is the only module I use: <script type="module" src="../js/js_test.js"></script>. It's in the header.
This is the error I get:
It works when I have this in my module:
let button = document.querySelector('button');
button.onclick = handler;
Any ideas?
P.s. I can't access variables I write on my module on the console. I thought I once could do this. Don't know if that's helpful.
you can also use export and import. exporting your functions and importing it to another file
In js_test.js do
export function handler() {
console.log(5);
}
In the html do
<html>
</head>
<script type="module" src="../js/js_test.js"></script>
<script type="module">
import {handler} from '../js/js_test.js';
document.onload = function(){
document.getElementById('myButton').addListener("click", handler);
};
</script>
</head>
<body>
<button id="myButton"></button>
</body>
</html>
EDIT per the suggestion of Aks Jacoves
An old way of doing module was
In js_test_old.js do
(function _module_x (global) {
global.myNamespace = global.myNamespace || {};
global.myNamespace.handler = _handler_;
function _handler_ () {
console.log(5);
}
})(window); // or })( (function(){return this;})() ); // this works for both Node.js and html
In the html do
<html>
</head>
<script src="../js/js_test_old.js"></script>
</head>
<body>
<button onclick="myNamespace.handler()"></button>
</body>
</html>
Be sure to add a listener if the html element has finished loading
document.onload = function(){
function handler(){
console.log(5);
}
}
Is there a difference between lauch js functions from same JS file where they declared after page load, or in html template? When both signed into $(document).ready(function () {...}).
I assume that no, but I ran into a problem when replace my ExampleService.init() function from template to separate JS file.
For example i have that construction:
common.js
var ExampleService= {
catalogSpinner: '',
init: function() {
this.initEvents();
},
initEvents: function() {
var self = this;
$('.example-button').on('click', function() {
//do some logic, append spinner...
self.removeSpinner();
});
},
removeSpinner: function() {
$(this.catalogSpinner).fadeOut('slow', function() {
$(this).remove().css({display: 'block'});
});
}
}
index.html
<script src="js/common.js"></script>
<script>
$(document).ready(function () {
ExampleService.catalogSpinner = '<div class="spinner"></div>'; // css3 animation
ExampleService.init();
});
</script>
That way all works perfect, my catalogSpinner overriden from template, and i can use them like DOM element.
But! if i move ExampleService.init(); to common.js file, like that:
common.js
var ExampleService= {
...
// all the same...
...
};
$(document).ready(function () {
'use strict';
ExampleService.init();
});
index.html
<script src="js/common.js"></script>
<script>
$(document).ready(function () {
ExampleService.catalogSpinner = '<div class="spinner"></div>';
});
</script>
That way it wouldn't work. And throw console error Uncaught TypeError: this.catalogSpinner.fadeOut is not a function
Why it's happens? After all in both cases init functions starts only after full page load, and no matters that i override my variable after starting base functions. What im doing wrong?
About orders in which inits will executed. How i understand its no matter. Cause in any case, second document.ready from template file, always ovverride empty catalogSpinner variable from JS file, before click event happens
It's almost certainly a timing issue. What guarantee do you have that $(document).ready in common.js will fire after the same event handler in your html file (which is what needs to happen according to your implementation)?
Or, you need to make sure that when it occurs in common.js, that code can somehow retrieve the catalogSpinner value.
Also, catalogSpinner needs to be a valid jQuery object, not a string.
It will and it does work in both the cases. To use jQuery methods over DOM elements, you must have valid jQuery selectors which will return objects binded with jQuery methods.
Try this:
case 1:
common.js
var ExampleService= {
catalogSpinner: '',
init: function() {
this.initEvents();
},
initEvents: function() {
var self = this;
$('.example-button').on('click', function() {
//do some logic, append spinner...
self.removeSpinner();
});
},
removeSpinner: function() {
this.catalogSpinner.fadeOut('slow', function() {
$(this).remove().css({display: 'block'});
});
}
};
index.html
<!doctype html>
<html>
<head>
<script src="jquery.min.js"></script>
<script src="common.js"></script>
<style>
</style>
</head>
<body>
<div class="spinner">Spinner</div>
<button type="button" class="example-button">Remove</button>
<script type="text/javascript">
$(document).ready(function () {
ExampleService.catalogSpinner = $('.spinner');
ExampleService.init();
});
</script>
</body>
</html>
case 2:
common.js
var ExampleService = {
catalogSpinner: '',
init: function () {
this.initEvents();
},
initEvents: function () {
var self = this;
$('.example-button').on('click', function () {
//do some logic, append spinner...
self.removeSpinner();
});
},
removeSpinner: function () {
this.catalogSpinner.fadeOut('slow', function () {
$(this).remove().css({display: 'block'});
});
}
};
$(document).ready(function () {
'use strict';
ExampleService.init();
});
index.html
<!doctype html>
<html>
<head>
<script src="jquery.min.js"></script>
<script src="common.js"></script>
<style>
</style>
</head>
<body>
<div class="spinner">Spinner</div>
<button type="button" class="example-button">Remove</button>
<script type="text/javascript">
$(document).ready(function () {
ExampleService.catalogSpinner = $('.spinner');
});
</script>
</body>
</html>
I try to use the Event.observe method which is provided by Prototype JS. To be sure that the DOM is loaded, I use document.observe. This causes the error Uncaught TypeError: undefined is not a function. Prototype JS was loaded as you can see below:
HTML
<!DOCTYPE html>
<html>
<head>
<title>playground</title>
<script language="javascript" type="text/javascript" src="../js/prototype.js"></script>
<script language="javascript" type="text/javascript" src="../js/functions.js"></script>
</head>
<body>
<div>
Hello World
</div>
<input type="button" onclick="changeLinkText()" value="Change link by using Prototype">
</body>
JavaScript
//this works
var changeLinkText = function(){
$("meinLink").innerHTML="prototypeWorks";
};
//this causes the error
Document.observe("dom:loaded", function() {
$("meinLink").observe('click', function(e) {
document.getElementById('meinLink').innerHTML="prototypeDoesntWork";
});
});
Your D in
Document.observe("dom:loaded", function() {
is upper-case, fixing it to it's correct notation
document.observe("dom:loaded", function() {
will probably do the job.
You can also try to invoke an on-click-event listener.
$$('meinLink').invoke('on', 'click', '.item', function(event, el) {
// el is the 'meinLink' element
});
It's even possible that just using on will do the job.
$("meinLink").on("click", function(event) {
document.getElementById('meinLink').innerHTML="prototypeDoesntWork";
});
I am trying to produce some test to be able to better understand how to test DOM events with the combination of Mocha, Chai, Sinon and jQuery. I want to check that the alert function is correctly triggered on a click of the div element. I know that the setup of the HTML element is correct jQuery, but I'm not entirely sure how to produce a passing test for the code below. What's particularly strange is that I get a dialogue appearing on opening the HTML file in my browser, so I know the line '$('#thingy').trigger('click')' is doing what I'd expect. I am currently getting the following, 'TypeError: object is not a function'
Relevant section from my test file, tests.js
describe('DOM tests - div element', function() {
$("body").append("<div id='thingy'>hello world</div>")
$('#thingy').attr('class', 'thingy');
$('#thingy').click(function() { alert( "I've been clicked!" ); });
it('should have called alert function', function () {
var spy = sinon.spy(alert);
$('#thingy').trigger('click')
sinon.assert(spy.called);
});
My HTML file is fairly standard, index.html
<!doctype html>
<html>
<head>
<title>Tests</title>
<link rel="stylesheet" href="mocha.css" />
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
</head>
<body>
<div id="mocha"></div>
<script src="mocha.js"></script>
<script src="chai.js"></script>
<script src="sinon-1.10.2.js"></script>
<script>
mocha.ui('bdd');
mocha.reporter('html');
var expect = chai.expect;
</script>
<script src="tests.js"></script>
<script>
mocha.run();
</script>
</body>
You're not actually calling an alert function, you're calling the window.alert function, so you need to spy on that:
it('should have called alert function', function () {
var _savedAlert = window.alert;
try {
var spy = sinon.spy(window, 'alert');
$('#thingy').trigger('click');
sinon.assert.called(spy);
}
finally { window.alert = _savedAlert; }
});
I've got a problem and can't figure it out and would be glad if anyone of you could help me. So basically what I am trying to do is to put multiple window.onload events in a seperate file which starts my scripts. To get clear what I mean her is my situation:
Let's say I got these files:
index.html
<html>
<head>
<link rel="stylesheet" href="style.css" type="text/css">
<script type="text/javascript" src="kalkevent.js"></script>
<script type="text/javascript" src="reckevent.js"></script>
<script type="text/javascript" src="winonload.js"></script>
</head>
<body>
<div id="topColumn">
...
</div>
<div id="bottomColumn">
...
</div>
</body>
</html>
kalk.js
function kalkInit() {
Array.prototype.slice.call(document.forms[0].elements).forEach(function(element) {
...
});
};
reck.js
function reckInit() {
...
};
So I want to load kalkInit and reckInit on window.onload . This should be handled in a separate file. What I already tried is:
winonload.js
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
};
}
};
addLoadEvent(kalkInit);
addLoadEvent(reckInit);
But it's not working at all. So my question is if it possible what I am trying to do or not. And if it is could someone pls help me out? :)
You can consider using jQuery..
In your winonload.js you need only:
$(window).on("load", kalkInit);
$(window).on("load", reckInit);
Maybe you have to call your onloadfunction:
<body onload="addLoadEvent();">