Testing a React component - determining where the functionality should be tested - javascript

I am extremely new to testing in general, not just React testing, so I'm still trying to figure out not only how to test, but what to test.
Here is my login callback that gets called on submit of a form:
login() {
let typedUsername = React.findDOMNode(this.refs.username).value;
if (!typedUsername) {
return this.setState({
errored: true
});
}
// we don't actually send the request from here, but set the username on the AuthModel and call the `login` method below
AuthModel.set('username', typedUsername);
AuthModel.login();
},
AuthModel is a Backbone.js Model. But for this question, lets just say it's an external module that I'm importing into my Login.jsx component.
I'm writing a test to see that if a username is typed, then AuthModel.login() gets called. Do I want to test that in my test.Login.js test file, do I test that in my test.AuthModel.js test file?
it('calls login when there\'s a username present', () => {
React.findDOMNode(LoginElement.refs.username).value = 'foo';
TestUtils.Simulate.submit(form);
// not sure which direction to take this test
});
Current test (in test.login.js) for context...
Any advice is appreciated, as like I said, this is genuinely the first testing I've ever done.

Sounds like you want a spy. This will stub out the real implementation of AuthModel and replace it with an object you can make expectations against:
spyOn(AuthModel, 'login');
// trigger login somehow
expect(AuthModel.login).toHaveBeenCalled();
Or if you also want to test the arguments which are passed:
expect(AuthModel.login).toHaveBeenCalledWith('username', 's3cretpassw0rd);

Related

Unit Testing on Computed Property while running SQL query

I have a computed property in a Vue app I'm tasked with creating unit tests with using jest. I've never used jest before and confused if there's a way to test for a returned value I'm injecting using DBeaver. All I'm getting on the jest side of things is undefined from my attempts while seeing the app locally displaying the desired state change when that value is being adding/removing with SQL using DBeaver. Is there a way to unit test this??
For example sake, let's say I have a default config key and a custom config key. I'd like to use the custom config key if it's present and use the default when it's not.
My computed logic is:
customConfigKey () {
return this.customConfigKey ?? this.defaultConfigKey;
}
I'm confused how to test this when the value for the customConfigKey is being set via DBeaver via a SQL querie.
Here's what I have for the unit test (the only thing I've been able to see a test pass due to obvious shortcomings.
describe('custom config key ', () => {
it('returns undefined if configKey does not exist', () => {
expect(wrapper.vm.CustomConfigKey).toBe(undefined); // value_returned
});
});

How can I add properties to a component in a unit test before init?

I'm working on an Ember component with an init function that I'd like to add a unit test for. The component has the following properties:
1) The init function must not be run more than once, and
2) The component depends on having a model (currentUser) passed to it.
So far I have tried writing a test like this:
test('#init', function(assert) {
const component = this.owner.lookup('component:component-that-depends-on-property');
const currentUser = make('user');
component.set('currentUser', user);
component.init();
assert.ok(component.somethingHasHappened);
});
My problem is that init method is run on the owner.lookup line, meaning I have no way of getting the currentUser into the component before it runs. Again, I cannot run the init method more than once without blowing up the component's state.
I noticed that the lookup method takes an options argument and thought I might be able to use that to pass currentUser in, but that doesn't seem to work and I couldn't find much documentation on the lookup method.
I'd like to avoid writing an integration test for this, if possible. Is there a good way of doing this/workaround I'm not seeing?
I would suggest writing integration tests for components. Avoid writing unit test cases for components rather write unit test cases for controllers, mixins, models, routes, services
If you do unit test the component, you can do:
const component = this.owner.factoryFor('component:component-that-depends-on-property').create({
currentUser: user,
});
That will create an instance of your component with currentUser set. You will not need to call init() explicitly because it is called on create().

Should I test Vue.js private functions?

So after I read common tips and watched the video about testing provided by Vue.js I decided to test only behaviors of my components. But I maybe misunderstand the concept. Here is the component:
<template>
<es-btn
class="a"
round
outline
color="primary"
#click="skipScan"
>
Skip Upload
</es-btn>
</template>
<script>
export default {
data: () => ({
uploadScanningDialog: false,
}),
methods: {
// public functions here which will be tested
skipScan() {
hideDialog();
triggerSkipScan();
},
},
}
// private functions here as vue.js suggests
function hideDialog() {
this.uploadScanningDialog = false;
}
....
</script>
I want to test the behavior:
it('should hide itself and show next dialog when Scan Button is clicked', () => {
const data = {
uploadScanningDialog: true,
};
wrapper.setData(data);
expect(wrapper.vm.uploadScanningDialog).toBeTruthy();
wrapper.find('.a').trigger('click');
expect(wrapper.vm.uploadScanningDialog).toBeFalsy();
});
So here are the questions and errors:
Should I do test this way, by triggering the action instead of calling the method itself? Because I used to test by calling the method and expecting some results, not triggering the component who calls the method
Shouldn't I test the private functions? Because my test tries to call real method, so the test I share gets error. I will mock them but I'm not sure how to continue
Generally it is better to unit test your code through its public api, where possible.
This improves maintainability, as:
It allows you to refactor any private functions, without having to update your unit tests.
If you make changes to your private functions, you can then assert that you haven't broken anything by running your unit tests against your public api.
Whether you run your unit tests by calling a public method or triggering a DOM event is a matter of choice.
The latter gives greater test coverage as you are also testing if you have wired up the event to the event handler function correctly in your template; but it is slightly less maintainable, as if you change your template you may have to update your tests.

