Skip to content

Commit 46c5275

Browse files
authored
#3180. Add tests for JS interop type constructors (#3272)
Add tests for JS interop type constructors
1 parent e511ead commit 46c5275

File tree

7 files changed

+389
-0
lines changed

7 files changed

+389
-0
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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`.
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+
external ET.fromId(int id);
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+
external factory ET2.fromId(int id);
32+
33+
external int get id;
34+
external String? get name;
35+
}
36+
37+
main() {
38+
eval(r'''
39+
class ET {
40+
constructor(id, name) {
41+
this._id = id;
42+
this._name = name;
43+
}
44+
get id() {
45+
return this._id;
46+
}
47+
get name() {
48+
return this._name;
49+
}
50+
}
51+
globalThis.ET = ET;
52+
''');
53+
ET et1 = ET(1, "one");
54+
Expect.equals(1, et1.id);
55+
Expect.equals("one", et1.name);
56+
57+
ET et2 = ET.fromId(2);
58+
Expect.equals(2, et2.id);
59+
Expect.isNull(et2.name);
60+
61+
ET2 et3 = ET2(3, "three");
62+
Expect.equals(3, et3.id);
63+
Expect.equals("three", et3.name);
64+
65+
ET2 et4 = ET2.fromId(4);
66+
Expect.equals(4, et4.id);
67+
Expect.isNull(et4.name);
68+
}
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+
/// - 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 the case when excessive
14+
/// positional parameter is ignored by JS.
15+
/// @author [email protected]
16+
17+
import 'dart:js_interop';
18+
import '../../Utils/expect.dart';
19+
import 'js_utils.dart';
20+
21+
extension type ET._(JSObject _) implements JSObject {
22+
external ET.withDescription(int id, String? name, String description);
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 ET2.withDescription(int id, String? name, String description);
31+
32+
external int get id;
33+
external String? get name;
34+
}
35+
36+
main() {
37+
eval(r'''
38+
class ET {
39+
constructor(id, name) {
40+
this._id = id;
41+
this._name = name;
42+
}
43+
get id() {
44+
return this._id;
45+
}
46+
get name() {
47+
return this._name;
48+
}
49+
}
50+
globalThis.ET = ET;
51+
''');
52+
53+
ET et1 = ET.withDescription(1, "one", "Description");
54+
Expect.equals(1, et1.id);
55+
Expect.equals("one", et1.name);
56+
57+
ET2 et2 = ET2.withDescription(2, "two", "Description");
58+
Expect.equals(2, et2.id);
59+
Expect.equals("two", et2.name);
60+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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 constructor of a JS
12+
/// interop type has no parameters.
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 ET.empty();
21+
external int? get id;
22+
external String? get name;
23+
}
24+
25+
main() {
26+
eval(r'''
27+
class ET {
28+
constructor(id, name) {
29+
if (id == null) {
30+
this._id = 0;
31+
} else {
32+
this._id = id;
33+
}
34+
this._name = name;
35+
}
36+
get id() {
37+
return this._id;
38+
}
39+
get name() {
40+
return this._name;
41+
}
42+
}
43+
globalThis.ET = ET;
44+
''');
45+
46+
ET et1 = ET.empty();
47+
Expect.equals(0, et1.id);
48+
Expect.isNull(et1.name);
49+
50+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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 a compile-time error if a constructor of a
12+
/// JS interop type contains both named and positional parameters.
13+
/// @author [email protected]
14+
15+
import 'dart:js_interop';
16+
17+
extension type ET1._(JSObject _) implements JSObject {
18+
external ET1.withDescription(int id, String? name, {String description});
19+
// ^^
20+
// [analyzer] unspecified
21+
// [web] unspecified
22+
}
23+
24+
extension type ET2._(JSObject _) implements JSObject {
25+
external factory ET2(int id, String? name, {String description});
26+
// ^^
27+
// [analyzer] unspecified
28+
// [web] unspecified
29+
}
30+
31+
main() {
32+
print(ET1);
33+
print(ET2);
34+
}
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+
/// - 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 invoking a constructor of a JS interop type creates
12+
/// a new JS object.
13+
/// @author [email protected]
14+
15+
import 'dart:js_interop';
16+
import 'dart:js_interop_unsafe';
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+
23+
external int get id;
24+
external String? get name;
25+
}
26+
27+
@JS("ET")
28+
extension type ET2._(JSObject _) implements JSObject {
29+
external factory ET2(int id, String? name);
30+
31+
external int get id;
32+
external String? get name;
33+
}
34+
35+
main() {
36+
eval(r'''
37+
class ET {
38+
constructor(id, name) {
39+
this._id = id;
40+
this._name = name;
41+
}
42+
get id() {
43+
return this._id;
44+
}
45+
get name() {
46+
return this._name;
47+
}
48+
}
49+
globalThis.ET = ET;
50+
''');
51+
globalContext["et1"] = ET(1, "one");
52+
globalContext["et2"] = ET(1, "one");
53+
eval("globalThis.res1 = globalThis.et1 == globalThis.et2;");
54+
Expect.isFalse((globalContext["res1"] as JSBoolean).toDart);
55+
56+
globalContext["et3"] = ET2(2, "two");
57+
globalContext["et4"] = ET2(2, "two");
58+
eval("globalThis.res2 = globalThis.et3 == globalThis.et4;");
59+
Expect.isFalse((globalContext["res2"] as JSBoolean).toDart);
60+
}
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.
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+
external ET1.fromId({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({int id, String? name});
33+
external factory ET2.fromId({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: 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+
/// ...
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 invoking a constructor of a JS interop type creates
14+
/// a new JS object.
15+
/// @author [email protected]
16+
17+
import 'dart:js_interop';
18+
import 'dart:js_interop_unsafe';
19+
import '../../Utils/expect.dart';
20+
import 'js_utils.dart';
21+
22+
extension type ET1._(JSObject _) implements JSObject {
23+
external ET1({int id, String? name});
24+
25+
external int get id;
26+
external String? get name;
27+
}
28+
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+
globalContext["et1"] = ET1(id: 1, name: "one");
38+
globalContext["et2"] = ET1(id: 1, name: "one");
39+
eval("globalThis.res1 = globalThis.et1 == globalThis.et2;");
40+
Expect.isFalse((globalContext["res1"] as JSBoolean).toDart);
41+
42+
globalContext["et3"] = ET2(id: 2, name: "two");
43+
globalContext["et4"] = ET2(id: 2, name: "two");
44+
eval("globalThis.res2 = globalThis.et3 == globalThis.et4;");
45+
Expect.isFalse((globalContext["res2"] as JSBoolean).toDart);
46+
}

0 commit comments

Comments
 (0)