blob: 5d4fc5ebfcfb89b7ccc08cc2f39de30eb7f872e8 [file] [log] [blame]
// Copyright (c) 2023, 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.
// Test the JS array proxy or reference that's created for lists for interop.
import 'dart:js_interop';
import 'package:expect/minitest.dart'; // ignore: deprecated_member_use_from_same_package
@JS()
external void eval(String code);
@JS()
external int iterateAndValidateArray(JSArray array);
@JS()
external Counter get counter;
extension type Counter(JSObject _) implements JSObject {
external int get numElements;
external JSFunction get forEachBound;
}
extension on JSArray {
external int get length;
external set length(int val);
external int operator [](int i);
external void operator []=(int i, int value);
external int at(int i);
external JSArray concat([JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4]);
external void forEach(JSFunction callback, [JSObject thisObj]);
external int indexOf(JSAny? element, [int? fromIndex]);
external bool includes(JSAny? element, [int? fromIndex]);
external String join([String? delimiter]);
external int pop();
external int push([JSAny? arg1, JSAny? arg2, JSAny? arg3]);
external JSArray slice([int? start, int? end]);
external JSArray splice(
[int? start,
int? deleteCount,
JSAny? arg1,
JSAny? arg2,
JSAny? arg3,
JSAny? arg4]);
}
void main() {
final numList = <int?>[4, 3, 2, 1, 0].map((e) => e?.toJS).toList();
final numProxy = numList.toJSProxyOrRef;
final roundTripProxy = numProxy.toDart.toJSProxyOrRef;
expect(numProxy, roundTripProxy);
// `length`/`[]`/`at`/`[]=`
numProxy.length = 6;
expect(numList.length, 6);
expect(numProxy.length, numList.length);
numList.length = 5;
expect(numProxy.length, numList.length);
for (var i = 0; i < numProxy.length; i++) {
expect(numProxy[i], numProxy.length - i - 1);
expect(numProxy.at(i), numProxy.length - i - 1);
numProxy[i] = i;
expect(numProxy[i], i);
expect(numProxy.at(i), i);
// Test negative indexing.
expect(numProxy.at(i - numProxy.length), i);
expect(numList[i]!.toDartInt, i);
}
// `includes`/`indexOf`
expect(numProxy.includes(0.toJS), true);
expect(numProxy.includes(0.toJS, 1), false);
expect(numProxy.includes(5.toJS), false);
expect(numProxy.indexOf(0.toJS), 0);
expect(numProxy.indexOf(0.toJS, 1), -1);
expect(numProxy.indexOf(5.toJS), -1);
// `pop`/`push`
expect(numProxy.push(5.toJS), numList.length);
expect(numProxy.length, numList.length);
expect(numList.length, 6);
expect(numList[5]!.toDartInt, 5);
expect(numProxy.pop(), 5);
expect(numProxy.length, numList.length);
expect(numList.length, 5);
expect(numProxy.push(5.toJS, 6.toJS, 7.toJS), 8);
expect(numProxy.push(8.toJS, null, null), 11);
expect(numList.length, 11);
numList.length = 9; // Remove the `null`s we just added.
// iteration/for loop
eval('''
globalThis.iterateAndValidateArray = function(array) {
var counter = 0;
for (const i of array) {
if (counter != i) break;
counter++;
}
return counter;
};
''');
expect(iterateAndValidateArray(numProxy), numList.length);
// `forEach`
var numElements = 0;
numProxy.forEach((int element, int index, JSArray array) {
expect(numElements, element);
expect(numElements, index);
expect(numProxy, array);
numElements++;
}.toJS);
expect(numElements, numList.length);
// `forEach` with a bound this.
eval('''
const counter = {
numElements: 0,
forEachBound: function (element, index, array) {
this.numElements++;
},
};
globalThis.counter = counter;
''');
numProxy.forEach(counter.forEachBound, counter);
expect(counter.numElements, numList.length);
// `slice`, `splice`, and `concat`
void testEquals(JSArray arr, List<int> list) {
final len = list.length;
for (var i = 0; i < len; i++) {
expect(arr[i], list[i]);
}
}
final sliced = numProxy.slice(4, 9);
testEquals(sliced, [4, 5, 6, 7, 8]);
expect(numList.length, 9);
final deleted = numProxy.splice(4, 5);
testEquals(deleted, [4, 5, 6, 7, 8]);
expect(numList.length, 4);
final deleted2 = numProxy.splice(0, 4, 3.toJS, 2.toJS, 1.toJS, 0.toJS);
testEquals(deleted2, [0, 1, 2, 3]);
testEquals(numProxy, [3, 2, 1, 0]);
testEquals(numProxy.concat(deleted2), [3, 2, 1, 0, 0, 1, 2, 3]);
// `join`
expect(numProxy.join('-'), '3-2-1-0');
expect(numProxy.join(), '3,2,1,0');
// TODO(srujzs): Test the remaining JS Array methods. While we cover the
// common ones and the ones needed for JSArrayImpl, we might be missing some
// subtleties (like `isConcatSpreadble` for example) or missing handler
// methods that are needed other Array methods.
}