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.
Related
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
});
});
I'm using Firestore in conjunction with realtime database in order to provide a user presence system for my application.
Update: article I followed
https://blog.campvanilla.com/firebase-firestore-guide-how-to-user-presence-online-offline-basics-66dc27f67802
In one of the methods I use this code here:
const usersRef = this.$fireStore.collection('users').doc(uid)
const whoIsOnlineRef = this.$fireDb.ref('.info/connected')
whoIsOnlineRef.on('value', (snapshot) => {
this.$fireDb.ref(`/status/${uid}`)
.onDisconnect()
.set('offline')
.then(() => {
usersRef.set({ online: true }, { merge: true })
this.$fireDb.ref(`/status/${uid}`).set('online')
})
})
The .set method, however, is giving me the error mentioned in the title and I can't quite understand why. I'm simply passing a javascript object to .set method and this should technically work.
Can you spot what is wrong with the code?
Looks like the reason why this wasn't working is that the code was running on the server in an SSR application.
I moved that very same logic to the browser and it started working nicely. I still don't see why this wouldn't work in the server as, at the end of the day I was still passing a simple js object to the .set() method.
Either way, there you have it
I am trying to mock an external module (jwt_decode for those interested), and I have seen many examples of how to mock external an node module using Jest both for all tests in a test suite, as well as on a per-test basis.
I have been able to mock the dependency so that it mocks the return value for all tests in the suite, although the default function is all that i'm really concerned with.
import jwt_decode from 'jwt-decode';
jest.mock('jwt-decode', () => jest.fn().mockReturnValue({
exp: 12345,
somethingElse: 'test_value'
}));
This works well, except I would like to test a scenario where the returned token has expired, so that I can verify that certain Redux actions were dispatched when this situation arises.
import jwt_decode from 'jwt-decode';
const decoded = jwt_decode(localStorage.jwtToken);
// set user info and isAuthenticated
store.dispatch(setCurrentUser(decoded));
// this is the scenario I am looking to test
const currentTime = Date.now() / 1000;
if (decoded.exp < currentTime) {
store.dispatch(logoutUser());
store.dispatch(clearCurrentProfile());
window.location.href = '/login';
}
I would like to modify the returned mock for an individual test so that I can ensure that the 'if' statement shown equates to false, and other parts of the code base are executed.
How can one go about this?
Some of the examples I have tried and failed with so far include:
test('some test that will use a different mock' () => {
// re-assign value of the imported module using the its given alias
jwt_decode = jest.fn().mockImplementation(() => {
return {
exp: 'something_different 9999999999',
somethingElse: 'I_changed_too'
};
});
});
As well as
jwt_decode.default = jest.fn().mockImplementation(() => {
return {
exp: 'something_different 9999999999',
somethingElse: 'I_changed_too'
};
});
And also jest.spyOn(), as seen in this SO question, as well as A Jar of Clay's answers on the same question, which proposes the following:
import { funcToMock } from './somewhere';
jest.mock('./somewhere');
beforeEach(() => {
funcToMock.mockImplementation(() => { /* default implementation */ });
});
test('case that needs a different implementation of funcToMock', () => {
funcToMock.mockImplementation(() => { /* implementation specific to this test */ });
// ...
});
I also found a suggestion for creating a util which changes the global localStorage on a test by test basis, but I would rather not use a real jsonwebtoken, or have to worry about storing sign-in credentials.
What I keep ending up with is that jwt_decode is not updated when running the test that should have the different mock value returned, or what's more common is that I get an error saying that ".default is not a function".
If you have suggestions, I would be very grateful.
Assuming I understand your ultimate goal, how about this approach:
In your project directory, at the same level as node_modules, create a directory called "__mocks__" and in that directory, put a file called "jwt-decode.js" -- with this in place there is no need to explicitly mock jwt-decode in your test module, as it will always be mocked automatically.
Put the following code in your __mocks__/jst_decode.js file:
export default token => token;
Thus, when the code that you're testing calls jwt_decode(something), the return value will be exactly what was passed in.
Now you can write unit tests that test the behavior of your module given various valid or invalid values in the token; just mock the token value in your module and your mocked implementation of jwt_decode() will simply pass it through.
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
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);