Mock an api function call inside of a route without actually calling it

I've got a route in my api which calls another server and I've ran into a problem where I can't test, mock a resolved value, for that another server call. The unit test seems to always call the other server no matter how I approach this.
let iAgent: PartialMock<InternalAgent>;
beforeEach(() => {
iAgent = {
extend: jest.fn()
};
});
if(iAgent.extend) {
iAgent.extend.mockResolvedValue({});
}
const r = await request.post('/api/v1/webhooks/extend')
.send({
id: 1
});
expect(r.status).toEqual(200);
expect(iAgent.extend).toBeCalledTimes(1);
and inside my actual route it calls this everytime:
await iAgent.extend();
and fails on this line as the other server is not running and I get a message of refused connection. Appearently the iAgent.extend function does not even get called once, yet manages to return a rejection.
So by all means I believe it shouldn't call the actual function in my route and skip it, falling back to my resolved value in the test if I understand correctly, however that's not the case and I'm not sure how to continue.
Oh and just to be clear about the if check for my mockResolvedValue, that is just to avoid the strict null checks in my config for now. But I have logged inside of the conditional and it does mock the value
Oh boy did I miss this. The problem here was that my routes were using the same class instance throughout all of the app and my unit test was trying to mock another instance of it - that is why the resolved value wasn't used in the route function when calling the other server.
So just by using the same instance of that agent class I was able to get my mocked value easily

Jest Testing with React Native and Contentful

I am trying to test my React Native Application with Jest. I am using Contentful as a CMS to hold my backend information. I am currently trying to test that I am initializing the correct client.
Here is the code I used to initialize the client:
var client = contentful.createClient({
space: 'w20789877', // whatever the space id is
accessToken: '883829200101001047474747737' // some accessToken
})
Here is the code I used to test initializing the client:
describe ('should initialize the correct client', () => {(
it('should initialize the correct client info from contentful', () =>{
expect(client).toEqual('w20789877', '883829200101001047474747737')
});
)};
However, I am getting an error message stating that:
Difference: Comparing two different types of values. Expected undefined but received string.
For some reason I am receiving undefined for the space and accessToken but I correctly initialize the client, as I am able to use the space later on. Even when trying to print out the space and accessToken an undefined value prints.
These are several issues here:
The toEqual matcher receives a single value parameter; you're sending 2
parameters, so effectively only the first one is being used.
The client in this case is a function and you're trying to compare it to a string. Regardless of the fact that the client is not a string, in your case it's also undefined, hence the message "Expected undefined but received string". You are not testing the space or accessToken here, you are testing the client.
I'm not completely sure what you're trying to test here, but this is not specifically related to Contentful.
I'm assuming that the client initialization part is somewhere in the code which you want to unit-test (and not initialized in the test file). I suggest a test that checks that the createClient function of the contentful is being called with your expected parameters when your code is executed; there's no need to test that the client is created - that's Contentful's responsibility to make sure they return a valid client object. What's important is that you pass the correct "space" and "accessToken" parameters required for your app.
Generally speaking, external services should be mocked, and you should only test your own logic and interaction with the external services.
Example
To make it simple, lets say that the code that initializes your client looks like this:
//client.js
var contentful = require('contentful')
export default function initializeClient() {
var client = contentful.createClient({
space: 'w20789877', // whatever the space id is
accessToken: '883829200101001047474747737' // some accessToken
});
}
The test might look something like this:
//client.test.js
describe('contentful client', () => {
let contentful;
let initializeClient;
beforeEach(() => {
jest.mock('contentful');
contentful = require('contentful');
initializeClient = require('./client').default;
});
it('should initialize the contentful client with the correct params', async () => {
initializeClient();
expect(contentful.createClient).toHaveBeenCalledWith({
space: 'w20789877',
accessToken: '883829200101001047474747737'
});
});
});
Note: I didn't actually run or test the above code, but this is the general concept.

Categories

Resources