OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library js_tests; | |
6 | |
7 import 'dart:async'; | |
8 import 'dart:html'; | |
9 | |
10 import 'package:js/js.dart' as js; | |
11 import 'package:unittest/unittest.dart'; | |
12 import 'package:unittest/html_config.dart'; | |
13 | |
14 class Foo implements js.Serializable<js.Proxy> { | |
15 final js.Proxy _proxy; | |
16 | |
17 Foo(num a) : this._proxy = new js.Proxy(js.context.Foo, a); | |
18 | |
19 js.Proxy toJs() => _proxy; | |
20 | |
21 num get a => _proxy.a; | |
22 num bar() => _proxy.bar(); | |
23 } | |
24 | |
25 class Color implements js.Serializable<String> { | |
26 static final RED = new Color._("red"); | |
27 static final BLUE = new Color._("blue"); | |
28 String _value; | |
29 Color._(this._value); | |
30 String toJs() => this._value; | |
31 } | |
32 | |
33 main() { | |
34 useHtmlConfiguration(); | |
35 | |
36 test('test scope', () { | |
37 var ctx; | |
38 js.scoped(() { | |
39 ctx = js.context; | |
40 }); | |
41 js.scoped(() { | |
42 expect(() => ctx.x, throws); | |
43 }); | |
44 }); | |
45 | |
46 test('read global field', () { | |
47 expect(js.context.x, equals(42)); | |
48 expect(js.context['x'], equals(42)); | |
49 expect(() => js.context.y, throwsA(isNoSuchMethodError)); | |
50 }); | |
51 | |
52 test('read global field with underscore', () { | |
53 expect(js.context._x, equals(123)); | |
54 expect(js.context['_x'], equals(123)); | |
55 expect(() => js.context._y, throwsA(isNoSuchMethodError)); | |
56 }); | |
57 | |
58 test('js instantiation : new Foo()', () { | |
59 final Foo2 = js.context.container.Foo; | |
60 final foo = new js.Proxy(Foo2, 42); | |
61 expect(foo.a, 42); | |
62 expect(Foo2.b, 38); | |
63 }); | |
64 | |
65 test('js instantiation : new Array()', () { | |
66 final a = new js.Proxy(js.context.Array); | |
67 expect(a, isNotNull); | |
68 expect(a.length, equals(0)); | |
69 | |
70 a.push("value 1"); | |
71 expect(a.length, equals(1)); | |
72 expect(a[0], equals("value 1")); | |
73 | |
74 a.pop(); | |
75 expect(a.length, equals(0)); | |
76 }); | |
77 | |
78 test('js instantiation : new Date()', () { | |
79 final a = new js.Proxy(js.context.Date); | |
80 expect(a.getTime(), isNotNull); | |
81 }); | |
82 | |
83 test('js instantiation : new Date(12345678)', () { | |
84 final a = new js.Proxy(js.context.Date, 12345678); | |
85 expect(a.getTime(), equals(12345678)); | |
86 }); | |
87 | |
88 test('js instantiation : new Date("December 17, 1995 03:24:00 GMT+01:00")', | |
89 () { | |
90 final a = new js.Proxy(js.context.Date, | |
91 "December 17, 1995 03:24:00 GMT+01:00"); | |
92 expect(a.getTime(), equals(819167040000)); | |
93 }); | |
94 | |
95 test('js instantiation : new Date(1995,11,17)', () { | |
96 // Note: JS Date counts months from 0 while Dart counts from 1. | |
97 final a = new js.Proxy(js.context.Date, 1995, 11, 17); | |
98 final b = new DateTime(1995, 12, 17); | |
99 expect(a.getTime(), equals(b.millisecondsSinceEpoch)); | |
100 }); | |
101 | |
102 test('js instantiation : new Date(1995,11,17,3,24,0)', () { | |
103 // Note: JS Date counts months from 0 while Dart counts from 1. | |
104 final a = new js.Proxy.withArgList(js.context.Date, | |
105 [1995, 11, 17, 3, 24, 0]); | |
106 final b = new DateTime(1995, 12, 17, 3, 24, 0); | |
107 expect(a.getTime(), equals(b.millisecondsSinceEpoch)); | |
108 }); | |
109 | |
110 test('js instantiation : new Object()', () { | |
111 final a = new js.Proxy(js.context.Object); | |
112 expect(a, isNotNull); | |
113 | |
114 a.attr = "value"; | |
115 expect(a.attr, equals("value")); | |
116 }); | |
117 | |
118 test(r'js instantiation : new RegExp("^\w+$")', () { | |
119 final a = new js.Proxy(js.context.RegExp, r'^\w+$'); | |
120 expect(a, isNotNull); | |
121 expect(a.test('true'), isTrue); | |
122 expect(a.test(' false'), isFalse); | |
123 }); | |
124 | |
125 test('js instantiation via map notation : new Array()', () { | |
126 final a = new js.Proxy(js.context['Array']); | |
127 expect(a, isNotNull); | |
128 expect(a['length'], equals(0)); | |
129 | |
130 a['push']("value 1"); | |
131 expect(a['length'], equals(1)); | |
132 expect(a[0], equals("value 1")); | |
133 | |
134 a['pop'](); | |
135 expect(a['length'], equals(0)); | |
136 }); | |
137 | |
138 test('js instantiation via map notation : new Date()', () { | |
139 final a = new js.Proxy(js.context['Date']); | |
140 expect(a['getTime'](), isNotNull); | |
141 }); | |
142 | |
143 test('js instantiation : typed array', () { | |
144 final codeUnits = "test".codeUnits; | |
145 final buf = new js.Proxy(js.context.ArrayBuffer, codeUnits.length); | |
146 final bufView = new js.Proxy(js.context.Uint8Array, buf); | |
147 for (var i = 0; i < codeUnits.length; i++) { | |
148 bufView[i] = codeUnits[i]; | |
149 } | |
150 }); | |
151 | |
152 test('write global field', () { | |
153 js.context.y = 42; | |
154 expect(js.context.y, equals(42)); | |
155 expect(js.context['y'], equals(42)); | |
156 }); | |
157 | |
158 test('get JS FunctionProxy', () { | |
159 var razzle = js.context.razzle; | |
160 expect(razzle(), equals(42)); | |
161 }); | |
162 | |
163 test('call JS function', () { | |
164 expect(js.context.razzle(), equals(42)); | |
165 expect(() => js.context.dazzle(), throwsA(isNoSuchMethodError)); | |
166 }); | |
167 | |
168 test('call JS function via map notation', () { | |
169 expect(js.context['razzle'](), equals(42)); | |
170 expect(() => js.context['dazzle'](), throwsA(isNoSuchMethodError)); | |
171 }); | |
172 | |
173 test('call JS function with varargs', () { | |
174 expect(js.context.varArgs(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), | |
175 equals(55)); | |
176 }); | |
177 | |
178 test('allocate JS object', () { | |
179 var foo = new js.Proxy(js.context.Foo, 42); | |
180 expect(foo.a, equals(42)); | |
181 expect(foo.bar(), equals(42)); | |
182 expect(() => foo.baz(), throwsA(isNoSuchMethodError)); | |
183 }); | |
184 | |
185 test('call toString()', () { | |
186 var foo = new js.Proxy(js.context.Foo, 42); | |
187 expect(foo.toString(), equals("I'm a Foo a=42")); | |
188 var container = js.context.container; | |
189 expect(container.toString(), equals("[object Object]")); | |
190 }); | |
191 | |
192 test('allocate simple JS array', () { | |
193 final list = [1, 2, 3, 4, 5, 6, 7, 8]; | |
194 var array = js.array(list); | |
195 expect(js.context.isArray(array), isTrue); | |
196 expect(array.length, equals(list.length)); | |
197 for (var i = 0; i < list.length ; i++) { | |
198 expect(array[i], equals(list[i])); | |
199 } | |
200 }); | |
201 | |
202 test('allocate JS array with iterable', () { | |
203 final set = new Set.from([1, 2, 3, 4, 5, 6, 7, 8]); | |
204 var array = js.array(set); | |
205 expect(js.context.isArray(array), isTrue); | |
206 expect(array.length, equals(set.length)); | |
207 for (var i = 0; i < array.length ; i++) { | |
208 expect(set.contains(array[i]), isTrue); | |
209 } | |
210 }); | |
211 | |
212 test('allocate simple JS map', () { | |
213 var map = {'a': 1, 'b': 2, 'c': 3}; | |
214 var jsMap = js.map(map); | |
215 expect(!js.context.isArray(jsMap), isTrue); | |
216 for (final key in map.keys) { | |
217 expect(js.context.checkMap(jsMap, key, map[key]), isTrue); | |
218 } | |
219 }); | |
220 | |
221 test('allocate complex JS object', () { | |
222 final object = | |
223 { | |
224 'a': [1, [2, 3]], | |
225 'b': { | |
226 'c': 3, | |
227 'd': new js.Proxy(js.context.Foo, 42) | |
228 }, | |
229 'e': null | |
230 }; | |
231 var jsObject = js.map(object); | |
232 expect(jsObject['a'][0], equals(object['a'][0])); | |
233 expect(jsObject['a'][1][0], equals(object['a'][1][0])); | |
234 expect(jsObject['a'][1][1], equals(object['a'][1][1])); | |
235 expect(jsObject['b']['c'], equals(object['b']['c'])); | |
236 expect(jsObject['b']['d'], equals(object['b']['d'])); | |
237 expect(jsObject['b']['d'].bar(), equals(42)); | |
238 expect(jsObject['e'], isNull); | |
239 }); | |
240 | |
241 test('invoke Dart callback from JS', () { | |
242 expect(() => js.context.invokeCallback(), throws); | |
243 | |
244 js.context.callback = new js.Callback.once(() => 42); | |
245 expect(js.context.invokeCallback(), equals(42)); | |
246 expect(() => js.context.invokeCallback(), throws); | |
247 }); | |
248 | |
249 test('callback as parameter', () { | |
250 expect(js.context.getTypeOf(js.context.razzle), equals("function")); | |
251 }); | |
252 | |
253 test('invoke Dart callback from JS with this', () { | |
254 final constructor = new js.Callback.once(($this, arg1) { | |
255 $this.a = 42; | |
256 $this.b = js.array(["a", arg1]); | |
257 }, withThis: true); | |
258 var o = new js.Proxy(constructor, "b"); | |
259 expect(o.a, equals(42)); | |
260 expect(o.b[0], equals("a")); | |
261 expect(o.b[1], equals("b")); | |
262 }); | |
263 | |
264 test('invoke Dart callback from JS with 11 parameters', () { | |
265 js.context.callbackWith11params = new js.Callback.once((p1, p2, p3, p4, | |
266 p5, p6, p7, p8, p9, p10, p11) => '$p1$p2$p3$p4$p5$p6$p7$p8$p9$p10' | |
267 '$p11'); | |
268 expect(js.context.invokeCallbackWith11params(), equals('1234567891011')); | |
269 }); | |
270 | |
271 test('create a Dart callback outside a scope', () { | |
272 // Note, the test framework does not guarantee that each test runs as a | |
273 // separate event. This test creates a new asynchronous event and | |
274 // ensures that a callback can be created without a scope (i.e., that the | |
275 // scope is created on demand). | |
276 final subtest = () { | |
277 var callback = new js.Callback.once(() => 42); | |
278 js.context.callback = callback; | |
279 expect(js.context.invokeCallback(), equals(42)); | |
280 }; | |
281 | |
282 scheduleMicrotask(expectAsync0(subtest)); | |
283 }); | |
284 | |
285 test('global scope', () { | |
286 var x; | |
287 var y; | |
288 js.scoped(() { | |
289 x = new js.Proxy(js.context.Foo, 42); | |
290 y = new js.Proxy(js.context.Foo, 38); | |
291 expect(x.a, equals(42)); | |
292 expect(y.a, equals(38)); | |
293 js.retain(y); | |
294 }); | |
295 js.scoped(() { | |
296 expect(() => x.a, throws); | |
297 expect(y.a, equals(38)); | |
298 js.release(y); | |
299 expect(() => y.a, throws); | |
300 }); | |
301 }); | |
302 | |
303 test('global scope for Serializable', () { | |
304 Foo x; | |
305 Foo y; | |
306 js.scoped(() { | |
307 x = new Foo(42); | |
308 y = new Foo(38); | |
309 expect(x.a, equals(42)); | |
310 expect(y.a, equals(38)); | |
311 js.retain(y); | |
312 }); | |
313 js.scoped(() { | |
314 expect(() => x.a, throws); | |
315 expect(y.a, equals(38)); | |
316 js.release(y); | |
317 expect(() => y.a, throws); | |
318 }); | |
319 }); | |
320 | |
321 test('retain and release in the same scope', () { | |
322 var x; | |
323 js.scoped(() { | |
324 x = new js.Proxy(js.context.Foo, 42); | |
325 expect(x.a, equals(42)); | |
326 js.retain(x); | |
327 expect(x.a, equals(42)); | |
328 js.release(x); | |
329 expect(() => x.a, throws); | |
330 }); | |
331 js.scoped(() { | |
332 expect(() => x.a, throws); | |
333 }); | |
334 }); | |
335 | |
336 test('retain and release a function', () { | |
337 var razzle; | |
338 js.scoped(() { | |
339 razzle = js.retain(js.context.razzle); | |
340 }); | |
341 js.scoped(() { | |
342 expect(razzle(), 42); | |
343 js.release(razzle); | |
344 expect(() => razzle(), throws); | |
345 }); | |
346 }); | |
347 | |
348 test('pass unattached Dom Element', () { | |
349 final div = new DivElement(); | |
350 div.classes.add('a'); | |
351 expect(js.context.getElementAttribute(div, 'class'), equals('a')); | |
352 }); | |
353 | |
354 test('pass unattached Dom Element two times on same call', () { | |
355 final div = new DivElement(); | |
356 div.classes.add('a'); | |
357 expect(js.context.addClassAttributes(js.array([div, div])), equals('aa')); | |
358 }); | |
359 | |
360 test('pass Dom Element attached to an unattached element', () { | |
361 final div = new DivElement(); | |
362 div.classes.add('a'); | |
363 final container = new DivElement(); | |
364 container.children.add(div); | |
365 expect(js.context.getElementAttribute(div, 'class'), equals('a')); | |
366 }); | |
367 | |
368 test('pass 2 Dom Elements attached to an unattached element', () { | |
369 final div1 = new DivElement(); | |
370 div1.classes.add('a'); | |
371 final div2 = new DivElement(); | |
372 div2.classes.add('b'); | |
373 final container = new DivElement(); | |
374 container.children.add(div1); | |
375 container.children.add(div2); | |
376 final f = js.context.addClassAttributes; | |
377 expect(f(js.array([div1, div2])), equals('ab')); | |
378 }); | |
379 | |
380 test('pass multiple Dom Elements unattached to document', () { | |
381 // A is alone | |
382 // 1 and 3 are brother | |
383 // 2 is child of 3 | |
384 final divA = new DivElement()..classes.add('A'); | |
385 final div1 = new DivElement()..classes.add('1'); | |
386 final div2 = new DivElement()..classes.add('2'); | |
387 final div3 = new DivElement()..classes.add('3')..children.add(div2); | |
388 final container = new DivElement()..children.addAll([div1, div3]); | |
389 final f = js.context.addClassAttributes; | |
390 expect(f(js.array([divA, div1, div2, div3])), equals('A123')); | |
391 expect(f(js.array([divA, div1, div3, div2])), equals('A132')); | |
392 expect(f(js.array([divA, div1, div1, div3, divA, div2, div3])), | |
393 equals('A113A23')); | |
394 expect(!document.documentElement.contains(divA), isTrue); | |
395 expect(!document.documentElement.contains(div1), isTrue); | |
396 expect(!document.documentElement.contains(div2), isTrue); | |
397 expect(!document.documentElement.contains(div3), isTrue); | |
398 expect(!document.documentElement.contains(container), isTrue); | |
399 }); | |
400 | |
401 test('pass one Dom Elements unattached and another attached', () { | |
402 final div1 = new DivElement()..classes.add('1'); | |
403 final div2 = new DivElement()..classes.add('2'); | |
404 document.documentElement.children.add(div2); | |
405 final f = js.context.addClassAttributes; | |
406 expect(f(js.array([div1, div2])), equals('12')); | |
407 expect(!document.documentElement.contains(div1), isTrue); | |
408 expect(document.documentElement.contains(div2), isTrue); | |
409 }); | |
410 | |
411 test('pass documentElement', () { | |
412 expect(js.context.returnElement(document.documentElement), | |
413 equals(document.documentElement)); | |
414 }); | |
415 | |
416 test('retrieve unattached Dom Element', () { | |
417 var result = js.context.getNewDivElement(); | |
418 expect(result is DivElement, isTrue); | |
419 expect(!document.documentElement.contains(result), isTrue); | |
420 }); | |
421 | |
422 test('element of foreign document should not be serialized', () { | |
423 final foreignDoc = js.context.foreignDoc; | |
424 final root = foreignDoc.documentElement; | |
425 expect(root is js.Proxy, isTrue); | |
426 final element = root.firstChild; | |
427 expect(element is js.Proxy, isTrue); | |
428 expect(element.getAttribute('id'), equals('abc')); | |
429 }); | |
430 | |
431 test('return a JS proxy to JavaScript', () { | |
432 var result = js.context.testJsMap( | |
433 new js.Callback.once(() => js.map({ 'value': 42 }))); | |
434 expect(result, 42); | |
435 }); | |
436 | |
437 test('dispose a callback', () { | |
438 var x = 0; | |
439 final callback = new js.Callback.many(() => x++); | |
440 js.context.callback = callback; | |
441 expect(js.context.invokeCallback(), equals(0)); | |
442 expect(js.context.invokeCallback(), equals(1)); | |
443 callback.dispose(); | |
444 expect(() => js.context.invokeCallback(), throws); | |
445 }); | |
446 | |
447 test('test proxy equality', () { | |
448 var foo1 = new js.Proxy(js.context.Foo, 1); | |
449 var foo2 = new js.Proxy(js.context.Foo, 2); | |
450 js.context.foo = foo1; | |
451 js.context.foo = foo2; | |
452 expect(foo1, isNot(equals(js.context.foo))); | |
453 expect(foo2, equals(js.context.foo)); | |
454 }); | |
455 | |
456 test('test instanceof', () { | |
457 var foo = new js.Proxy(js.context.Foo, 1); | |
458 expect(js.instanceof(foo, js.context.Foo), isTrue); | |
459 expect(js.instanceof(foo, js.context.Object), isTrue); | |
460 expect(js.instanceof(foo, js.context.String), isFalse); | |
461 }); | |
462 | |
463 test('test hasProperty', () { | |
464 var object = js.map({}); | |
465 object.a = 1; | |
466 expect(js.hasProperty(object, "a"), isTrue); | |
467 expect(js.hasProperty(object, "b"), isFalse); | |
468 }); | |
469 | |
470 test('test deleteProperty', () { | |
471 var object = js.map({}); | |
472 object.a = 1; | |
473 expect(js.context.Object.keys(object).length, 1); | |
474 expect(js.context.Object.keys(object)[0], "a"); | |
475 js.deleteProperty(object, "a"); | |
476 expect(js.context.Object.keys(object).length, 0); | |
477 }); | |
478 | |
479 test('test index get and set', () { | |
480 final myArray = js.context.myArray; | |
481 expect(myArray.length, equals(1)); | |
482 expect(myArray[0], equals("value1")); | |
483 myArray[0] = "value2"; | |
484 expect(myArray.length, equals(1)); | |
485 expect(myArray[0], equals("value2")); | |
486 | |
487 final foo = new js.Proxy(js.context.Foo, 1); | |
488 foo["getAge"] = new js.Callback.once(() => 10); | |
489 expect(foo.getAge(), equals(10)); | |
490 }); | |
491 | |
492 test('test experimental apis', () { | |
493 var depth = js.$experimentalEnterScope(); | |
494 expect(js.context.x, equals(42)); | |
495 js.$experimentalExitScope(depth); | |
496 }); | |
497 | |
498 test('access a property of a function', () { | |
499 expect(js.context.Bar(), "ret_value"); | |
500 expect(js.context.Bar.foo, "property_value"); | |
501 }); | |
502 | |
503 test('retrieve same dart Object', () { | |
504 final date = new DateTime.now(); | |
505 js.context.dartDate = date; | |
506 expect(js.context.dartDate, equals(date)); | |
507 }); | |
508 | |
509 test('usage of Serializable', () { | |
510 final red = Color.RED; | |
511 js.context.color = red; | |
512 expect(js.context.color, equals(red._value)); | |
513 }); | |
514 | |
515 test('check for leaks', () { | |
516 // Verify that the number of live objects is zero. | |
517 final verifyNoLeaks = expectAsync0(() => expect(0, js.proxyCount())); | |
518 // Run this check asychnronously to ensure that any current scope is | |
519 // cleared first. | |
520 scheduleMicrotask(verifyNoLeaks); | |
521 }); | |
522 } | |
OLD | NEW |