I'm using mocha and chai as assertions.
I have several assertions in my spec:
Exp1.should.be.true
Exp2.should.be.true
Exp3.should.be.true
If one of them fails mocha writes "expected false to be true". Is there a way to identify them?
With expect I can do it:
expect(Exp1, 'Exp1').to.be true
Is something like this possible with should?
Apparently should does not support custom error messages at the moment.
You can create your own helper for setting the message:
var chai = require('chai'),
should = chai.should();
// Helper definition - should be in a shared file
chai.use(function(_chai, utils) {
_chai.Assertion.addMethod('withMessage', function(msg) {
utils.flag(this, 'message', msg);
});
});
// Sample usage
it('should fail', function() {
var Exp1 = false;
var Exp2 = false;
Exp1.should.be.withMessage('Exp1').true;
Exp1.should.withMessage('Exp2').be.true;
});
I checked the chai code with respect to should and found that the currently accepted answer is either incorrect or incomplete.
If you read there, you will find that there is indeed a way to include your own custom message in each assertion. The catch is that you may need to change your assertion syntaxes to use should's function calls instead.
(1).should.equal(0, 'This should fail');
/****** Output with (I believe) default reporter *****
* This should fail
* + expected - actual
*
* -1
* +0
*/
Note that your output may look different if you are using your own reporter. If you feel so inclined, you could probably wrap should's functions to always include line number in your assertion output.
I wonder why they don't simply add which line fired the assertion, but I ran into this exact same problem myself. A colleague who can manuals better than I noted there is a setting for includeStack which will give line numbers for assertions.
http://chaijs.com/guide/styles/#configure
Since I'm doing a lot of async, I might run my tests in before or beforeEach and then run a separate it for each assertion.
Related
I've found this function in an assemblyscript project for a NEAR contract:
export function assert_single_promise_success(): void {
const x = ContractPromise.getResults()
assert(x.length == 1, "Expected exactly one promise result")
assert(x[0].succeeded, "Expected PromiseStatus to be successful")
}
What does ContractPromise.getResults() do exactly? How should implement the same thing in rust?
here is something similar in Rust from one of the examples in the SDK repo
require!(env::promise_results_count() == 2);
let data0: Vec<u8> = match env::promise_result(0) {
PromiseResult::Successful(x) => x,
_ => env::panic_str("Promise with index 0 failed"),
};
I'm going to give an answer, comments taken directly from the implementation of ContractPromise.getResults(), which can be found here. The implementation also has an example on how to use the function, which may be useful.
Method to receive async (one or multiple) results from the remote
contract in the callback.
#returns An array of results based on the number of promises the
callback was created on. If the callback using then was scheduled
only on one result, then one result will be returned.
I have tried to unsubscribe within the subscribe method. It seems like it works, I haven't found an example on the internet that you can do it this way.
I know that there are many other possibilities to unsubscribe the method or to limit it with pipes. Please do not suggest any other solution, but answer why you shouldn't do that or is it a possible way ?
example:
let localSubscription = someObservable.subscribe(result => {
this.result = result;
if (localSubscription && someStatement) {
localSubscription.unsubscribe();
}
});
The problem
Sometimes the pattern you used above will work and sometimes it won't. Here are two examples, you can try to run them yourself. One will throw an error and the other will not.
const subscription = of(1,2,3,4,5).pipe(
tap(console.log)
).subscribe(v => {
if(v === 4) subscription.unsubscribe();
});
The output:
1
2
3
4
Error: Cannot access 'subscription' before initialization
Something similar:
const subscription = of(1,2,3,4,5).pipe(
tap(console.log),
delay(0)
).subscribe(v => {
if (v === 4) subscription.unsubscribe();
});
The output:
1
2
3
4
This time you don't get an error, but you also unsubscribed before the 5 was emitted from the source observable of(1,2,3,4,5)
Hidden Constraints
If you're familiar with Schedulers in RxJS, you might immediately be able to spot the extra hidden information that allows one example to work while the other doesn't.
delay (Even a delay of 0 milliseconds) returns an Observable that uses an asynchronous scheduler. This means, in effect, that the current block of code will finish execution before the delayed observable has a chance to emit.
This guarantees that in a single-threaded environment (like the Javascript runtime found in browsers currently) your subscription has been initialized.
The Solutions
1. Keep a fragile codebase
One possible solution is to just ignore common wisdom and continue to use this pattern for unsubscribing. To do so, you and anyone on your team that might use your code for reference or might someday need to maintain your code must take on the extra cognitive load of remembering which observable use the correct scheduler.
Changing how an observable transforms data in one part of your application may cause unexpected errors in every part of the application that relies on this data being supplied by an asynchronous scheduler.
For example: code that runs fine when querying a server may break when synchronously returned a cashed result. What seems like an optimization, now wreaks havoc in your codebase. When this sort of error appears, the source can be rather difficult to track down.
Finally, if ever browsers (or you're running code in Node.js) start to support multi-threaded environments, your code will either have to make do without that enhancement or be re-written.
2. Making "unsubscribe inside subscription callback" a safe pattern
Idiomatic RxJS code tries to be schedular agnostic wherever possible.
Here is how you might use the pattern above without worrying about which scheduler an observable is using. This is effectively scheduler agnostic, though it likely complicates a rather simple task much more than it needs to.
const stream = publish()(of(1,2,3,4,5));
const subscription = stream.pipe(
tap(console.log)
).subscribe(x => {
if(x === 4) subscription.unsubscribe();
});
stream.connect();
This lets you use a "unsubscribe inside a subscription" pattern safely. This will always work regardless of the scheduler and would continue to work if (for example) you put your code in a multi-threaded environment (The delay example above may break, but this will not).
3. RxJS Operators
The best solutions will be those that use operators that handle subscription/unsubscription on your behalf. They require no extra cognitive load in the best circumstances and manage to contain/manage errors relatively well (less spooky action at a distance) in the more exotic circumstances.
Most higher-order operators do this (concat, merge, concatMap, switchMap, mergeMap, ect). Other operators like take, takeUntil, takeWhile, ect let you use a more declarative style to manage subscriptions.
Where possible, these are preferable as they're all less likely to cause strange errors or confusion within a team that is using them.
The examples above re-written:
of(1,2,3,4,5).pipe(
tap(console.log)
first(v => v === 4)
).subscribe();
It's working method, but RxJS mainly recommend use async pipe in Angular. That's the perfect solution. In your example you assign result to the object property and that's not a good practice.
If you use your variable in the template, then just use async pipe. If you don't, just make it observable in that way:
private readonly result$ = someObservable.pipe(/...get exactly what you need here.../)
And then you can use your result$ in cases when you need it: in other observable or template.
Also you can use pipe(take(1)) or pipe(first()) for unsubscribing. There are also some other pipe methods allowing you unsubscribe without additional code.
There are various ways of unsubscribing data:
Method 1: Unsubscribe after subscription; (Not preferred)
let localSubscription = someObservable.subscribe(result => {
this.result = result;
}).unsubscribe();
---------------------
Method 2: If you want only first one or 2 values, use take operator or first operator
a) let localSubscription =
someObservable.pipe(take(1)).subscribe(result => {
this.result = result;
});
b) let localSubscription =
someObservable.pipe(first()).subscribe(result => {
this.result = result;
});
---------------------
Method 3: Use Subscription and unsubscribe in your ngOnDestroy();
let localSubscription =
someObservable.subscribe(result => {
this.result = result;
});
ngOnDestroy() { this.localSubscription.unsubscribe() }
----------------------
Method 4: Use Subject and takeUntil Operator and destroy in ngOnDestroy
let destroySubject: Subject<any> = new Subject();
let localSubscription =
someObservable.pipe(takeUntil(this.destroySubject)).subscribe(result => {
this.result = result;
});
ngOnDestroy() {
this.destroySubject.next();
this.destroySubject.complete();
}
I would personally prefer method 4, because you can use the same destroy subject for multiple subscriptions if you have in a single page.
This question already has answers here:
Proper way to skip a then function in Q Promises
(4 answers)
Closed 6 years ago.
Using When.js, we have a situation where we want to quietly abort a promise chain mid way, due to the user changing their mind. Our current method is to simply never resolve that step of the chain - effectively leaving the other promises "hanging". This seems slightly dirty?
If we reject the promise, then of course our exception handlers kick in. We could work around that, using a custom message which we detect and ignore, but that also seems a bit unclean.
Is there a better approach?
This is what the code looks like:
return getConfirmation(confirmConversion, 'Ready to upload your file to the ' + terria.appName + ' conversion service?')
.then(function() {
return loadItem(createCatalogMemberFromType('ogr', terria), name, fileOrUrl);
});
function getConfirmation(confirmConversion, message) {
...
var d = when.defer(); // there's no `when.promise(resolver)` in when 1.7.1
PopupMessageConfirmationViewModel.open('ui', {
...
confirmAction: d.resolve,
denyAction: function() { this.close(); /* Do nothing or d.reject(); ? */ }
});
return d.promise;
}
Result
For completeness, I changed the code to:
confirmAction: function () { d.resolve(true); },
enableDeny: true,
denyAction: function() { this.close(); d.resolve(false); }
and
.then(function(confirmed) {
return confirmed ? loadItem(createCatalogMemberFromType('ogr', terria), name, fileOrUrl) : undefined;
});
Making my comment into an answer:
If you're trying to return three possible states (resolve, rejected and user cancelled) so your code can handle all three possible resolutions correctly and you're using promises, then you will have to make either the resolved value indicate that the user cancelled or the reject reason will have to indicate cancel and your code will have to check for that.
There are only two possible final states for a promise, not three so you'll have to communicate the third state in one of the other two.
I'd recommend not stranding promises in the pending state unless you're absolutely sure they won't lead to a memory leak, but even then it doesn't seem like a very clean design to just strand them.
I am wondering if there's a way to create a promise chain that I can build based on a series of if statements and somehow trigger it at the end. For example:
// Get response from some call
callback = (response) {
var chain = Q(response.userData)
if (!response.connected) {
chain = chain.then(connectUser)
}
if (!response.exists) {
chain = chain.then(addUser)
}
// etc...
// Finally somehow trigger the chain
chain.trigger().then(successCallback, failCallback)
}
A promise represents an operation that has already started. You can't trigger() a promise chain, since the promise chain is already running.
While you can get around this by creating a deferred and then queuing around it and eventually resolving it later - this is not optimal. If you drop the .trigger from the last line though, I suspect your task will work as expected - the only difference is that it will queue the operations and start them rather than wait:
var q = Q();
if(false){
q = q.then(function(el){ return Q.delay(1000,"Hello");
} else {
q = q.then(function(el){ return Q.delay(1000,"Hi");
}
q.then(function(res){
console.log(res); // logs "Hi"
});
The key points here are:
A promise represents an already started operation.
You can append .then handlers to a promise even after it resolved and it will still execute predictably.
Good luck, and happy coding
As Benjamin says ...
... but you might also like to consider something slightly different. Try turning the code inside-out; build the then chain unconditionally and perform the tests inside the .then() callbacks.
function foo(response) {
return = Q().then(function() {
return (response.connected) ? null : connectUser(response.userData);
}).then(function() {
return (response.exists) ? null : addUser(response.userData);//assuming addUser() accepts response.userData
});
}
I think you will get away with returning nulls - if null doesn't work, then try Q() (in two places).
If my assumption about what is passed to addUser() is correct, then you don't need to worry about passing data down the chain - response remains available in the closure formed by the outer function. If this assumption is incorrect, then no worries - simply arrange for connectUser to return whatever is necessary and pick it up in the second .then.
I would regard this approach to be more elegant than conditional chain building, even though it is less efficient. That said, you are unlikely ever to notice the difference.
I'm new to mocha, and am trying to implement a new test. I'm finding that the callback to my end method never gets called
it('should allow valid urls', function(){
var myUrl = "http://localhost:8080/test";
api.get(myUrl)
.end(function(err, res) {
console.log('THIS IS THE END, MY FRIEND');
});
});
Does anyone know why? I've tried expect with a callback as well, and it never gets called too.
Turns out that mocha does analysis of the function arguments, and I'd forgotten to put an argument in my mocha callback - even though it's never referenced in my function or any visible code at all!
So the solution was simply to add a variable, done as a function parameter to my it function, and it worked, even though it's not visibly used in the immediate context ;-)
it('should allow valid urls', function(done){
...
EDIT: Note that done should be used in my callback, as mentioned by # oligofren, but I hadn't gotten to that point yet and was surprised to see the callback itself not firing.