how to mock a promise in jest-test?
till now, we were using launchDarkly.getFlag directly without waiting for the onInitialization method/promise? so the tests had it mocked
// in myFunc.test.js file
jest.spyOn(launchDarkly, 'getFlag').mockImplementation(() => true);
But now that it has changed as mentioned below, the test(s) has started to fail, so what and how should I mock so that the test-flow is checked with isWhiteSpaceFeatureEnabled variable being tested against an if check?
// in componentUtility.js file
// before isWhitespaceOvertimeFeatureEnabled = launchDarkly.getFlag(WHITESPACE_OVERTIME_CHART_FLAG, false);
launchDarkly.onInitialization().then(() => {
isWhitespaceOvertimeFeatureEnabled = launchDarkly.getFlag(WHITESPACE_OVERTIME_CHART_FLAG, false);
});
Related
The RxJS Observer fires the events:
complete
error
next
If we want to test for the complete event with Jest. How is this done?
For example we can test the next and error events, because those functions pass data:
o.subscribe(result => {
expect(result.data.length).toEqual(1);
},
(e)=>{expect(e).toBeFalsy()},
()=>{ WHAT TO EXPECT HERE? }
The complete event does not. The function signature is ()=>void. How do we test that function signature?
Also the line (e)=>{expect(e).toBeFalsy()} because it never actually fires. Is there a way to check that a callback does not run?
const toPromise = obs =>
new Promise((complete, error) => {
obs.subscribe({ complete, error });
});
import { getUserEvents } as user from '../user';
// The assertion for a promise must be returned.
it('works with promises', () =>
expect(toPromise(getUserEvents(4))).resolves.toEqual('Mark'))
Via:
https://jestjs.io/docs/en/tutorial-async
https://github.com/ReactiveX/rxjs/issues/3482#issuecomment-385106653
Furthermore, since Jest will fail on Errors being thrown, you can use any testing framework inside of its test. E.g. import 'rxjs/testing', like described here
How to test that the error callback is not called is here.
Looks like this will test the complete callback:
let complete = false;
let completeHandler = ()=>{
complete = true;
expect(complete).toBeTruthy()
};
let errorHandler = (e)=>{
console.log("THIS IS NEVER EXECUTED");
console.log("HOW DO WE VERIFY THAT IT IS NOT?");
let o:Observable<Result> = fn(data, errorHandler, completeHandler);
o.subscribe();
The errorHandler and completeHandler are baked into the Observable<Result returned by the fn function.
I'm trying to upload a file from a <input type="file"> HTML tag, using the uploadFile method.
The uploadFile promise resolves, but with a <100 progress value - it's still uploading. So I need to wait until it finishes, but after the first promise resolves how do I keep updating the FileUploadResult please?
My example page is here.
function UploadFile(curform, file) {
return new Promise((resolve, reject) => {
var FileUploadResult;
var check = function () {
if (FileUploadResult.isLast) {
resolve(FileUploadResult)
} else {
console.log(FileUploadResult);
setTimeout(check, 1000);
}
};
curform.uploadFile(file).then(Result => {
FileUploadResult = Result
check();
}).catch(er => { reject(er) })
})
}
Don't use Promise here. Use callbacks.
As it is written in the documentation :
uploadFile(file, [onSuccess], [onError]) ⇒ Promise.
#simon-barnett, I encountered the same problem. Everything else I'm doing is with promises and .then() statements aside from the uploadFile() call.
curForm.uploadFile(file,uploadSuccess, uploadError);
function uploadSuccess(r) {
if (r.isLast) {
curForm.newRow()
.then(() => curForm.fieldUpdate("EXTFILENAME", r.file))
.then(() => curForm.saveRow(1)) //Save and Close curForm
}
}
What I think is happening is that the .isLast Boolean is not being properly updated once the upload is finished, even if the progress gets to 100. The callback method does not get hung up on this, returns the promise and sets the .isLastBoolean correctly.
I believe this is true as of version 1.5 (although I'm having trouble getting the version # right now)
UPDATE: As per the documentation, as of version 2.0.1 the .isLast property was removed. As of version 2.1.0 we now have FileProgress and FileResult. This should allow for .uploadFile to be called as a promise instead of with call backs, although I have not tested this yet myself.
Description: I want to read a particular label from the webpage, whose value changes to one of "started", "inprogress", "success", "Error". Once the label value changes to "success" or "Error" there will not be any further changes.
Issue: When I read the label value using javascript in protractor, the text value of the label is not returned to the calling function; instead it returns 'undefined'. Below is my code, please have a look and let me where the issue is.
CheckColor_Test.js
var commonFunctions = require('../pages/CommonFunctions.js');
describe("Run Test", function () {
it("should stop once the status reached Success or Error", function () {
var processStatus = commonFunctions.refreshTillProcessFinish();
expect(processStatus).toContain('Success','Error');
});
});
CommonFunctions.js
Var CommonFunctions = function(){
var label = element(by.id('Status'));
var refreshStatusBtn = element(by.css('[ng-click="getJob()"]'));
this.getStatusValue = function () {
return label.then(function (headers) {
return headers.getText();
});
};
this.refreshTillRefreshFinish = function () {
var refreshStatusMonitor = function (currentStatus) {
return currentStatus.then(function (Status) {
if (Status == 'Success' || Status.includes("Error")) {
console.log(Status);
return Status;
} else {
refreshStatusBtn.click();
console.log(Status);
browser.sleep(2000);
refreshStatusMonitor (currentStatus);
}
});
};
return refreshStatusMonitor (this.getStatusValue);
};
}
module.exports = new CommonFunctions();
Executing in Protractor:
I have configured protractor in Webstorm, hence I used to run using that.
Expected Result:
The test should get successful and passed
Actual Result:
The test fails with below error.
"C:\Program Files (x86)\JetBrains\WebStorm 2016.1.1\bin\runnerw.exe" "C:\Program Files\nodejs\node.exe" node_modules\protractor\built\cli.js D:\Somesh_HDD\WebstormProjects\ProjectUBET\conf.js
[22:19:59] I/direct - Using ChromeDriver directly...
[22:19:59] I/launcher - Running 1 instances of WebDriver
Spec started
Started
InProgress
Success
Run Test
? should stop once the status reached Success or Error
- Expected undefined to contain 'Success', 'Error'.
**************************************************
* Failures *
**************************************************
1) Run Test should stop once the status reached Success or Error
- Expected undefined to contain 'Success', 'Error'.
Executed 1 of 1 spec (1 FAILED) in 33 secs.
[22:20:36] I/launcher - 0 instance(s) of WebDriver still running
[22:20:36] I/launcher - chrome #01 failed 1 test(s)
[22:20:36] I/launcher - overall: 1 failed spec(s)
[22:20:36] E/launcher - Process exited with error code 1
Process finished with exit code 1
The following return value:
return currentStatus.then(...);
is not the value returned by this statement:
return Status;
In fact, the latter is returned to one of the recursive calls of refreshStatusMonitor which is not captured anywhere.
Because this is asynchronous code involving promises, the return value of currentStatus should be a promise as well, which would bubble up via refreshStatusMonitor, refreshTillRefreshFinish to your test, which then also needs to be adapted to wait for the promise to be fulfilled before expecting anything.
I would also advise against the use of browser.sleep(...) as it completely blocks your JavaScript environment. You could use setTimeout(...) instead.
Here is some untested code which builds on those ideas:
this.refreshTillRefreshFinish = function () {
// create a promise
var deferred = protractor.promise.defer();
var refreshStatusMonitor = function (currentStatus) {
currentStatus.then(function refresh(Status) {
if (Status == 'Success' || Status.includes("Error")) {
// Signal the completion via the promise.
// This triggers the `then` callback in your revised test
deferred.fulfill(Status);
} else {
refreshStatusBtn.click();
console.log(Status);
// Use setTimeout so JavaScript is not blocked here:
setTimeout(function () {
refreshStatusMonitor(currentStatus);
}, 2000);
}
});
};
refreshStatusMonitor(this.getStatusValue);
// Don't wait for the result to happen while blocking everything,
// instead return a custom-made promise immediately
return deferred.promise;
};
Your test should then also take into account that you are dealing with a promise:
it("should stop once the status reached Success or Error", function () {
var processStatus = commonFunctions.refreshTillProcessFinish().then(function () {
expect(processStatus).toContain('Success','Error');
done();
});
}, 20000); // set timeout to 20 seconds
Note that Jasmine has a default timeout of 2 seconds, so you need to provide that extra argument at the end.
NB: Such asynchronous tests are not very suitable for running batches of unit tests.
Is your script able to click on the refresh button recursively?
i have made few changes to your existing script by introducing promises inside the recursive method.Just give a try.
var CommonFunctions = function(){
var label = element(by.id('Status'));
var refreshStatusBtn = element(by.css('[ng-click="getJob()"]'));
this.refreshTillRefreshFinish = function () {
var defer = protractor.promise().defer();
var refreshStatusMonitor = function () {
label.getText().then(function (Status) {
if (Status == 'Success' || Status.includes("Error")) {
defer.fulfill(Status);
} else {
refreshStatusBtn.click();
browser.sleep(2000);
refreshStatusMonitor ();
}
});
return defer.promise;
};
return refreshStatusMonitor ();
};
}
module.exports = new CommonFunctions();
I am a bit confused and I am also a newcomer to promises.
My problem is that the beforeEach function runs in random order (how is this possible?) so that the delete query is not run first. Also the order changes if I put console.log messages in the promise (??). What am I doing wrong here.
Note that the database (neo4j in this case) returns 200 OK in case there is a constrain violation that is why I am reading the result and then rejecting.
I have this test (using chai-as-promised):
beforeEach(function() {
return neodb.query('MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE n,r',{}) //clear the db first
.then(neodb.query(query,{props:[{username:'arisAlexis'}]}))
.then(neodb.query(query,{props:[{username:'marySilva'}]}))
.then(neodb.query(query,{props:[{username:'silviaBurakof'}]}));
});
it('create a username conflict',function() {
return User.create([{username:'arisAlexis'}]).should.be.rejected;
})
User.create is a static method that just runs this :
return db.query(query,{props:props});
so it returns a promise that is created here:
exports.query=function(query,params) {
return new Promise(function(resolve,reject) {
request.postAsync({
uri: dbUrl,
json: {statements: [{statement: query, parameters: params}]}
}).then(function(result) {
if (result[1].errors.length > 0) {
reject(new NeoError(result[1].errors[0].message,result[1].errors[0].code));
}
resolve(result[1].results);
});
});}
I am running mocha with babel-node.
I am also using promisify on request module and I am rejecting with a custom error (am I using it correctly ? In the documentation they throw the error).
You are executing all query functions at the same time, instead of waiting for the previous one to end:
.then(neodb.query(...)) // this executes `neodb.query()` right away
// and uses its return value as the callback
// function for the `.then()`.
Here's how to fix that:
beforeEach(function() {
return neodb.query('MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE n,r',{}).then(function() {
return neodb.query(query,{props:[{username:'arisAlexis'}]});
}).then(function() {
return neodb.query(query,{props:[{username:'marySilva'}]});
}).then(function() {
return neodb.query(query,{props:[{username:'silviaBurakof'}]});
});
});
The description of the task. I want to test the code that loads a list of resources using $.get.
So, the source code:
fetchTemplates: function(list, cb){
var promises = [],
$container = $('#templates');
Object.keys(list).forEach(function(tplSelector){
if($(tplSelector).length > 0){ return; }
var promise = $.get(list[tplSelector]);
promise
.done(function(tplHtml){
$container.append(tplHtml);
})
.fail(function(){
console.warn('Template "' + tplSelector + " not found by url:" + list[tplSelector]);
});
promises.push( promise );
});
return $.when.apply($,promises).done(cb);
}
The test suite:
it("Correct template fetching", function (done) {
var fetchResult = viewManager.fetchTemplates({
'#helpTpl': 'somecorrectaddress'
});
fetchResult.done(function () {
expect(true).toBeTruthy();
done();
});
fetchResult.fail(function () {
expect(false).toBeTruthy();
done();
});
});
What it generates. Test passes, but generates an error:
TypeError: 'null' is not an object (evaluating 'this.results_.addResult')
at jasmine.js?2348
So, the test case marks as passed. But whole test suite still generates the error above (and this method is the only one async, other parts are trivial to test). My thought was that since the tested method contains async operations and promises - results were not properly handled and thus TypeError. So I added jasmine async "done()" to handle the issue - unfortunately nothing changed. Also worth noting that if I leave only one test in the suite using "iit" - no error is generated. Search didn't find similar cases. Any ideas?
You need to wrap your async calls in 'runs()' with 'waitsFor()' after, read the documentation here. I've never worked with jquery, but try something like the following inside your it function:
var done = false;
var that = this;
runs( function() {
//your async test goes here
that.done = true;
});
waitsFor( function() {
return that.done;
}, "async code failed", 2000);