I'm writing an async test in Jest and having trouble. I'm pretty sure the test is finishing and passing before the async call returns anything in spite of everything I've tried. I know the function works because it logs out the correct response after the test suite has finished. Here is the test code:
describe('updateUser', () => {
test('should update a user', (done) => {
updateUser(user).then(({err, res}) => {
console.log('updated user:', err, res); // this show up after the test is done
expect(err).toBeFalsy();
expect(res).toBeTruthy();
done();
});
});
});
console output:
updateUser
✓ should update a user (68ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 6.058s
Ran all test suites.
console.log server/db/crud_Users/crud_user.test.js:38
updated user: null { homeLocations: [],
meetingPlaces: [],
hostedEvents: [],
attendingEvents: [],
flags: [],
tokens: [],
_id: 5b2147495995cb45f9c4f079,
name: 'test',
email: '83277963493533480000#test.com',
password: 'testtest',
ageRange: '1',
gender: 'Female',
accountCreatedAt: null,
__v: 0 }
Expected behavior: the test suite waits for the console.log statement and the assertions to run before finishing.
Actual behavior: it doesn't.
I also tried making the test callback an async function and awaiting the updateUser call, but nothing changed; I tried tacking the done() callback on in a second .then block as well, with no results.
It's just about how Jest output things in async tests. I have just checked but don't see how to proof that.
If you remove done(); call you will get test failed because of timeout exceeded.
If you change your expectation to be invalid you will also get your test failed.
So it works fine. For sure.
Also since updateUser returns Promise you don't need to run done(). Just return Promise so test would be slightly lighter:
test('should update a user', () => {
return updateUser(user).then(({err, res}) => {
expect(err).toBeFalsy();
expect(res).toBeTruthy();
});
});
Related
Sending a mutation with a bad set of variables (on purpose in this case) results in errors being thrown in the console, and the apollo-link-error link not picking up the error. Additionally, the mutation loading state is stuck as 'loading' and not error object comes through.
Through a debugging session, I fount that the zen-observable global error handling picks up an error thrown in the error-link's "next" function, because 'result' is not defined
pasted the apollo-link-error code that has the observable wrapped in a try catch, but the catch at the bottom here is not the catch that gets hit when if (result.errors) throws a 'nullpointer' because result in undefined.
try {
sub = forward(operation).subscribe({
next: function (result) {
// result is undefined, throwing an error
if (result.errors) {
retriedResult = errorHandler({
graphQLErrors: result.errors,
response: result,
operation: operation,
forward: forward,
});
if (retriedResult) {
retriedSub = retriedResult.subscribe({
next: observer.next.bind(observer),
error: observer.error.bind(observer),
complete: observer.complete.bind(observer),
});
return;
}
}
observer.next(result);
},
error: function (networkError) {
retriedResult = errorHandler({
operation: operation,
networkError: networkError,
graphQLErrors: networkError &&
networkError.result &&
networkError.result.errors,
forward: forward,
});
if (retriedResult) {
retriedSub = retriedResult.subscribe({
next: observer.next.bind(observer),
error: observer.error.bind(observer),
complete: observer.complete.bind(observer),
});
return;
}
observer.error(networkError);
},
complete: function () {
if (!retriedResult) {
observer.complete.bind(observer)();
}
},
});
} // the error is NOT caught here
catch (e) {
errorHandler({ networkError: e, operation: operation, forward: forward });
observer.error(e);
}
```
Link definition:
```javascript
export const client = new ApolloClient({
link: ApolloLink.from([
onError((errors) => {
console.log('errors in link!', errors);
handleServerError(errors);
}),
new MeteorAccountsLink(),
new HttpLink({
uri: '/graphql',
}),
]),
cache: new InMemoryCache(),
});
Edit:
The request in the browser does show a response with an error object with the graphQlErro of shape {errors: [{..}]} which is strange that it's not coming into the 'result' in the link.
Edit 2:
It looks like Meteor is picking up the error thrown in the http link prior to the error posted above, which might be why "result" is undefined. Writing a custom link to polyfill the missing 'result' so the app will at least work.
It seems like an issue with Meteor swallowing the errors. fixed make making a polyfill link to at least not break the js in the mutation complete function and show a general error.
const stupidMeteorErorrPolyfill = new ApolloLink((operation, forward) => forward(operation).map(data => data || { errors: [{ message: '! Empty response in gql links, see graphql.js and network tab' }] }));
I'm trying to include a list of users (more than 50) through a specific function in Firebase. Here's my code:
Object.keys(newUsers).forEach((key) => {
console.log(newUsers[key]['name']);
admin.auth().createUser({
uid: key,
email: newUsers[key]['email']
password: newUsers[key]['InitialPwd'],
disabled: false,
emailVerified: false,
displayName: newUsers[key]['name'],
}).then((userRecord) => {
return console.log('Success');
}).catch(function(error) {
console.log("Error:", error);
});
});
And the error is (for each record):
{ Error: Error while making request: timeout of 10000ms exceeded.
at FirebaseAppError.FirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:39:28)
at FirebaseAppError.PrefixedFirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:85:28)
at new FirebaseAppError (/srv/node_modules/firebase-admin/lib/utils/error.js:119:28)
at /srv/node_modules/firebase-admin/lib/utils/api-request.js:117:23
at
at process._tickDomainCallback (internal/process/next_tick.js:228:7) errorInfo: { code:
'app/network-timeout',
message: 'Error while making request: timeout of 10000ms exceeded.' }, codePrefix: 'app' }
How can I solve this?
Cloud Functions are set to run for a short period of time. If you are doing lots of work in a Cloud Function, it may time out before it is complete. There are a few solutions to this that I would suggest:
1.Change your Cloud Functions timeout. In the Cloud console, check at the top to make sure your current project is selected, and then in the middle you'll find your list of functions. Click on your function. You should be in function details now. Click "Edit". Right above the "save" button is "more". Select "more" and you'll see an option for upping the timeout. This can modify how long the function stays alive.
2.Change the batch size so you're creating fewer users at a time.
3.Make sure your promises are working as expected. If you don't return the call to createUser, the resulting UserRecord won't be accessible.
Object.keys(newUsers).forEach((key) => {
console.log(newUsers[key]['name']);
return admin.auth().createUser({
uid: key,
email: newUsers[key]['email']
password: newUsers[key]['InitialPwd'],
disabled: false,
emailVerified: false,
displayName: newUsers[key]['name'],
}).then((userRecord) => {
return console.log('Success');
}).catch(function(error) {
console.log("Error:", error);
});
});
4.I may be incorrect about this point, but it appears that the users are created one after another rather than concurrently. This could be a good case to look into using Promise.all so that all of the users can be created simultaneously, rather than waiting for one to complete before starting the next.
I am using mocha and selenium-webdriver for E2E tests. Most of the tests are async and I am using async/await functions to handle this. Unfortunately right now I can't get a single one done. Here is what my code looks like:
describe('Some test', function () {
before(function () {
driver.navigate().to('http://localhost:3000')
})
after(function () {
driver.quit()
})
it('should display element', async function () {
let elementFound = false
try {
await driver.wait(until.elementIsVisible(driver.findElement(By.className('element'))), 1000)
assessForm = await driver.findElement(By.className('element')).isDisplayed()
assert.ok(elementFound)
console.log('elementFound', elementFound)
} catch (err) {
console.log(err)
assert.fail(err)
}
})
})
The problem that is happening seems to be that the after function is being called before the test can finish. Here are the error logs:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure
"done()" is called; if returning a Promise, ensure it resolves.
{ NoSuchSessionError: no such session (Driver info:
chromedriver=2.36.540469
(1881fd7f8641508feb5166b7cae561d87723cfa8),platform=Mac OS X 10.13.3
x86_64)
at Object.checkLegacyResponse (/Users/me./myproject/node_modules/selenium-webdriver/lib/error.js:585:15)
at parseHttpResponse (/Users/me./myproject/node_modules/selenium-webdriver/lib/http.js:533:13)
at Executor.execute (/Users/me./myproject/node_modules/selenium-webdriver/lib/http.js:468:26)
at
at process._tickCallback (internal/process/next_tick.js:188:7) name: 'NoSuchSessionError', remoteStacktrace: '' }
If I remove my after() function, I still get
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure
"done()" is called; if returning a Promise, ensure it resolves.
but, my console.log shows that my element has been found.
If I then try making after() async, like this:
after(async function () {
await driver.quit()
})
I get the same error as the first one.
It is also important to note that I have read that I don't have to use done() when I am doing async/await. So what in the world is that all about? And even if I did, I keep getting the same error.
How do I solve this? It seems like everything is in order, but I can't seem to appropriately have the tests run through without running into each other.
Instead of using:
await driver.wait(until.elementIsVisible(driver.findElement(By.className('element'))), 1000)
try:
await driver.wait(until.elementLocated(By.className('element'))).isDisplayed()
I am trying to use jest to test calls to firebase. Firebase is an online database service offered by Google. I am mocking the firebase module like below
'use strict';
const firebase = jest.genMockFromModule('firebase');
const ref = jest.fn(() => {
return {
child: jest.fn(() => {
return ref
}),
update: jest.fn(() => {
console.log('Called update')
return Promise.resolve()
})
}
})
firebase.initializeApp = jest.fn()
firebase.database = jest.fn(() => {
return {
ref: ref
}
})
module.exports = firebase
I am only mocking the functions that I need to test at the moment. Below is my test case.
it('+++ actionCreator addAlarm', () => {
const store = mockStore(initialState)
store.dispatch(ActionCreators.addAlarm(alarm));
// Make sure that the scheduleNotifications API is called
expect(scheduleNotifications).toHaveBeenCalled();
expect(firebase.initializeApp).toHaveBeenCalled();
expect(firebase.database().ref().update).toHaveBeenCalled();
});
The last line in the test case is trying to make sure that I am calling the firebase update function which is mocked.
Below is the console output
abcs-MBP-2:GalarmApp abc$ npm test
> GalarmApp#1.0.53 test /Users/abc/Projects/GalarmApp
> jest
FAIL __tests__/actionsSpecs.js
● >>>A C T I O N --- Test galarm actions: › +++ actionCreator addAlarm
expect(jest.fn()).toHaveBeenCalled()
Expected mock function to have been called.
at Object.<anonymous> (__tests__/actionsSpecs.js:58:52)
at tryCallTwo (node_modules/promise/lib/core.js:45:5)
at doResolve (node_modules/promise/lib/core.js:200:13)
at new Promise (node_modules/promise/lib/core.js:66:3)
at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
at tryCallOne (node_modules/promise/lib/core.js:37:12)
at node_modules/promise/lib/core.js:123:15
>>>A C T I O N --- Test galarm actions:
✕ +++ actionCreator addAlarm (8ms)
✓ +++ actionCreator setConnectionStatus (4ms)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 passed, 2 total
Snapshots: 1 passed, 1 total
Time: 1.989s, estimated 2s
Ran all test suites.
console.warn node_modules/rn-host-detect/index.js:45
[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()
console.log __mocks__/firebase.js:11
Called update
The test case is failing on the line where I check that the update function is called. If you look down in the console output, you will see that Called update console is present which means that the update function is called but it is called after the test case has failed.
This is the addAlarm action which is a thunk action
const addAlarm = (alarm) => (dispatch, getState) => {
if(alarm.status) {
NotificationManager.scheduleNotifications(alarm);
}
const alarmObjForFirebase = this.createAlarmObjForFirebase(alarm)
firebaseRef.update(alarmObjForFirebase)
}
The call to firebase update function is not happening asynchronously as far as I understand.
Please let me know if you have pointers on how I may be able to fix this problem.
I have found the problem in my code and posting as a solution for others benefit. The problem is the way the update mock was defined. The way it was defined, I was getting a new instance of the update mock function every time I will make a call to firebase.database().ref().update. Since this is a new instance of the mock function, it wouldn't contain any data aboutupdate` function being called in the past.
I needed to change the code as follows
const update = jest.fn(() => {
return Promise.resolve()
})
const ref = jest.fn(() => {
return {
update: update
}
})
This way, I am not creating new instances of the update mock function and I was able to assert that it has been called during the testcase.
I am working with Mocha and am trying to test an API that I am in the process of building.
I am having trouble understanding where to place the done() function.
If I place it where it is now, it doesn't execute the callback function of User.findOne().
If I place the done at the bottom of the callback function of User.findOne(), then it creates a timeout.
I am relatively new to async and this done function, so can someone help explain why these two cases happen, and how to fix the code so that it will test correctly in Mocha?
describe('POST /signup', function() {
before(checkServerIsRunning); // Need to implement
it('create a new user if username is unique', function(done) {
httpReq({
method : 'POST',
url : url + '/signup',
json : true,
body : JSON.stringify({
username : 'test',
first : 'first',
last : 'last' })
},
function (err, res, body) {
if (err) {
done(err);
}
else {
res.statusCode.should.be.equal(201);
User.findOne( { username: 'test' }, function(err, user) {
user.should.have.property('username', 'testy');
user.should.have.property('firstName', 'first');
user.should.have.property('lastName', 'last');
usersToRemove.push(user);
});
done();
}
}
);
});
});
You should place done() inside the called to findOne.
If you're finding that it times out then either findOne is never calling its callback (which is an error!) or it's taking too long to execute.
In this case you could up the timeout by sticking something like this.timeout(5000) at the beginning of the test (which increases the timeout to 5 seconds).
In general you wouldn't usually want tests that slow though, so maybe try and figure out why it takes so long.