[dart2wasm] Fix null rejection exception and add tests for conversions
Then callbacks should accept and return a JSAny?. Some JS types tests were incomplete as well. Change-Id: Id46e2a53f8f83ce17247fbd23d5be82f3f986f30 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/326688 Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Srujan Gaddam <srujzs@google.com>
This commit is contained in:
committed by
Commit Queue
parent
94e4a4dfb5
commit
d54f0acd02
@@ -102,17 +102,19 @@ extension ObjectToJSBoxedDartObject on Object {
|
||||
extension JSPromiseToFuture on JSPromise {
|
||||
@patch
|
||||
Future<JSAny?> get toDart {
|
||||
final completer = Completer<JSAny>();
|
||||
final success = (JSAny r) {
|
||||
final completer = Completer<JSAny?>();
|
||||
final success = (JSAny? r) {
|
||||
return completer.complete(r);
|
||||
}.toJS;
|
||||
final error = (JSAny e) {
|
||||
final error = (JSAny? e) {
|
||||
// TODO(joshualitt): Investigate reifying `JSNull` and `JSUndefined` on
|
||||
// all backends and if it is feasible, or feasible for some limited use
|
||||
// cases, then we should pass [e] directly to `completeError`.
|
||||
// TODO(joshualitt): Use helpers to avoid conflating `null` and `JSNull` /
|
||||
// `JSUndefined`.
|
||||
if (e == null) {
|
||||
// Note that we pass false as a default. It's not currently possible to
|
||||
// be able to differentiate between null and undefined.
|
||||
return completer.completeError(js_util.NullRejectionException(false));
|
||||
}
|
||||
return completer.completeError(e);
|
||||
|
||||
@@ -316,86 +316,98 @@ void syncTests() {
|
||||
expect(typeofEquals(definedNonNullAny, 'object'), true);
|
||||
}
|
||||
|
||||
@JS()
|
||||
external JSPromise get resolvedPromise;
|
||||
|
||||
@JS()
|
||||
external JSPromise get rejectedPromise;
|
||||
|
||||
@JS()
|
||||
external JSPromise getResolvedPromise();
|
||||
|
||||
@JS()
|
||||
external JSPromise getRejectablePromise();
|
||||
external JSPromise getRejectedPromise();
|
||||
|
||||
@JS()
|
||||
external JSVoid rejectPromiseWithNull();
|
||||
external JSPromise resolvePromiseWithNullOrUndefined(bool resolveWithNull);
|
||||
|
||||
@JS()
|
||||
external JSVoid rejectPromiseWithUndefined();
|
||||
external JSPromise rejectPromiseWithNullOrUndefined(bool resolveWithNull);
|
||||
|
||||
Future<void> asyncTests() async {
|
||||
eval(r'''
|
||||
globalThis.resolvedPromise = new Promise(resolve => resolve('resolved'));
|
||||
globalThis.getResolvedPromise = function() {
|
||||
return resolvedPromise;
|
||||
return Promise.resolve('resolved');
|
||||
}
|
||||
globalThis.getRejectablePromise = function() {
|
||||
return new Promise(function(_, reject) {
|
||||
globalThis.rejectPromise = reject;
|
||||
});
|
||||
globalThis.getRejectedPromise = function() {
|
||||
return Promise.reject(new Error('rejected'));
|
||||
}
|
||||
globalThis.rejectPromiseWithNull = function() {
|
||||
globalThis.rejectPromise(null);
|
||||
globalThis.resolvePromiseWithNullOrUndefined = function(resolveWithNull) {
|
||||
return Promise.resolve(resolveWithNull ? null : undefined);
|
||||
}
|
||||
globalThis.rejectPromiseWithUndefined = function() {
|
||||
globalThis.rejectPromise(undefined);
|
||||
globalThis.rejectPromiseWithNullOrUndefined = function(rejectWithNull) {
|
||||
return Promise.reject(rejectWithNull ? null : undefined);
|
||||
}
|
||||
''');
|
||||
|
||||
// [JSPromise] -> [Future].
|
||||
// Test resolved
|
||||
{
|
||||
Future<JSAny?> f = resolvedPromise.toDart;
|
||||
expect(((await f) as JSString).toDart, 'resolved');
|
||||
}
|
||||
|
||||
// Test rejected
|
||||
// TODO(joshualitt): Write a test for rejected promises that works on all
|
||||
// backends.
|
||||
|
||||
// Test return resolved
|
||||
// Test resolution.
|
||||
{
|
||||
Future<JSAny?> f = getResolvedPromise().toDart;
|
||||
expect(((await f) as JSString).toDart, 'resolved');
|
||||
}
|
||||
|
||||
// Test promise chaining
|
||||
// Test rejection.
|
||||
{
|
||||
try {
|
||||
await getRejectedPromise().toDart;
|
||||
fail('Expected rejected promise to throw.');
|
||||
} catch (e) {
|
||||
final jsError = e as JSObject;
|
||||
expect(jsError.toString(), 'Error: rejected');
|
||||
}
|
||||
}
|
||||
|
||||
// Test resolution Promise chaining.
|
||||
{
|
||||
bool didThen = false;
|
||||
Future<JSAny?> f = getResolvedPromise().toDart;
|
||||
f.then((resolved) {
|
||||
Future<JSAny?> f = getResolvedPromise().toDart.then((resolved) {
|
||||
expect((resolved as JSString).toDart, 'resolved');
|
||||
didThen = true;
|
||||
return null;
|
||||
});
|
||||
await f;
|
||||
expect(didThen, true);
|
||||
}
|
||||
|
||||
// Test rejecting promise with null should trigger an exception.
|
||||
// TODO(joshualitt): `catchError` doesn't seem to clear the JS exception on
|
||||
// Dart2Wasm.
|
||||
//{
|
||||
// bool threw = false;
|
||||
// Future<JSAny?> f = getRejectablePromise().toDart;
|
||||
// f.then((_) {}).catchError((e) {
|
||||
// threw = true;
|
||||
// expect(e is NullRejectionException, true);
|
||||
// });
|
||||
// rejectPromiseWithNull();
|
||||
// await f;
|
||||
// expect(threw, true);
|
||||
//}
|
||||
// Test rejection Promise chaining.
|
||||
{
|
||||
Future<JSAny?> f = getRejectedPromise().toDart.then((_) {
|
||||
fail('Expected rejected promise to throw.');
|
||||
return null;
|
||||
}, onError: (e) {
|
||||
final jsError = e as JSObject;
|
||||
expect(jsError.toString(), 'Error: rejected');
|
||||
});
|
||||
await f;
|
||||
}
|
||||
|
||||
// Test resolving promise with null and undefined.
|
||||
Future<void> testResolveWithNullOrUndefined(bool resolveWithNull) async {
|
||||
Future<JSAny?> f =
|
||||
resolvePromiseWithNullOrUndefined(resolveWithNull).toDart;
|
||||
expect(((await f) as JSAny?), null);
|
||||
}
|
||||
|
||||
await testResolveWithNullOrUndefined(true);
|
||||
await testResolveWithNullOrUndefined(false);
|
||||
|
||||
// Test rejecting promise with null and undefined should trigger an exception.
|
||||
Future<void> testRejectionWithNullOrUndefined(bool rejectWithNull) async {
|
||||
try {
|
||||
await rejectPromiseWithNullOrUndefined(rejectWithNull).toDart;
|
||||
fail('Expected rejected promise to throw.');
|
||||
} catch (e) {
|
||||
expect(e is NullRejectionException, true);
|
||||
}
|
||||
}
|
||||
|
||||
await testRejectionWithNullOrUndefined(true);
|
||||
await testRejectionWithNullOrUndefined(false);
|
||||
}
|
||||
|
||||
void main() async {
|
||||
|
||||
Reference in New Issue
Block a user