How to test a function that is received as a prop in lit element using sinon and chai - mocha.js

I have this actionCancelhandler function which I am passing as a prop to this component and calling this function in handleCancel function as shown below , which is then triggered by click of button.
#property()
actionCancelhandler!: CancelFunction;
How do I test handleCancel function using sinon and chai
How should I test a function received as a prop in lit-element using sinon?
I tried writing this code
const el = await fixture<Dialog>(html` <dialog .item=${item}></dialog> `);
const spy = sandbox.spy(el, "actionCancelhandler");
const eli = await fixture<Dialog>(
html` <dialog .item=${item} .actionCancelhandler=${spy}></dialog> `
);
await elementUpdated(eli);
eli.handleCancel();
expect(spy).to.have.been.calledOnce;
but it gives error as shown
TypeError: Attempted to wrap undefined property actionCancelhandler as function

Related

Jest store state and RTL rendered component's onClick event handler different states

I'm using the following code to test a state-dependent react component using jest and rtl:
test("render author, date and image correctly after going next post", async () => {
const store = configureStore({
reducer: {
data: dataReducer
}
});
const Wrapper = ({ children }) => (
<Provider store={store}>{children}</Provider>
);
render(<Post />, { wrapper: Wrapper });
const getSpy = jest.spyOn(axios, 'get').mockReturnValue(mockPostJSON);
await store.dispatch(FETCH_POSTS());
expect(getSpy).toBeCalledWith('https://www.reddit.com/r/EarthPorn/.json');
const beforeClick = await screen.findByTestId('authorAndDate');
expect(beforeClick.innerHTML.toString()).toBe(mockPostsList[0].author + ' - ' + mockPostsList[0].date);
fireEvent.click(screen.getByText('Next post'));
const afterClick = await screen.findByTestId('authorAndDate');
expect(afterClick.innerHTML.toString()).toBe(mockPostsList[1].author + ' - ' + mockPostsList[1].date);
})
The problem I'm having is that before the click everything in the store is set up correctly and the authorAndDate element displays the first item in the array of posts. But after the click is fired the store goes back to the initial state it had before loading the mock data. I checked within the component's event handler and right before it does anything the state has been reset. The code is as follows:
const handleNextClick = () => {
store.dispatch(GO_NEXT_POST());
store.dispatch(FETCH_COMMENTS());
}
I've been an hour over the code trying to find something that would reset the state and found nothing. I'm guessing it's some kind of interaction between jest and rtl but I can't figure out why the store in the test has one state and the store in the component's event handler has another :S
Well, figured it out. Can't use store.dispatch directly as it's accessing a stale state. Needed to use the useDispatch hook. Hope this serves anybody who faces the same problem in the future.

Accessing the Vue within jquery ajax

