| Index: tests/html/js_typed_interop_test.dart | 
| diff --git a/tests/html/js_typed_interop_test.dart b/tests/html/js_typed_interop_test.dart | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..c8c02600743cdb4c345d992d4f709891ccfc16f7 | 
| --- /dev/null | 
| +++ b/tests/html/js_typed_interop_test.dart | 
| @@ -0,0 +1,139 @@ | 
| +// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file | 
| +// for details. All rights reserved. Use of this source code is governed by a | 
| +// BSD-style license that can be found in the LICENSE file. | 
| + | 
| +library jsArrayTest; | 
| + | 
| +import 'dart:html'; | 
| +import 'dart:js'; | 
| + | 
| +import 'package:unittest/unittest.dart'; | 
| +import 'package:unittest/html_config.dart'; | 
| + | 
| +_injectJs() { | 
| +  document.body.append(new ScriptElement() | 
| +    ..type = 'text/javascript' | 
| +    ..innerHtml = r""" | 
| +  var foo = { | 
| +    x: 3, | 
| +    z: 40, // Not specified in typed Dart API so should fail in checked mode. | 
| +    multiplyByX: function(arg) { return arg * this.x; }, | 
| +    // This function can be torn off without having to bind this. | 
| +    multiplyBy2: function(arg) { return arg * 2; } | 
| +  }; | 
| + | 
| +  var foob = { | 
| +    x: 8, | 
| +    y: "why", | 
| +    multiplyByX: function(arg) { return arg * this.x; } | 
| +  }; | 
| + | 
| +  var bar = { | 
| +    x: "foo", | 
| +    multiplyByX: true | 
| +  }; | 
| + | 
| +  var selection = ["a", "b", "c", foo, bar]; | 
| +  selection.doubleLength = function() { return this.length * 2; }; | 
| +"""); | 
| +} | 
| + | 
| +abstract class Foo { | 
| +  int get x; | 
| +  set x(int v); | 
| +  num multiplyByX(num y); | 
| +  num multiplyBy2(num y); | 
| +} | 
| + | 
| +abstract class Foob extends Foo { | 
| +  final String y; | 
| +} | 
| + | 
| +abstract class Bar { | 
| +  String get x; | 
| +  bool get multiplyByX; | 
| +} | 
| + | 
| +class Baz {} | 
| + | 
| +// This class shows the pattern used by APIs such as jQuery that add methods | 
| +// to Arrays. | 
| +abstract class Selection implements List { | 
| +  num doubleLength(); | 
| +} | 
| + | 
| +Foo get foo => context['foo']; | 
| +Foob get foob => context['foob']; | 
| +Bar get bar => context['bar']; | 
| +Selection get selection => context['selection']; | 
| + | 
| +main() { | 
| +  // Call experimental API to register Dart interfaces implemented by | 
| +  // JavaScript classes. | 
| +  registerJsInterfaces([Foo, Foob, Bar, Selection]); | 
| + | 
| +  _injectJs(); | 
| + | 
| +  useHtmlConfiguration(); | 
| + | 
| +  group('property', () { | 
| +    test('get', () { | 
| +      expect(foo.x, equals(3)); | 
| +      expect(foob.x, equals(8)); | 
| +      expect(foob.y, equals("why")); | 
| + | 
| +      // Exists in JS but not in API. | 
| +      expect(() => foo.z, throws); | 
| +      expect(bar.multiplyByX, isTrue); | 
| +    }); | 
| +    test('set', () { | 
| +      foo.x = 42; | 
| +      expect(foo.x, equals(42)); | 
| +      // Property tagged as read only in typed API. | 
| +      expect(() => foob.y = "bla", throws); | 
| +      expect(() => foo.unknownName = 42, throws); | 
| +    }); | 
| +  }); | 
| + | 
| +  group('method', () { | 
| +    test('call', () { | 
| +      foo.x = 100; | 
| +      expect(foo.multiplyByX(4), equals(400)); | 
| +      foob.x = 10; | 
| +      expect(foob.multiplyByX(4), equals(40)); | 
| +    }); | 
| + | 
| +    test('tearoff', () { | 
| +      foo.x = 10; | 
| +      // TODO(jacobr): should we automatically bind "this" for tearoffs of JS | 
| +      // objects? | 
| +      JsFunction multiplyBy2 = foo.multiplyBy2; | 
| +      expect(multiplyBy2(5), equals(10)); | 
| +    }); | 
| +  }); | 
| + | 
| +  group('type check', () { | 
| +    test('js interfaces', () { | 
| +      expect(foo is JsObject, isTrue); | 
| +      // Cross-casts are allowed. | 
| +      expect(foo is Bar, isTrue); | 
| +      expect(selection is JsArray, isTrue); | 
| + | 
| +      // We do know at runtime whether something is a JsArray or not. | 
| +      expect(foo is JsArray, isFalse); | 
| +    }); | 
| + | 
| +    test('dart interfaces', () { | 
| +      expect(foo is Function, isFalse); | 
| +      expect(selection is List, isTrue); | 
| +    }); | 
| +  }); | 
| + | 
| +  group("registration", () { | 
| +    test('repeated fails', () { | 
| +      // The experimental registerJsInterfaces API has already been called so | 
| +      // it cannot be called a second time. | 
| +      expect(() => registerJsInterfaces([Baz]), throws); | 
| +    }); | 
| +  }); | 
| +} | 
|  |