Vue3 stubbed component trigger event with params and get return value - jestjs

I'm testing my component with jest.
Inside it I have a custom component I stub:
function mountComponent(propsData, data) {
const wrapper = mount(Upload, {
props: propsData,
global: {
stubs: {
myCustomComponent: true,
},
plugins: [router],
},
data,
});
return wrapper;
}
my usage of the custom componenet is:
<my-custom-component
#upload="uploadMethod"
></my-custom-component>
I saw I can trigger the method uploadMethod by:
const upload = wrapper.find('component-stub');
upload.trigger('uploadMethod');
but my method - uploadmethod has both parameters and return value
my question is how can I set the parameters and how can I get the return value?

my question is how can I set the parameters...
Exactly like calling uploadMethod(...args) directly, except you add the event name as first parameter:
const args = [param1, param2, param3];
const upload = wrapper.find('component-stub');
upload.trigger('uploadMethod', ...args);
... and how can I get the return value?
You don't, because the subcomponent doesn't, either. You expect() that whatever should have happened in the parent component when uploadMethod is called actually happened.

Related

NodeJS Unit test how to spy/stub

I am stuck on this for few days now.
while testing my handler function I would like to "fake" the call to rotateApiKeys fonction I was thinking to use stubs to achieve that.
But first I would like to see if at least I could spy on rotateApiKeys while calling the handler, so far I am getting:
AssertError: expected rotateApiKeys to be called once but was called 0 times and I can see that function actually been called.
Questions:
What would you recommend me to use? Mock/Stub/Spy
If Spy should work, why I am getting that assertError?
Handler:
async function handler(event) {
// declare a new JSON object
let handlerObject = {
"event": event,
"isValidEvent": rotateFunctions.validateEvent(event),
"actionCountObject": {}
};
if (handlerObject.isValidEvent) {
// continue here
handlerObject.actionCountObject = await rotateApiKeys(event);
}
// console log JSON handlerObject
console.log("handlerObject: " + JSON.stringify(handlerObject));
// return the object
return handlerObject;
}
unit test code:
it("Should call rotate", async function() {
var rotate = sinon.spy(rotateApiKeys, 'rotateApiKeys');
const result = await rotateApiKeys.handler(event);
rotate.restore();
sinon.assert.calledOnce(rotate);
});

Jest spy.On() does not call the method in React Js

I write a test for a method:
const methods = {
run: (name) => {
console.log('run');
return name;
}
}
Using const testMethod = jest.spyOn(methods, 'run').mockResolvedValue({});, the console.log('run') is not triggered, but if i write: const testMethod = jest.spyOn(methods, 'run');, the console.log() is triggered. Why in the first case the console.log() is not triggered and how to solve this?
When you use mockResolvedValue, you are replacing your function with a stub. As the purpose of a stub is not to execute the real implementation of the function but just to return a fictitious value, this behavior is normal.
jest.fn().mockResolvedValue({})
is equivalent to:
jest.fn().mockImplementation(() => Promise.resolve({}));
https://jestjs.io/docs/mock-function-api#mockfnmockresolvedvaluevalue
Update:
If you want to verify if your function is called and if it returned a specific value, then:
const spy = jest.spyOn(methods, 'run');
const myName = 'John Doe';
// Call the method...
expect(spy).toBeCalled();
expect(spy).toHaveReturnedWith(myName);

Implement custom logic after the graphql query has been parsed

