| // Copyright (c) 2013, 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. |
| |
| @JS() |
| library js_native_test; |
| |
| import 'dart:async'; |
| import 'dart:html'; |
| import 'dart:typed_data' show ByteBuffer, Int32List; |
| import 'dart:indexed_db' show IdbFactory, KeyRange; |
| |
| import 'package:js/js.dart'; |
| import 'package:js/js_util.dart' as js_util; |
| import 'package:expect/minitest.dart'; |
| import 'package:async_helper/async_helper.dart'; |
| |
| _injectJs() { |
| final script = new ScriptElement(); |
| script.type = 'text/javascript'; |
| script.innerHtml = r""" |
| var x = 42; |
| |
| var _x = 123; |
| |
| var myArray = ["value1"]; |
| |
| function returnThis() { |
| return this; |
| } |
| |
| function getTypeOf(o) { |
| return typeof(o); |
| } |
| |
| function Foo(a) { |
| this.a = a; |
| } |
| |
| Foo.b = 38; |
| |
| Foo.prototype.bar = function() { |
| return this.a; |
| } |
| Foo.prototype.toString = function() { |
| return "I'm a Foo a=" + this.a; |
| } |
| |
| var container = new Object(); |
| container.Foo = Foo; |
| |
| function checkMap(m, key, value) { |
| if (m.hasOwnProperty(key)) |
| return m[key] == value; |
| else |
| return false; |
| } |
| |
| var rejectedPromise = new Promise((resolve, reject) => reject('rejected')); |
| var resolvedPromise = new Promise(resolve => resolve('resolved')); |
| function getResolvedPromise() { |
| return resolvedPromise; |
| } |
| |
| """; |
| document.body!.append(script); |
| } |
| |
| @JS() |
| external bool checkMap(m, String, value); |
| |
| @JS('JSON.stringify') |
| external String stringify(o); |
| |
| @JS('Node') |
| external get JSNodeType; |
| |
| @JS('Element') |
| external get JSElementType; |
| |
| @JS('Text') |
| external get JSTextType; |
| |
| @JS('HTMLCanvasElement') |
| external get JSHtmlCanvasElementType; |
| |
| @JS() |
| class Foo { |
| external Foo(num a); |
| |
| external num get a; |
| external num bar(); |
| } |
| |
| @JS('Foo') |
| external get JSFooType; |
| |
| @JS() |
| @anonymous |
| class ExampleTypedLiteral { |
| external factory ExampleTypedLiteral({a, b, JS$_c, JS$class}); |
| |
| external get a; |
| external get b; |
| external get JS$_c; |
| external set JS$_c(v); |
| // Identical to JS$_c but only accessible within the library. |
| external get _c; |
| external get JS$class; |
| external set JS$class(v); |
| } |
| |
| @JS() |
| abstract class Promise<T> {} |
| |
| @JS() |
| external Promise get resolvedPromise; |
| |
| @JS() |
| external Promise get rejectedPromise; |
| |
| @JS() |
| external Promise getResolvedPromise(); |
| |
| @JS("Object.prototype.hasOwnProperty") |
| external get _hasOwnProperty; |
| |
| bool hasOwnProperty(o, String name) { |
| return js_util.callMethod(_hasOwnProperty, 'call', [o, name]); |
| } |
| |
| main() { |
| _injectJs(); |
| |
| group('js_util.jsify()', () { |
| test('convert a List', () { |
| final list = [1, 2, 3, 4, 5, 6, 7, 8]; |
| var array = js_util.jsify(list); |
| expect(array is List, isTrue); |
| expect(identical(array, list), isFalse); |
| expect(array.length, equals(list.length)); |
| for (var i = 0; i < list.length; i++) { |
| expect(array[i], equals(list[i])); |
| } |
| }); |
| |
| test('convert an Iterable', () { |
| final set = new Set.from([1, 2, 3, 4, 5, 6, 7, 8]); |
| var array = js_util.jsify(set); |
| expect(array is List, isTrue); |
| expect(array.length, equals(set.length)); |
| for (var i = 0; i < array.length; i++) { |
| expect(set.contains(array[i]), isTrue); |
| } |
| }); |
| |
| test('convert a Map', () { |
| var map = {'a': 1, 'b': 2, 'c': 3}; |
| var jsMap = js_util.jsify(map); |
| expect(jsMap is! List, isTrue); |
| for (var key in map.keys) { |
| expect(checkMap(jsMap, key, map[key]), isTrue); |
| } |
| }); |
| |
| test('deep convert a complex object', () { |
| dynamic object = { |
| 'a': [ |
| 1, |
| [2, 3] |
| ], |
| 'b': {'c': 3, 'd': new Foo(42)}, |
| 'e': null |
| }; |
| var jsObject = js_util.jsify(object); |
| expect(js_util.getProperty(jsObject, 'a')[0], equals(object['a'][0])); |
| expect( |
| js_util.getProperty(jsObject, 'a')[1][0], equals(object['a'][1][0])); |
| expect( |
| js_util.getProperty(jsObject, 'a')[1][1], equals(object['a'][1][1])); |
| expect(js_util.getProperty(js_util.getProperty(jsObject, 'b'), 'c'), |
| equals(object['b']['c'])); |
| expect(js_util.getProperty(js_util.getProperty(jsObject, 'b'), 'd'), |
| equals(object['b']['d'])); |
| expect( |
| js_util.callMethod( |
| js_util.getProperty(js_util.getProperty(jsObject, 'b'), 'd'), |
| 'bar', []), |
| equals(42)); |
| expect(js_util.getProperty(jsObject, 'e'), isNull); |
| }); |
| |
| test('throws if object is not a Map or Iterable', () { |
| expect(() => js_util.jsify('a'), throwsArgumentError); |
| }); |
| }); |
| |
| group('js_util.newObject', () { |
| test('create', () { |
| expect(identical(js_util.newObject(), js_util.newObject()), isFalse); |
| }); |
| |
| test('callMethod', () { |
| var o = js_util.newObject(); |
| expect(js_util.callMethod(o, 'toString', []), equals('[object Object]')); |
| expect(stringify(o), equals('{}')); |
| }); |
| |
| test('properties', () { |
| var o = js_util.newObject(); |
| expect(js_util.hasProperty(o, 'foo bar'), isFalse); |
| expect(js_util.hasProperty(o, 'toString'), isTrue); |
| expect(hasOwnProperty(o, 'toString'), isFalse); |
| expect(hasOwnProperty(o, 'foo bar'), isFalse); |
| js_util.setProperty(o, 'foo bar', 42); |
| expect(hasOwnProperty(o, 'foo bar'), isTrue); |
| expect(js_util.getProperty(o, 'foo bar'), equals(42)); |
| expect(js_util.hasProperty(o, 'foo bar'), isTrue); |
| expect(stringify(o), equals('{"foo bar":42}')); |
| }); |
| }); |
| |
| group('hasProperty', () { |
| test('typed object', () { |
| var f = new Foo(42); |
| expect(js_util.hasProperty(f, 'a'), isTrue); |
| expect(js_util.hasProperty(f, 'toString'), isTrue); |
| js_util.setProperty(f, '__proto__', null); |
| expect(js_util.hasProperty(f, 'toString'), isFalse); |
| }); |
| test('typed literal', () { |
| var l = |
| new ExampleTypedLiteral(a: 'x', b: 42, JS$_c: null, JS$class: true); |
| expect(js_util.hasProperty(l, 'a'), isTrue); |
| expect(js_util.hasProperty(l, 'b'), isTrue); |
| expect(js_util.hasProperty(l, '_c'), isTrue); |
| expect(l.JS$_c, isNull); |
| expect(js_util.hasProperty(l, 'class'), isTrue); |
| // JS$_c escapes to _c so the property JS$_c will not exist on the object. |
| expect(js_util.hasProperty(l, r'JS$_c'), isFalse); |
| expect(js_util.hasProperty(l, r'JS$class'), isFalse); |
| expect(l.JS$class, isTrue); |
| |
| l = new ExampleTypedLiteral(a: null); |
| expect(js_util.hasProperty(l, 'a'), isTrue); |
| expect(js_util.hasProperty(l, 'b'), isFalse); |
| expect(js_util.hasProperty(l, '_c'), isFalse); |
| expect(js_util.hasProperty(l, 'class'), isFalse); |
| |
| l = new ExampleTypedLiteral(JS$_c: 74); |
| expect(js_util.hasProperty(l, '_c'), isTrue); |
| expect(l.JS$_c, equals(74)); |
| }); |
| }); |
| |
| group('getProperty', () { |
| test('typed object', () { |
| var f = new Foo(42); |
| expect(js_util.getProperty(f, 'a'), equals(42)); |
| expect(js_util.getProperty(f, 'toString') is Function, isTrue); |
| js_util.setProperty(f, '__proto__', null); |
| expect(js_util.getProperty(f, 'toString'), isNull); |
| }); |
| |
| test('typed literal', () { |
| var l = new ExampleTypedLiteral(a: 'x', b: 42, JS$_c: 7, JS$class: true); |
| expect(js_util.getProperty(l, 'a'), equals('x')); |
| expect(js_util.getProperty(l, 'b'), equals(42)); |
| expect(js_util.getProperty(l, '_c'), equals(7)); |
| expect(l.JS$_c, equals(7)); |
| expect(js_util.getProperty(l, 'class'), isTrue); |
| expect(js_util.getProperty(l, r'JS$_c'), isNull); |
| expect(js_util.getProperty(l, r'JS$class'), isNull); |
| }); |
| }); |
| |
| group('setProperty', () { |
| test('typed object', () { |
| var f = new Foo(42); |
| expect(js_util.getProperty(f, 'a'), equals(42)); |
| js_util.setProperty(f, 'a', 100); |
| expect(f.a, equals(100)); |
| expect(js_util.getProperty(f, 'a'), equals(100)); |
| }); |
| |
| test('typed literal', () { |
| var l = new ExampleTypedLiteral(); |
| js_util.setProperty(l, 'a', 'foo'); |
| expect(js_util.getProperty(l, 'a'), equals('foo')); |
| expect(l.a, equals('foo')); |
| js_util.setProperty(l, 'a', l); |
| expect(identical(l.a, l), isTrue); |
| var list = ['arr']; |
| js_util.setProperty(l, 'a', list); |
| expect(identical(l.a, list), isTrue); |
| l.JS$class = 42; |
| expect(l.JS$class, equals(42)); |
| js_util.setProperty(l, 'class', 100); |
| expect(l.JS$class, equals(100)); |
| }); |
| }); |
| |
| group('callMethod', () { |
| test('html object', () { |
| var canvas = new CanvasElement(); |
| expect( |
| identical(canvas.getContext('2d'), |
| js_util.callMethod(canvas, 'getContext', ['2d'])), |
| isTrue); |
| }); |
| |
| test('typed object', () { |
| var f = new Foo(42); |
| expect(js_util.callMethod(f, 'bar', []), equals(42)); |
| }); |
| }); |
| |
| group('instanceof', () { |
| test('html object', () { |
| var canvas = new Element.tag('canvas'); |
| expect(js_util.instanceof(canvas, JSNodeType), isTrue); |
| expect(js_util.instanceof(canvas, JSTextType), isFalse); |
| expect(js_util.instanceof(canvas, JSElementType), isTrue); |
| expect(js_util.instanceof(canvas, JSHtmlCanvasElementType), isTrue); |
| var div = new Element.tag('div'); |
| expect(js_util.instanceof(div, JSNodeType), isTrue); |
| expect(js_util.instanceof(div, JSTextType), isFalse); |
| expect(js_util.instanceof(div, JSElementType), isTrue); |
| expect(js_util.instanceof(div, JSHtmlCanvasElementType), isFalse); |
| |
| var text = new Text('foo'); |
| expect(js_util.instanceof(text, JSNodeType), isTrue); |
| expect(js_util.instanceof(text, JSTextType), isTrue); |
| expect(js_util.instanceof(text, JSElementType), isFalse); |
| }); |
| |
| test('typed object', () { |
| var f = new Foo(42); |
| expect(js_util.instanceof(f, JSFooType), isTrue); |
| expect(js_util.instanceof(f, JSNodeType), isFalse); |
| }); |
| |
| test('typed literal', () { |
| var l = new ExampleTypedLiteral(); |
| expect(js_util.instanceof(l, JSFooType), isFalse); |
| }); |
| }); |
| |
| group('callConstructor', () { |
| test('html object', () { |
| var textNode = js_util.callConstructor(JSTextType, ['foo']); |
| expect(js_util.instanceof(textNode, JSTextType), isTrue); |
| expect(textNode is Text, isTrue); |
| expect(textNode.text, equals('foo')); |
| }); |
| |
| test('typed object', () { |
| Foo f = js_util.callConstructor(JSFooType, [42]); |
| expect(f.a, equals(42)); |
| }); |
| }); |
| |
| Future<void> testResolvedPromise() async { |
| final String result = await js_util.promiseToFuture(resolvedPromise); |
| expect(result, equals('resolved')); |
| } |
| |
| Future<void> testRejectedPromise() async { |
| try { |
| final String result = await promiseToFuture(rejectedPromise); |
| fail('expected Future to throw an error'); |
| } catch (error) { |
| expect(error, equals('rejected')); |
| } |
| } |
| |
| Future<void> testReturnRejectedPromise() async { |
| final String result = await promiseToFuture(getResolvedPromise()); |
| expect(result, equals('resolved')); |
| } |
| |
| asyncTest(() async { |
| await testResolvedPromise(); |
| await testRejectedPromise(); |
| await testReturnRejectedPromise(); |
| }); |
| } |