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
No comments:
Post a Comment