Skip to content

Commit f589cfa

Browse files
authored
#3180. Add more tests for JS interop (#3273)
Add more tests for JS interop
1 parent 46c5275 commit f589cfa

12 files changed

+723
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright (c) 2025, 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+
/// @assertion Within an interop type, you can declare several different types
6+
/// of external interop members:
7+
/// - Constructors. When called, constructors with only positional parameters
8+
/// create a new JS object whose constructor is defined by the name of the
9+
/// extension type using `new`.
10+
///
11+
/// @description Check that a constructor of a JS interop type with positional
12+
/// parameters when called creates a new JS object whose constructor is defined
13+
/// by the name of the extension type using `new`. Test redirecting constructor.
14+
/// @author [email protected]
15+
16+
import 'dart:js_interop';
17+
import '../../Utils/expect.dart';
18+
import 'js_utils.dart';
19+
20+
extension type ET._(JSObject _) implements JSObject {
21+
external ET(int id, String? name);
22+
ET.fromId(int id) : this(id, "default");
23+
24+
external int get id;
25+
external String? get name;
26+
}
27+
28+
@JS("ET")
29+
extension type ET2._(JSObject _) implements JSObject {
30+
external factory ET2(int id, String? name);
31+
factory ET2.f(int id) => ET2(id, "default");
32+
factory ET2.fromId(int id) = ET2.f;
33+
34+
external int get id;
35+
external String? get name;
36+
}
37+
38+
main() {
39+
eval(r'''
40+
class ET {
41+
constructor(id, name) {
42+
this._id = id;
43+
this._name = name;
44+
}
45+
get id() {
46+
return this._id;
47+
}
48+
get name() {
49+
return this._name;
50+
}
51+
}
52+
globalThis.ET = ET;
53+
''');
54+
55+
ET et1 = ET.fromId(1);
56+
Expect.equals(1, et1.id);
57+
Expect.equals("default", et1.name);
58+
59+
ET2 et2 = ET2.f(2);
60+
Expect.equals(2, et2.id);
61+
Expect.equals("default", et2.name);
62+
63+
ET2 et3 = ET2.fromId(3);
64+
Expect.equals(3, et3.id);
65+
Expect.equals("default", et3.name);
66+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) 2025, 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+
/// @assertion Within an interop type, you can declare several different types
6+
/// of external interop members:
7+
/// - Constructors. When called, constructors with only positional parameters
8+
/// create a new JS object whose constructor is defined by the name of the
9+
/// extension type using `new`.
10+
///
11+
/// @description Check that a primary constructor of a JS interop type is not
12+
/// external and therefore its invocation does not call a JS constructor.
13+
/// @author [email protected]
14+
15+
import 'dart:js_interop';
16+
import '../../Utils/expect.dart';
17+
import 'js_utils.dart';
18+
19+
extension type ET(JSAny v) implements JSAny {
20+
external ET.create(int id, String? name);
21+
22+
external int? get id;
23+
external String? get name;
24+
}
25+
26+
main() {
27+
eval(r'''
28+
class ET {
29+
constructor(id, name) {
30+
this._id = id;
31+
this._name = name;
32+
}
33+
get id() {
34+
return this._id;
35+
}
36+
get name() {
37+
return this._name;
38+
}
39+
}
40+
globalThis.ET = ET;
41+
''');
42+
43+
ET et1 = ET(42.toJS);
44+
Expect.isNull(et1.id);
45+
Expect.isNull(et1.name);
46+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (c) 2025, 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+
/// @assertion Within an interop type, you can declare several different types
6+
/// of external interop members:
7+
/// - Constructors. When called, constructors with only positional parameters
8+
/// create a new JS object whose constructor is defined by the name of the
9+
/// extension type using `new`.
10+
///
11+
/// @description Check that it is not an error if a JS interop type declares a
12+
/// constructor but the appropriate interop object in JS doesn't declare a
13+
/// constructor.
14+
/// @author [email protected]
15+
16+
import 'dart:js_interop';
17+
import 'dart:js_interop_unsafe';
18+
import '../../Utils/expect.dart';
19+
import 'js_utils.dart';
20+
21+
extension type ET._(JSObject _) implements JSObject {
22+
external ET(int id, String? name);
23+
24+
external int? get id;
25+
external String? get name;
26+
}
27+
28+
@JS("ET")
29+
extension type ET2._(JSObject _) implements JSObject {
30+
external factory ET2(int id, String? name);
31+
32+
external int? get id;
33+
external String? get name;
34+
}
35+
36+
main() {
37+
eval(r'''
38+
class ET {}
39+
globalThis.ET = ET;
40+
''');
41+
ET et1 = ET(1, "one");
42+
Expect.isNull(et1.id);
43+
Expect.isNull(et1.name);
44+
globalContext["et1"] = et1;
45+
Expect.isNotNull(globalContext["et1"]);
46+
47+
ET2 et2 = ET2(2, "two");
48+
Expect.isNull(et2.id);
49+
Expect.isNull(et2.name);
50+
globalContext["et2"] = et2;
51+
Expect.isNotNull(globalContext["et2"]);
52+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) 2025, 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+
/// @assertion Within an interop type, you can declare several different types
6+
/// of external interop members:
7+
/// ...
8+
/// - Object literal constructors. It's sometimes useful to create a JS object
9+
/// literal that simply contains a number of properties and their values. In
10+
/// order to do this, declare a constructor with only named parameters, where
11+
/// the names of the parameters match the property names.
12+
///
13+
/// @description Check that a constructor of a JS interop type with named
14+
/// parameters creates a new JS object with all properties defined by the
15+
/// constructor. Test required named parameters.
16+
/// @author [email protected]
17+
18+
import 'dart:js_interop';
19+
import 'dart:js_interop_unsafe';
20+
import '../../Utils/expect.dart';
21+
import 'js_utils.dart';
22+
23+
extension type ET1._(JSObject _) implements JSObject {
24+
external ET1({required int id, required String? name});
25+
external ET1.fromId({required int id});
26+
27+
external int get id;
28+
external String? get name;
29+
}
30+
31+
extension type ET2._(JSObject _) implements JSObject {
32+
external factory ET2({required int id, required String? name});
33+
external factory ET2.fromId({required int id});
34+
35+
external int get id;
36+
external String? get name;
37+
}
38+
39+
main() {
40+
globalContext["et1"] = ET1(id: 1, name: "one");
41+
eval(r'''
42+
globalThis.v1 = globalThis.et1.id;
43+
globalThis.v2 = globalThis.et1.name;
44+
''');
45+
Expect.equals(1, (globalContext["v1"] as JSNumber).toDartInt);
46+
Expect.equals("one", (globalContext["v2"] as JSString).toDart);
47+
48+
globalContext["et2"] = ET1.fromId(id: 2);
49+
eval(r'''
50+
globalThis.v3 = globalThis.et2.id;
51+
globalThis.v4 = globalThis.et2.name;
52+
''');
53+
Expect.equals(2, (globalContext["v3"] as JSNumber).toDartInt);
54+
Expect.isNull(globalContext["v4"]);
55+
56+
globalContext["et3"] = ET2(id: 3, name: "three");
57+
eval(r'''
58+
globalThis.v5 = globalThis.et3.id;
59+
globalThis.v6 = globalThis.et3.name;
60+
''');
61+
Expect.equals(3, (globalContext["v5"] as JSNumber).toDartInt);
62+
Expect.equals("three", (globalContext["v6"] as JSString).toDart);
63+
64+
globalContext["et4"] = ET2.fromId(id: 4);
65+
eval(r'''
66+
globalThis.v7 = globalThis.et4.id;
67+
globalThis.v8 = globalThis.et4.name;
68+
''');
69+
Expect.equals(4, (globalContext["v7"] as JSNumber).toDartInt);
70+
Expect.isNull(globalContext["v8"]);
71+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) 2025, 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+
/// @assertion Within an interop type, you can declare several different types
6+
/// of external interop members:
7+
/// ...
8+
/// - Object literal constructors. It's sometimes useful to create a JS object
9+
/// literal that simply contains a number of properties and their values. In
10+
/// order to do this, declare a constructor with only named parameters, where
11+
/// the names of the parameters match the property names.
12+
///
13+
/// @description Check that a constructor of a JS interop type with named
14+
/// parameters creates a new JS object with all properties defined by the
15+
/// constructor. Test redirecting constructors.
16+
/// @author [email protected]
17+
18+
import 'dart:js_interop';
19+
import 'dart:js_interop_unsafe';
20+
import '../../Utils/expect.dart';
21+
import 'js_utils.dart';
22+
23+
extension type ET1._(JSObject _) implements JSObject {
24+
external ET1({int id, String? name});
25+
ET1.fromId({int id = 0}) : this(id: id, name: "default");
26+
27+
external int get id;
28+
external String? get name;
29+
}
30+
31+
extension type ET2._(JSObject _) implements JSObject {
32+
external factory ET2({int id, String? name});
33+
factory ET2.f({int id = 0}) => ET2(id: id, name: "default");
34+
factory ET2.fromId({int id}) = ET2.f;
35+
36+
external int get id;
37+
external String? get name;
38+
}
39+
40+
main() {
41+
globalContext["et1"] = ET1.fromId(id: 1);
42+
eval(r'''
43+
globalThis.v1 = globalThis.et1.id;
44+
globalThis.v2 = globalThis.et1.name;
45+
''');
46+
Expect.equals(1, (globalContext["v1"] as JSNumber).toDartInt);
47+
Expect.equals("default", (globalContext["v2"] as JSString).toDart);
48+
49+
globalContext["et2"] = ET2.f(id: 2);
50+
eval(r'''
51+
globalThis.v3 = globalThis.et2.id;
52+
globalThis.v4 = globalThis.et2.name;
53+
''');
54+
Expect.equals(2, (globalContext["v3"] as JSNumber).toDartInt);
55+
Expect.equals("default", (globalContext["v4"] as JSString).toDart);
56+
57+
globalContext["et3"] = ET2.fromId(id: 3);
58+
eval(r'''
59+
globalThis.v5 = globalThis.et3.id;
60+
globalThis.v6 = globalThis.et3.name;
61+
''');
62+
Expect.equals(3, (globalContext["v5"] as JSNumber).toDartInt);
63+
Expect.equals("default", (globalContext["v6"] as JSString).toDart);
64+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) 2025, 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+
/// @assertion Within an interop type, you can declare several different types
6+
/// of external interop members:
7+
/// ...
8+
/// - static members. Like constructors, static members use the name of the
9+
/// extension type to generate the JS code.
10+
///
11+
/// @description Check that static members use the name of the extension type to
12+
/// generate the JS code.
13+
/// @author [email protected]
14+
15+
import 'dart:js_interop';
16+
import '../../Utils/expect.dart';
17+
import 'js_utils.dart';
18+
19+
extension type ET._(JSObject _) implements JSObject {
20+
external static int variable;
21+
external static int get getter;
22+
external static String method();
23+
external static void set setter(int value);
24+
}
25+
26+
@JS("ET")
27+
extension type ET2._(JSObject _) implements JSObject {
28+
external static int variable;
29+
external static int get getter;
30+
external static String method();
31+
external static void set setter(int value);
32+
}
33+
34+
main() {
35+
eval(r'''
36+
class ET {
37+
static variable = 42;
38+
static get getter() {
39+
return ET.variable;
40+
}
41+
static method() {
42+
return "static method";
43+
}
44+
static set setter(value) {
45+
ET.variable = value;
46+
}
47+
}
48+
globalThis.ET = ET;
49+
''');
50+
51+
Expect.equals(42, ET.variable);
52+
Expect.equals("static method", ET.method());
53+
ET.setter = -1;
54+
Expect.equals(-1, ET.getter);
55+
56+
Expect.equals(-1, ET2.variable);
57+
Expect.equals("static method", ET2.method());
58+
ET2.setter = 42;
59+
Expect.equals(42, ET2.getter);
60+
}

0 commit comments

Comments
 (0)