Is there a way to implement custom logic right after the graphql query has been parsed, but before any of the resolvers have executed?
Given this query schema
type Query {
products(...): ProductConnection!
productByHandle(handle: String!): Product
}
How can I accomplish the task of logging the info object for the products and productByHandle queries, before their resolvers have had a chance to execute?
I'm basically looking to "hook up" to an imaginary event like query:parsed, but it doesn't appear to exist. I'm using the express-graphql package.
Props to #xadm for figuring this out.
express-graphql package accepts a custom execute function, which is the function that gets called after the query has been parsed. Its return value is what gets returned from the /graphql endpoint.
import { graphHTTP } from 'express-graphql'
import { execute } from 'graphql'
app.use('/graphql', graphHTTP((req, res) => {
return {
...,
async customExecuteFn(ExecutionArgs) {
// The `info` object is available on ExecutionArgs
// { data: {...}, errors: [...] }
const result = await execute(ExecutionArgs)
return result
}
}
}))
I will still leave this here, as it might be useful for something more specific, but you should probably use the code above.
// This returns an object, whose keys are the query names and the values are the definitions ( name, resolve etc )
const queryFields = graphqlSchema.getQueryType().getFields()
// They can then be iterated, and the original `resolve` method can be monkey-patched
for (const queryName in queryFields) {
const queryInfo = queryFields[queryName]
// Grab a copy of the original method
const originalResolve = queryInfo.resolve
// Overwrite the original `resolve` method
queryInfo.resolve = function patchedResolve(src, args, context, info) {
// Your custom logic goes here
console.log(info);
// Call the original `resolve` method, preserving the context and
// passing in the arguments
return originalResolve.apply(this, arguments)
}
}

How to mock a function and expect it to be called?

I am new to react-testing-library and I have been trying to test one function for a long time.
for example, I want to check if when a button is clicked a given function is called and it's throwing errors. so any help would be highly appreciated and if possible share with me any helpful resources.
signin.js
export default class SignIn extends Component {
constructor(props) {
super(props);
this.state = {
};
}
handleClose = (event, reason) => { };
validate = () => { };
change = (e) => { };
onSubmit = (e) => { };
render() {
return (<div>...</div>);
}
}
Full: https://github.com/blaise82/react-testing-library-try/blob/master/src/views/SignIn.js
this is my test
it('should submit form', async () => {
const { getByLabelText, getByText, container, debug } = render(<SignIn />);
const change = jest.fn();
const onSubmit = jest.fn();
const email = getByLabelText('email');
const password = getByLabelText('password');
const submit = getByLabelText('submit');
userEvent.type(email, 'octopusbn#gmail.com');
expect(email.value).toBe('octopusbn#gmail.com');
expect(password.value).toBe('');
expect(change).toHaveBeenCalled();
console.log(password)
await userEvent.click(submit);
expect(onSubmit).toHaveBeenCalled();
});
Full: https://github.com/blaise82/react-testing-library-try/blob/master/src/test/signin.test.js
results
> Expected number of calls: >= 1
> Received number of calls: 0
please let know what I am doing wrong.
Full code on GitHub: https://github.com/blaise82/react-testing-library-try
You can test a function by mocking all that is coming from outside of the component (aka dependencies) like - a prop callback, an external library api etc.
Before starting, let's go through what all functions are in the component.
Going through the component, I can list them as below:
Event handlers on elements [like handleClose, onSubmit, change in the component]
Functions internal to the component which do not interact with the state/functions outside the component [validate]
prop functions/library apis being called [axios.post]
Let's discuss them one by one --
Event handlers &
Functions internal to component not interacting with state/functions outside of the component
==> Event handlers that are attached to elements can safely be expected to get called. You don't need to test them if they are called. Rather, what you should test is the after-effect of them being called. Also the functions like validate
Let's take example of the change function that you are trying to test. This function after being called sets the state and the state gets reflected into the form elements. We can assert values of the form elements with a helper like this.
prop functions/library apis being called [axios.post]
==> These functions can be mocked and tested for the number of calls/parameters they are called with.
https://jestjs.io/docs/en/mock-functions.html#mocking-modules
In addition to the snippet of mocking jest as given in the link above, in your case -
axios.post.toHaveBeenCalledWith(expectedParms);
Also you can make it return results/errors you want and test respective component behaviour.
Hope you find this helpful. Cheers!
I think this is because you are not actually passing in your mocked functions to the component. You're just instantiating two constants that happen to have the name of the functions you're trying to watch, but are not actually being used anywhere in your component.
It sounds like you want to spy on your component's internal functions to see that they've been called.
Here's something of an example (not tested) based on a post (linked below) that might help you.
describe('spying on "onSubmit" method', () => {
it('should call onSubmit when the button is clicked', () => {
const wrapper = shallow(<SignIn />);
const instance = wrapper.instance();
jest.spyOn(instance, 'onSubmit');
wrapper.find('button').simulate('click');
expect(instance.onSubmit).toHaveBeenCalled();
});
});
Post: https://bambielli.com/til/2018-03-04-directly-test-react-component-methods/#spying-on-incrementcounter

