Dart VM tests with `dart:html` — yes, you can!
Well, sort of. Let me clarify what I mean by yes, you can
. By default, running VM tests doesn’t allow for dart:html
import. If you try, you will see a message similar to this:
Unable to spawn isolate: The built-in library 'dart:html' is not available on the stand-alone VM.
You can still run such tests in a browser (Dart won’t leave you hanging) by simply passing -p somebrowser
to pub
. More info about supported platforms here. However, this has some drawbacks:
- you must have some kind of browser to run them
- they are always slower than VM tests
- sometimes you just need a super-small subset of browser functionality to get going
- sometimes
dart:html
features are completely unused, transitive dependency that should not have any effect or impact on the test results*
I build Angular Dart applications with complex business logic. A lot of the code is completely decoupled from the browser that can be easily unit-tested, however some have that annoying transitive import somewhere deep in the code. A way I found to deal with this is via optional imports. A side note: I still have concerns about this approach and will be interested to read community response to it.
* You will need a transformer or similar mechanics to go over source files and make sure that server compatible imports are used — everywhere.
The magic of optional imports
Or you might see them as “configuration specific imports”. A quick google search will reveal poor results to understand it. In short, the syntax looks like this:
import "something.dart" if (condition) "other.dart";
Very useful if your application/package targets multiple platforms such as browsers, NodeJS (eg. DartSass) or DartVM.
condition
is evaluated to true by passing a -D
flag to dart
command.
dart -Dcondition=true my_app.dart
or by setting a special DART_VM_OPTIONS
environment variable. This latter is particularly useful if you intend to run your app via pub or other build tools. (again, search for this in google site:dartlang.org "DART_VM_OPTIONS"
)
A simple use-case
Consider the following piece of code and the test to it.
All it does: naively extracts textual content split by space from a piece of markup. One could go to great lengths to make this functionality VM compatible by parsing, sanitizing the input or could go the quicker route: use what we already got to do the same.
One problem: won’t run on VM.
Let’s alter it (patch syntax ahead)
-import 'dart:html';
+import 'dart:html' if (dart_vm) 'package:html/dom.dart';
With the modification of that one line — symbols that are normally in dart:html
and is only available in the browser — are available on the VM as well. package:html
offers a lot of the same (mostly compatible) functionality.
To run this test, the following one-liner can be used to set the appropriate VM flag and lunch it via pub.
DART_VM_OPTIONS=-Ddart_vm=true pub run test test/extract_test.dart
On windows you can do the same
set DART_VM_OPTIONS=-Ddart_vm=true
pub run test test\extract_test.dart
Test reliability matter
A personal note: there are things to consider when using this method. Developers should check if such package replacements can be made. Eg. implementations are compatible with each-other.
All in all, I hope you find the information useful. Thanks for the read!