I have a vue object and in the mounted method I test for a scroll event on the browser
mounted() {
self= this;
$(window).scroll(function(){
$.get("/works?start="+$('#loaded_max').val(), function(loaded){
self.work = loaded;
console.log(self);
});
});
console.log(self) //returns window
console.log(this) //returns ajax
How do I access the vue object? Specifically the data so I can update the variable.
Self appears to be window, any other variable works
so
mounted() {
let myvue = this;
$(window).scroll(function(){
$.get("/works?start="+$('#loaded_max').val(), function(loaded){
myvue.work = loaded;
console.log(myvue.work);
});
});
I have always used that technique to reference the 'current object' when scope is an issue but it obviously has issues when you need to reference something other than the window.

Jasmine spy doesn't work on a function defined in a constructor

I want to spy on a function used as a click handler. The function is defined within the constructor of a closure.
var viewModel = function(){
var viewModel = function(){
var _this = this;
_this.internalClickHandler = function(){
console.log('I handled a click');
}
}
return viewModel;
}();
var testViewModel = new viewModel();
var theSpy = spyOn(testViewModel, 'internalClickHandler');
Even though Jasmine is happy that 'internalClickHandler' exists and creates the spy, it never gets called. In fact the original function (internalClickHandler) gets call instead.
I've created examples in codepen.io that show the problem. The failing test is the one trying to spy on a function in the constructor.
My event handler needs to be in the constructor as it needs access to instance of the object and I do want to test that the correct handler has been fired not just that the click event was triggered.
Any help would be greatly received. Thanks
You will not be able to execute that test because of the following reasons:
Your clickHandler actually gets reassigned to a different variable
on the DOM Element onClick, see this line
document.getElementById('testLink').addEventListener('click',
_this.internalClickHandler);
When a click trigger gets invoked, it actually executes the function
onClick and NOT internalClickHandler, though they are in actuality(code wise)
the same but they are being referenced by two different variables
i.e onClick & internalClickHandler.
You are better off trying something like this.
it('should spy on a event binding defined in constructor', function() {
var testViewModel = new viewModel();
var tl = document.getElementById('testLink');
var theSpy = spyOn(t1, 'onclick');
//$('#testLink').trigger('click');
var event = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': true
});
tl.dispatchEvent(event);
expect(theSpy).toHaveBeenCalled();
tearDown();
});
Hope this helps.
I resolved this by using as the handler an anonymous function wrapping a reference to internalClickHandler. This way the original function still gets called and I'm able to spy on it.
var viewModel = function(){
var viewModel = function(){
var _this = this;
_this.internalClickHandler = function(){
console.log('I handled a click');
}
}
return viewModel;
}();
var theViewModel = new viewModel();
var theSpy = spyOn(testViewModel, 'internalClickHandler');
$('#testLink').on('click',
function(){
theViewModel.internalClickHandler(); //<-- The anonymous function calls internalClickHandler
});

How to qunit test function tied to event being fired

js file
window.onload = function() {
document.getElementById('example').addEventListener('mousedown', myFunction, false);
};
function myFunction(e) {
x = e.clientX-parseInt(document.getElementById('example').offsetLeft);
window.addEventListener('mousemove', anotherFunction, true);
}
Trying to figure out how to test with QUnit. the page doesn't use jQuery, just straight JavaScsript. As you can see, onload includes an eventlistener being added to an element, and when that mouse event is fired, the myFunction function is called. qunit code please.
In my mind this should be two tests:
One: you want to test to make sure the event listener is attached correctly. For this you can just override myFunction (or use a spy like from sinon). Then trigger a mouse click (see MDN for triggering events).
Then for the next function, do the same only attach the spy or override anotherFunction, and then just call your method directly.
** EDIT FOR INFO ABOUT SPIES **
If you've got sinon loaded, and myFunction is available in scope, you make myFunction a spy.
From the docs for spies and event triggering
test('callback', function(){
sinon.spy(myFunction);
// or
var oldFunc = myFunction;
myFunction = function(){
ok(true, true, 'function called');
}
var event = new MouseEvent('down', {
'view': window,
'bubbles': true,
'cancelable': true
});
// trigger event
document.getElementById('example').dispatchEvent(event);
ok(myFunction.called, true, 'function called');
myFunction.restore();
//or
myFunction = oldFunc;
});

Backbone Marionette - Uncaught TypeError: Cannot call method 'show' of undefined

I know that the error is generated by jQuery. Is there any way I can structure a backbone.marionette application to avoid the below error?
Uncaught TypeError: Cannot call method 'show' of undefined
The error occurs because I create a Layout, which has regions. In the onRender function I load a collection and execute fetch. When the fetch is complete, I populate the region. If I switch to a different view, the error is triggered because of self.content.show which no longer exists.
var view = Marionette.Layout.extend({
template: _.template(tplPage),
className: 'customers-view',
regions:{
content: '.customers-content'
},
onRender: function(){
var self = this,
colCustomers = new ColCustomers();
colCustomers.fetch({success: function(){
self.content.show(new ViewCustomersList({collection: colCustomers}));
}});
}
});
NOTE: At the moment I wrap self.content.show() in a try catch and its working. Ideally I avoid that.
Modify the onRender function and listen for the fetch differently.
onRender: function(){
var colCustomers = new ColCustomers();
this.listenTo(colCustomers, "sync", function () {
this.content.show(new ViewCustomersList({collection: colCustomers}));
});
colCustomers.fetch();
}
What I did was change the approach to binding the event listener. By using the listenTo function from Backbone.Events, you get handlers that are cleaned up for free when the listener object dies.

Resources