blob: c8c02600743cdb4c345d992d4f709891ccfc16f7 [file] [log] [blame]
// 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);
});
});
}