| 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
|
| index c8c02600743cdb4c345d992d4f709891ccfc16f7..69cc733cd98ce9d9ae8387d8f90ae1c0c30178fa 100644
|
| --- a/tests/html/js_typed_interop_test.dart
|
| +++ b/tests/html/js_typed_interop_test.dart
|
| @@ -19,7 +19,19 @@ _injectJs() {
|
| 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; }
|
| + multiplyBy2: function(arg) { return arg * 2; },
|
| + callClosureWithArg1: function(closure, arg) {
|
| + return closure(arg);
|
| + },
|
| + callClosureWithArg2: function(closure, arg1, arg2) {
|
| + return closure(arg1, arg2);
|
| + },
|
| + callClosureWithArgAndThis: function(closure, arg) {
|
| + return closure.apply(this, [arg]);
|
| + },
|
| + getBar() {
|
| + return bar;
|
| + }
|
| };
|
|
|
| var foob = {
|
| @@ -30,7 +42,10 @@ _injectJs() {
|
|
|
| var bar = {
|
| x: "foo",
|
| - multiplyByX: true
|
| + multiplyByX: true,
|
| + getFoo() {
|
| + return foo;
|
| + }
|
| };
|
|
|
| var selection = ["a", "b", "c", foo, bar];
|
| @@ -38,34 +53,56 @@ _injectJs() {
|
| """);
|
| }
|
|
|
| -abstract class Foo {
|
| - int get x;
|
| - set x(int v);
|
| - num multiplyByX(num y);
|
| - num multiplyBy2(num y);
|
| +// TODO(jacobr): depend on package:js instead of defining this annotation here.
|
| +class JsName {
|
| + const JsName();
|
| }
|
|
|
| -abstract class Foob extends Foo {
|
| - final String y;
|
| +@JsName()
|
| +class Foo extends JavaScriptObject {
|
| + int get x => JsNative.getProperty(this, 'x');
|
| + set x(int v) => JsNative.setProperty(this, 'x', v);
|
| + num multiplyByX(num y) => JsNative.callMethod1(this, 'multiplyByX', y);
|
| + num multiplyBy2(num y) => JsNative.callMethod1(this, 'multiplyBy2', y);
|
| + callClosureWithArgAndThis(Function closure, arg) =>
|
| + JsNative.callMethod2(this, 'callClosureWithArgAndThis', closure, arg);
|
| + callClosureWithArg1(Function closure, arg1) =>
|
| + JsNative.callMethod2(this, 'callClosureWithArg1', closure, arg1);
|
| + callClosureWithArg2(Function closure, arg1, arg2) =>
|
| + JsNative.callMethod3(this, 'callClosureWithArg2', closure, arg1, arg2);
|
| + Bar getBar() => JsNative.callMethod0(this, 'getBar');
|
| + static int multiply(int a, int b) => a * b;
|
| }
|
| +// TODO(jacobr): check chained calls of a().b().c()
|
| +// as this case will bust Dart2Js if it concludes that c() is not reachable or is not
|
| +// an interceptor.
|
|
|
| -abstract class Bar {
|
| - String get x;
|
| - bool get multiplyByX;
|
| +@JsName()
|
| +class Foob extends Foo {
|
| + String get y => JsNative.getProperty(this, 'y');
|
| +}
|
| +
|
| +@JsName()
|
| +class Bar extends JavaScriptObject {
|
| + String get x => JsNative.getProperty(this, 'x');
|
| + bool get multiplyByX => JsNative.getProperty(this, 'multiplyByX');
|
| + Foo getFoo() => JsNative.callMethod0(this, 'getFoo');
|
| }
|
|
|
| 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();
|
| +// This class shows the pattern used by APIs like jQuery that add methods
|
| +// to array like objects.
|
| +abstract class Selection implements JsArray {
|
| + num doubleLength() => JsNative.callMethod0(this, 'doubleLength');
|
| }
|
|
|
| -Foo get foo => context['foo'];
|
| -Foob get foob => context['foob'];
|
| -Bar get bar => context['bar'];
|
| -Selection get selection => context['selection'];
|
| +Foo get foo => JsNative.getProperty(nativeContext, 'foo');
|
| +Foob get foob => JsNative.getProperty(nativeContext, 'foob');
|
| +Bar get bar => JsNative.getProperty(nativeContext, 'bar');
|
| +Selection get selection => JsNative.getProperty(nativeContext, 'selection');
|
| +
|
| +addWithDefault(a, [b = 100]) => a + b;
|
|
|
| main() {
|
| // Call experimental API to register Dart interfaces implemented by
|
| @@ -83,15 +120,15 @@ main() {
|
| expect(foob.y, equals("why"));
|
|
|
| // Exists in JS but not in API.
|
| - expect(() => foo.z, throws);
|
| + expect(() => (foo as dynamic).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);
|
| + expect(() => (foob as dynamic).y = "bla", throws);
|
| + expect(() => (foo as dynamic).unknownName = 42, throws);
|
| });
|
| });
|
|
|
| @@ -105,22 +142,72 @@ main() {
|
|
|
| test('tearoff', () {
|
| foo.x = 10;
|
| - // TODO(jacobr): should we automatically bind "this" for tearoffs of JS
|
| - // objects?
|
| - JsFunction multiplyBy2 = foo.multiplyBy2;
|
| + Function multiplyBy2 = foo.multiplyBy2;
|
| expect(multiplyBy2(5), equals(10));
|
| + Function multiplyByX = foo.multiplyByX;
|
| + // Tearing off a JS closure doesn't bind this.
|
| + // You will need to use the new method tearoff syntax to bind this.
|
| + expect(multiplyByX(4), isNaN);
|
| + });
|
| + });
|
| +
|
| + group('static method', () {
|
| + test('call from dart', () {
|
| + expect(Foo.multiply(6, 7), equals(42));
|
| + Function tearOffMethod = Foo.multiply;
|
| + expect(tearOffMethod(6, 6), equals(36));
|
| + });
|
| + });
|
| +
|
| + group('closure', () {
|
| + test('call from js', () {
|
| + localClosure(x) => x * 10;
|
| + var wrappedLocalClosure = allowInterop(localClosure);
|
| + expect(
|
| + identical(allowInterop(localClosure), wrappedLocalClosure), isTrue);
|
| + expect(foo.callClosureWithArg1(wrappedLocalClosure, 10), equals(100));
|
| + expect(foo.callClosureWithArg1(wrappedLocalClosure, "a"),
|
| + equals("aaaaaaaaaa"));
|
| + expect(foo.callClosureWithArg1(allowInterop(addWithDefault), 10),
|
| + equals(110));
|
| + expect(foo.callClosureWithArg2(allowInterop(addWithDefault), 10, 20),
|
| + equals(30));
|
| + addThisXAndArg(Foo that, int arg) {
|
| + return foo.x + arg;
|
| + }
|
| + var wrappedCaptureThisClosure = allowInteropCaptureThis(addThisXAndArg);
|
| + foo.x = 20;
|
| + expect(foo.callClosureWithArgAndThis(wrappedCaptureThisClosure, 10),
|
| + equals(30));
|
| + foo.x = 50;
|
| + expect(foo.callClosureWithArgAndThis(wrappedCaptureThisClosure, 10),
|
| + equals(60));
|
| + expect(
|
| + identical(allowInteropCaptureThis(addThisXAndArg),
|
| + wrappedCaptureThisClosure),
|
| + isTrue);
|
| + });
|
| + });
|
| +
|
| + group('chain calls', () {
|
| + test("method calls", () {
|
| + // In dart2js make sure we still use interceptors when making nested
|
| + // calls to objects.
|
| + var bar = foo.getBar().getFoo().getBar().getFoo().getBar();
|
| + expect(bar.x, equals("foo"));
|
| });
|
| });
|
|
|
| group('type check', () {
|
| test('js interfaces', () {
|
| - expect(foo is JsObject, isTrue);
|
| - // Cross-casts are allowed.
|
| + // Is checks return true for all JavaScript interfaces.
|
| expect(foo is Bar, isTrue);
|
| - expect(selection is JsArray, isTrue);
|
| + expect(foo is Foob, isTrue);
|
| +
|
| + expect(selection is List, isTrue);
|
|
|
| // We do know at runtime whether something is a JsArray or not.
|
| - expect(foo is JsArray, isFalse);
|
| + expect(foo is List, isFalse);
|
| });
|
|
|
| test('dart interfaces', () {
|
| @@ -128,12 +215,4 @@ main() {
|
| 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);
|
| - });
|
| - });
|
| }
|
|
|