dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.22k stars 1.57k forks source link

Can't `.toJS` a `Future<Never>` function. #56369

Open ditman opened 2 months ago

ditman commented 2 months ago

We've been porting some old test code to a newer style, and I was trying to "mock" a function that ends up throwing:

mockMediaDevices.getUserMedia = ([web.MediaStreamConstraints? _]) {
  throw web.DOMException('', 'NotFoundError');
}.toJS;

However the compiler complains that it doesn't like Never:

org-dartlang-app:/camera_service_test.dart:103:13: Error: Function converted via 'toJS' contains invalid types in its
function signature: '*Never* Function(MediaStreamConstraints?)'.
Use one of these valid types instead: JS types from 'dart:js_interop', ExternalDartReference, void, bool, num,
double, int, String, extension types that erase to one of these types, '@staticInterop' types, 'dart:html' types when
compiling to JS, or a type parameter that is a subtype of a valid non-primitive type.
          }.toJS;
            ^
the Dart compiler exited unexpectedly.
Failed to compile application.

So I need to end up doing:

mockMediaDevices.getUserMedia = ([web.MediaStreamConstraints? _]) {
  throw web.DOMException('', 'NotFoundError');
  // ignore: dead_code
  return Future<web.MediaStream>.value(web.MediaStream()).toJS;
}.toJS;

Is there a more graceful way to handle something like this?

dart-github-bot commented 2 months ago

Summary: The toJS method cannot be used on a function that returns Future<Never> because it throws an exception and never completes. The user is looking for a more elegant way to mock a function that throws an exception.

ditman commented 2 months ago

Good bot @dart-github-bot !

srujzs commented 2 months ago

I think the conflict is really Never and not Future<Never> looking at the static type.

At some point we discussed supporting Never in the allowed types but decided against it for some reason I don't remember. Maybe because the exception is not really a JS value? That's an insufficient reason if so, and we should support this.

A cleaner workaround may be to cast the function to a valid type e.g.

((() => throw 'done') as void Function()).toJS;