One of the main reasons that I am switching the ICE Code Editor from JavaScript to Dart is for testing. I keep making all sorts of changes to a moderately large project with no safety net. With the Dart version, I will have type analysis safety net from the outset. Even so, I love me some tests.
The ICE Code Editor is very much a browser-based application. This means that the tests need a simple web page to serve as context for my tests. So I create the following as
test/index.html
:<html> <head> <title>ICE Test Suite</title> <script type="application/dart" src="editor_test.dart"></script> <script type="text/javascript"> // start dart navigator.webkitStartDart(); </script> </head> <body> <h1>Test!</h1> </body> </html>There is not much to this page. The body has an
<h1>
, which serves no purpose other than to have something on the page when viewed in a browser. The two <script>
tags load the test suite and start the dart engine.As for the test suite, I start very simple by testing some default values in the
Editor
class. The test outline will look something like this:import 'package:unittest/unittest.dart'; import 'package:ice_code_editor/editor.dart'; import 'dart:html'; main() { group("defaults", () { // tests will go here... }); }The import statements pull in the libraries that are needed for testing: the unit test library, the class being tested, and 'dart:html' for simple DOM manipulation and querying. Next comes the
main()
function. All Dart scripts need a main()
entry point, so I oblige. I start by jamming all of my tests directly inside the body of the main()
function. Eventually, I will pull them out, but this will do for now. Lastly, I add a test group()
. This is not strictly necessary, but I seem to recall that certain test output formatters appreciate a group()
.With that, I am ready to test the class. It is possible to disable auto-update of the preview layer when code changes take place. I am going to test that an
Editor
instance has auto-update on by default. The test for this is simple enough: test("defaults to auto-update the preview", () {
var it = new Editor('ice');
expect(it.autoupdate, equals(true));
});
The entire content of editor_test.dart
is now:import 'package:unittest/unittest.dart'; import 'package:ice_code_editor/editor.dart'; import 'dart:html'; main() { group("defaults", () { test("defaults to auto-update the preview", () { var it = new Editor('ice'); expect(it.autoupdate, equals(true)); }); }); }To make that pass, I define the
Editor
class in lib/editor.dart
as:import 'dart:html'; class Editor { bool edit_only, autoupdate; String title; Editor(el, {this.edit_only, this.autoupdate:true, this.title}) { } }And it passes. When I load the test page up in Dartium and check the console, I see:
Unfortunately, the bug that suppresses console output in
DumpRenderTree
stills seems to be in place. When I try to test from the command-line, I see console output indicating that the unit test suite is starting, but nothing else:➜ ice-code-editor git:(master) ✗ DumpRenderTree test/index.html CONSOLE MESSAGE: unittest-suite-wait-for-done Content-Type: text/plain layer at (0,0) size 800x600 RenderView at (0,0) size 800x600 layer at (0,0) size 800x600 RenderBlock {HTML} at (0,0) size 800x600 RenderBody {BODY} at (8,8) size 784x571 RenderBlock {H1} at (0,0) size 784x37 RenderText {#text} at (0,0) size 69x36 text run at (0,0) width 69: "Test!" #EOF #EOFHappily, the submitter of that bug noted a workaround. I downgrade the unittest version on which I am depending by editing my package's
pubspec.yaml
to indicate that I want to peg ICE at version 4.0:name: ice_code_editor version: 0.0.1 description: Code Editor + Preview author: Chris Strom <chris@eeecomputes.com> homepage: https://github.com/eee-c/ice-code-editor dependencies: unittest: 0.4.0 js: anyThen re-run
pub install
:➜ ice-code-editor git:(master) ✗ pub install Resolving dependencies... Dependencies installed!I can then get the desired unit test output on the command-line as well:
➜ ice-code-editor git:(master) ✗ DumpRenderTree test/index.html CONSOLE MESSAGE: unittest-suite-wait-for-done Content-Type: text/plain layer at (0,0) size 800x600 RenderView at (0,0) size 800x600 layer at (0,0) size 800x600 RenderBlock {HTML} at (0,0) size 800x600 RenderBody {BODY} at (8,8) size 784x571 RenderBlock {H1} at (0,0) size 784x37 RenderText {#text} at (0,0) size 69x36 text run at (0,0) width 69: "Test!" #EOF #EOF CONSOLE MESSAGE: PASS: defaults defaults to auto-update the preview CONSOLE MESSAGE: CONSOLE MESSAGE: All 1 tests passed. CONSOLE MESSAGE: unittest-suite-successFor good measure, I ensure that
dart_analyzer
is happy:➜ ice-code-editor git:(master) ✗ echo $? 0Before calling it a night, I get started on the js-interop testing, which I need for things like incorporating ACE code editor. I will leave the actual testing until tomorrow, but I would like to ensure that turning it on does not break anything. So I add it to the
Editor
definition:import 'dart:html'; import 'package:js/js.dart' as js; class Editor { bool edit_only, autoupdate; String title; Editor(el, {this.edit_only:false, this.autoupdate:true, this.title}) { var context = js.context; context.ace.edit(el); } }The addition of the js
import
does not break anything, but trying to retrieve the js.context
property cause all sort of bad:unittest-suite-wait-for-done undefined:1 Uncaught ReferenceError: ReceivePortSync is not defined index.html:54 Exception: 'file:///home/chris/repos/ice-code-editor/test/packages/unittest/unittest.dart': Error: line 763 pos 28: type 'ExpectException' is not loaded String message = (e is ExpectException) ? e.message : 'Caught $e'; ^ malformed type used. Stack Trace: #0 _registerException (file:///home/chris/repos/ice-code-editor/test/packages/unittest/unittest.dart:763:28) #1 guardAsync (file:///home/chris/repos/ice-code-editor/test/packages/unittest/unittest.dart:744:23) #2 _nextBatch._nextBatch (file:///home/chris/repos/ice-code-editor/test/packages/unittest/unittest.dart:782:23) #3 runTests.runTests.<anonymous closure> (file:///home/chris/repos/ice-code-editor/test/packages/unittest/unittest.dart:731:16) #4 _defer.<anonymous closure> (file:///home/chris/repos/ice-code-editor/test/packages/unittest/unittest.dart:688:13) #5 _ReceivePortImpl._handleMessage (dart:isolate-patch:81:92)This turns out to be due to the web page that provides context for the test suite. More specifically, it is not sufficient to start the Dart engine if I want to perform any kind of
js-interop
. There is additional setup required that, thankfully, is included in the browser
dart package that is already part of my package dependencies. All I need do is replace this <script>
tag in the web page:<script type="text/javascript"> // start dart navigator.webkitStartDart(); </script>With a single source
<script>
tag instead:<script src="packages/browser/dart.js"></script>Armed with that, I am ready to start testing the ACE setup via
js-interop
. And I'll pick back up there tomorrow.Day #737