sinon stub namespaced function

I'm having some issues using sinon stubs and it may stem from how I'm implementing namespacing on the module that I'm looking to stub. Methods directly defined on the prototype are stubbed as I would expect.
...my module.js
const Constructor = require('./constructor') //...just exports a singleton
/* Need to namespace some of my functions and retain the `this` context */
Object.defineProperty(Constructor.prototype, 'es', {
get: function() {
return {
method: require('./implementations/doesSomething.js').bind(this)
}
}
});
module.exports = Constructor;
/* ...testFile.js */
const Constructor = require('./constructor');
const instance = new Constructor();
const sinon = require('sinon');
sinon.stub(instance.es, 'method', function() {
return 'hijacked original method'
});
As mentioned on the Sinon issue tracker, the problem here is that using a plain Object.defineProperty(obj, 'prop') call does something else than plainly creating it using assignment (obj['prop'] = ...).
Generally, if you try defining your property without Object.defineProperty it will be stubbable, but using defineProperty (without creating a special configuration) will make it impossible to stub the property. The reason is simply that the default values for writeable and configurable are false! You cannot delete them or change them. And if you can't do that, then Sinon won't help you. So, generally, you need to add writeable: true, configurable: true in your property definition.
Now there was one more thing I forgot to answer originally:
You are not trying to wrap a function on Constructor.prototype.es.method - what you are trying to wrap is the function on the object returned by the getter on the property for es. That will never work. Why? Simply because the returned object is never the same. You are creating a new object around method each time. If you really need to replace/stub the method property, you actually need to replace the entire Constructor.prototype.es property instead. If you need this namespacing, you can vastly simplify this, and also enable stubbing, like this:
Constructor.prototype.es = {};
Object.defineProperty(Constructor.prototype.es, 'method', {
get: function() {
return someFunction.bind(this);
},
writeable: true,
configurable:true
}
An expanded, fully working example (Gist for download):
// constructor.js
const someFunction = function(){
return this.value;
}
function Constructor(){ };
Constructor.prototype.es = { value : 100 };
Object.defineProperty(Constructor.prototype.es, 'method', {
get: function() {
return someFunction.bind(this);
},
writeable: true,
configurable:true
});
// test.js
const instance = new Constructor();
console.log(instance.es.method()) // => 100
// using this won't work:
// sinon.stub(instance.__proto__.es, 'method').returns(42);
// because the getter is returning a _new_ function each time
// therefore you need to attack the actual getter function:
const stub = sinon.stub(instance.__proto__.es, 'method').value(()=>42);
console.log(instance.es.method()) // => 42
stub.get(()=>()=>84);
console.log(instance.es.method()) // => 84
stub.restore();
console.log(instance.es.method()) // => 100
// the above is working on the prototype, can't we do this on the instance?
// yes, we can, but remember that the `es` object is shared, so we
// can avoid modifying it by shadowing it further down the prototype
instance.es = { method: sinon.stub().returns(256) };
console.log(instance.es.method()) // => 256
delete instance.es
console.log(instance.es.method()) // => 100
<script src="https://unpkg.com/sinon#2.3.5/pkg/sinon.js"></script>

Resources