I have a library that imposes "metering" on some code. The normal case is easy to test where the code runs to completion and the meter is not exceeded.
I also want to test the case where the meter is exceeded, causing the code under test to throw forever until it unwinds to the caller. It is easy to test that the code only executes the parts I expect. However, in the case of promises, the exceeded meter causes some unhandled rejections in the code under test, as expected.
AVA currently fails my test run with:
1 test passed
1 unhandled rejection
Effectively, the test reduces to:
const expectedLog = ['a'];
test('unhandled rejection', async t => {
const log = [];
// I don't have control over the code in f():
const f = async () => {
log.push('a');
// This is a side-effect, but fails the test.
Promise.reject(RangeError('metering'));
throw RangeError('metering');
};
await t.throwsAsync(() => f(), { instanceOf: RangeError });
t.deepEqual(log, expectedLog);
});
Is there any way for me to tell AVA that I expected the 1 unhandled rejection?
I require not to modify the code under test (the f function above), as the whole point is to test that metering stops the code dead in its tracks no matter what that untrusted code is.
Is there any way for me to tell AVA that I expected the 1 unhandled rejection?
No. Unhandled rejections are indicative of bugs and therefore AVA will fail the test run. As AVA's maintainer I don't think there's enough reason to change that behavior.
I require not to modify the code under test (the f function above), as the whole point is to test that metering stops the code dead in its tracks no matter what that untrusted code is.
Rejecting a promise, that is then garbage collected, won't impact the untrusted code. If you're in an async function you can use throw directly.
Related
I'm running into an exception in C# code intended to set the contents of a WinUI3 Image object. I don't know how to interpret the exception message.
Here's the code:
using var responseStream = await response.Content.ReadAsInputStreamAsync();
var memStream = new InMemoryRandomAccessStream();
await RandomAccessStream.CopyAsync(responseStream, memStream);
memStream.Seek(0);
var retVal = new Image();
var source = new BitmapImage();
// the exception is thrown on the next line
await source.SetSourceAsync( outStream );
retVal.Source = source;
The exception message is
Unspecified error (Error HRESULT E_FAIL has been returned from a call to a COM component.)
What's weird is that calls to this code sometimes succeed and sometimes don't, even when the exact same parameters (which define the Uri that the response stream is derived from) are specified and the exact same response is received.
That suggests there's something in the context of the call that's the problem. The cases that succeed are when the code is called from a viewmodel in a WinUI3 test app. The cases that fail are when the code is called from a custom WinUI3 control I've written.
I thought there might be a "called from the wrong thread" problem but in both the success and failure cases the code is being called from the main UI thread.
Another odd thing is that the code throwing the exception is contained within a try/catch block (not shown for simplicity)...but the catch block doesn't catch the exception. Instead, it gets caught by the unhandled exception handler generated by WinUI3.
Advice on how to proceed with researching what's going wrong -- or potential solutions! -- would be appreciated, thanx.
I recently tried to figure out how promises works in ECMAScript. Most interested in the construction of AwaitExpression. In my opinion, it is the most incomprehensible and rather complicated in the specification.
Let me give some code:
/// Promise
var promiseA = new Promise((resolve, reject) => {
setTimeout(() => resolve("Done!"), 10000)
});
/// Async/Await
(async function(){
var result = await promiseA;
console.log(result); /// Output: "Done!"
})();
/// Promise.prototype.then
promiseA.then(function (result){
console.log(result); /// Output: "Done!"
});
For me, as I said above, AwaitExpression is incomprehensible, I do not understand where the return of the value from promise is going. But I understand where the value from [[PromiseResult]] comes from and how the value [[PromiseResult]] from .then is passed into the argument to the callback function.
And there are some steps that unfortunately are not clear to me from Await ():
Remove asyncContext from the execution context stack and restore the execution context that is at the top of the execution context
stack as the running execution context.
Set the code evaluation state of asyncContext such that when evaluation is resumed with a Completion completion, the following
steps of the algorithm that invoked Await will be performed, with
completion available.
Return.
NOTE: This returns to the evaluation of the operation that had most previously resumed evaluation of asyncContext.
And part of the actions from the Await Fulfilled Functions is still not quite clear:
Resume the suspended evaluation of asyncContext using NormalCompletion(value) as the result of the operation that suspended
it.
Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the
currently running execution context.
Return undefined.
P.S How Promise and .then are executed is clear to me, you can take this into account when explaining AwaitExpression.
I think the critical thing to keep in mind when reading this is that the spec is free to start and stop execution of a given function right in the middle. When that happens, the function literally stops exactly where it is, but the spec steps keep going.
Given your example
(async function(){
var result = await promiseA;
console.log(result); /// Output: "Done!"
})();
in spec terms, this functions becomes:
Call the async function [[Call]]
Do the normal prep work that function has
OrdinaryCallEvaluateBody
EvaluateBody for async functions
Create the promise that gets returned by the async function
AsyncFunctionStart
Initialize the promise object that gets returned
Mark the execution context such that, when it fully completes, it will fulfill or reject the promise.
Start executing the steps of the function, one at a time
Eventually we get to the await and do:
Using the awaited promise, set it up so that the async function will resume execution when the promise finishes. (Step 2-9)
"pop the execution context" which marks what step we were in the function, so that it can be started again later. (Step 10 in your quote)
Set a flag on the execution context saying "the function is suspended, when it resumes, you will get the result of a promise, please resume the function as if the promise result was the completion value of the 'await'. (Step 11)
Return. (Step 12).
Return the promise for the async fn result.
The core thing to understand, is that Step 12 is not returning into the async function, because it was suspended. It is returning to AsyncFunctionStart, which then returns to EvaluateBody, which then returns the Promise result of the async function.
Then, later when the promiseA fulfills (due to the work of step 2-9 earlier)
Set the async function as the active execution context again (Step 5 of "Await Fulfilled Functions")
Resume execution with the result of the promise as the "completion" (Step 6). Because of the flags set on Step 11, this uses the completion value as the result of the await, and picks up execution of the async function until it returns, or awaits again.
Assert that the async function has finished some work for now (Step 7)
Return. (Step 8)
It's the part
using NormalCompletion(value) as the result of the operation that suspended it.
from the text you quoted. It will resume the execution of the async function, and make the await expression have the value as the result. Compare the yield operation and the generator next() method for reference.
I've just recently finished working on a rather complex contract with the Remix IDE. I'm now attaching web3 to the frontend but when I call functions that should fail, they still go through on Metamask.
When testing my contract in Remix, I would often click on and call certain functions that had require statements that I knew would fail just to confirm that the contract state was recorded correctly. Remix didn't send the transaction to metamask and instead output an error message and I would like to handle the transaction error on my own as well.
How can I check my contract call to see whether it will fail. Must I use the method that predicts gas and detect it that way and if so how? My current code is below:
contract.callFunction(function(error, result) {
if (!error) alert(result);
else alert(error);
}
The above code catches rejecting the metamask confirmation as an error but transactions that should fail go through to metamask with an insanely high gas limit set. The function callFunction is in the contract and takes no parameters but does have an effect on the blockchain so it requires the transaction. The first line of the function is "require(state == 1);" and I have the contract set to state 2 currently so I'm expecting the transaction to fail, I just want to detect it failing.
In order to find out whether the transaction will fail we do have to call estimateGas() and attach a callback function. I assumed we'd have to check the gas estimate returned in order to predict whether it would fail but the process is made rather easy. Here's the full code I ended up with to successfully run a function while catching the two most common error cases.
contract.nextState.estimateGas(function(error, result) {
if (!error) {
contract.nextState(function(error, result) {
if (!error) {
alert("This is my value: " + result);
} else {
if (error.message.indexOf("User denied") != -1) {
alert("You rejected the transaction on Metamask!");
} else {
alert(error);
}
}
});
} else {
alert("This function cannot be run at this time.");
}
});
[EDIT] I'm coming back after the fact to help clear up information for those with a similar question. All of the information discussed below references the following link.
After creating a contract object, you can access any variable or function through using it's name. You can also access these members through array notation which is useful when the name of the variable or function isn't known at the time the code is written.
contract.foobar == contract["foobar"]
Once you have a function object (contract.foobar) you can use either call, send, or estimateGas. After first giving the function the parameters it needs (call it like any other function) you then use either call, send, or estimateGas on the returned object while providing options and a callback function.
This callback function takes 2 parameters. The first is the error which will be undefined if there was no error, and the second will be the result of the call, send, or estimateGas. Call and Send will both return the result of the function while estimateGas always returns a number showing how much gas is estimated to be necessary.
According to Uncle Bob in his Clean Code book: Functions should either do something or answer something.
So commands (do something) must not to return some information. But, it's useful to know if the command was executed without error.
For that, we can throw an exception that we catch in try/catch.
But, the reactive way (rxjs) seems to be little bit different.
If we take this code sample:
function test(var: number): Observable<void> {
if(var == 2)
return Rx.Observable.throw("error")
return Rx.Observable.of(var)
}
let foo = test(1).catch(err => Rx.Observable.of(err))
foo.subscribe(val => console.log(val))
let foo2 = test(2).catch(err => Rx.Observable.of(err))
foo2.subscribe(val => console.log(val))
Console log of foo displays 1 and it's quite logic. Console log of foo2 displays "error" and it's logic too.
Maybe, I don't use correctly throw and .catch?
To use the catch operator, I have to return an Observable otherwise I have a javascript error (Cannot read property 'catch' of undefined).
That's mean we always must to return something?
Whenever a test function (a function annotated with test) contains assertions that fail, the assertion has the same effect as when trowing an exception: no further code lines in that function will be executed. Thus, assert statements in functions that are annotated with 'test' works just as ordinary assert statements in ordinary Ceylon functions. This runs contrary to the documentation, which states that ordinary assert statements can be used for making unit tests.
Thus, running the code below, I get to see the statement myTests1 but not ´myTests2`:
import ceylon.test {
test, TestRunner, createTestRunner
}
test
Anything myTests1 () {
// assert something true!
assert(40 + 2 == 42);
print("myTests1");
return null;
}
test
void myTests2 () {
// assert something false!
assert(2 + 2 == 54);
print("myTests2");
}
"Run the module `tests`."
shared void run() {
print("reached run function");
TestRunner myTestRunner = createTestRunner(
[`function myTests1`, `function myTests2`]);
myTestRunner.run();
}
This is the actual output:
"C:\Program Files\Java\jdk1.8.0_121\bin\java" -Dceylon.system.repo=C:\Users\Jon\.IdeaIC2017.2\config\plugins\CeylonIDEA\classes\embeddedDist\repo "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.2.1\lib\idea_rt.jar=56393:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.2.1\bin" -Dfile.encoding=windows-1252 -classpath C:\Users\Jon\.IdeaIC2017.2\config\plugins\CeylonIDEA\classes\embeddedDist\lib\ceylon-bootstrap.jar com.redhat.ceylon.launcher.Bootstrap run --run run tests/1.0.0
reached run function
myTests1
Process finished with exit code 0
This is working as intended – replacing those asserts with assertEquals’ has the same effect and prints the same output, because both do exactly the same thing: throw an exception if the assertion fails.
All test frameworks that I’m aware of behave the same way in this situation: an assertion failure results in an exception and thus immediately terminates execution of the test method. This is by design, since you don’t know what your program will do once one expectation will be violated – the rest of the method might depend on that assertion holding true, and might break in unpredictable and confusing ways.
If you’re writing tests like
test
shared void testTwoThings() {
assertEquals { expected = 42; actual = 40 + 2; };
assertEquals { expected = 42; actual = 6 * 9; };
}
you’re supposed to write two tests instead.