[dart:js_interop] Add tests for extension type factories

Extension type factories are added to the language, so they
should be tested. Also fixes a small issue on detecting
tear-offs.

Change-Id: I8d2b374830e4ac11783d10d3b75221544ee9ef3d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/318160
Commit-Queue: Srujan Gaddam <srujzs@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/_js_interop_checks/lib/js_interop_checks.dart b/pkg/_js_interop_checks/lib/js_interop_checks.dart
index 3e5e594..ad2cfb7 100644
--- a/pkg/_js_interop_checks/lib/js_interop_checks.dart
+++ b/pkg/_js_interop_checks/lib/js_interop_checks.dart
@@ -658,8 +658,7 @@
   ///
   /// Tear-offs of the following are disallowed when using dart:js_interop:
   ///
-  /// - External extension type constructors and factories (TODO(srujzs): Add
-  /// checks for factories once they're added.)
+  /// - External extension type constructors and factories
   /// - External factories of @staticInterop classes
   /// - External interop extension type methods
   /// - External interop extension methods on @staticInterop or extension types
diff --git a/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart b/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart
index eaa085f..57c9444 100644
--- a/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart
+++ b/pkg/_js_interop_checks/lib/src/transformations/js_util_optimizer.dart
@@ -851,6 +851,7 @@
           _extensionTypeIndex[reference] = extensionType;
           if (descriptor.kind == ExtensionTypeMemberKind.Method ||
               descriptor.kind == ExtensionTypeMemberKind.Constructor ||
+              descriptor.kind == ExtensionTypeMemberKind.Factory ||
               descriptor.kind == ExtensionTypeMemberKind.TearOff) {
             final descriptorName = descriptor.name.text;
             if (descriptorNames.containsKey(descriptorName)) {
diff --git a/tests/lib/js/static_interop_test/disallowed_tearoffs_static_test.dart b/tests/lib/js/static_interop_test/disallowed_tearoffs_static_test.dart
index 6342e45..c1f8f14 100644
--- a/tests/lib/js/static_interop_test/disallowed_tearoffs_static_test.dart
+++ b/tests/lib/js/static_interop_test/disallowed_tearoffs_static_test.dart
@@ -14,10 +14,9 @@
   external ExtensionType();
   external ExtensionType.named();
   external ExtensionType.literal({JSNumber? a});
-  // TODO(srujzs): Once we have extension type factories, test these.
-  // external factory ExtensionType.fact();
-  // external factory ExtensionType.literalFact({JSNumber? a});
-  // factory ExtensionType.nonExternalFact() => ExtensionType();
+  external factory ExtensionType.fact();
+  external factory ExtensionType.literalFact({JSNumber? a});
+  factory ExtensionType.nonExternalFact() => ExtensionType();
 
   external static void externalStatic();
   static void nonExternalStatic() {}
@@ -110,11 +109,16 @@
 //^
 // [web] Tear-offs of external extension type interop member 'new' are disallowed.
 
-  // TODO(srujzs): Once we have factories available, test these.
-  // ExtensionType.fact;
-  // ExtensionType.literalFact;
-  // ExtensionType.nonExternalFact;
-  // const [ExtensionType.fact];
+  ExtensionType.fact;
+//^
+// [web] Tear-offs of external extension type interop member 'fact' are disallowed.
+  ExtensionType.literalFact;
+//^
+// [web] Tear-offs of external extension type interop member 'literalFact' are disallowed.
+  ExtensionType.nonExternalFact;
+  const [ExtensionType.fact];
+//^
+// [web] Tear-offs of external extension type interop member 'fact' are disallowed.
 
   StaticInterop.new;
 //^
diff --git a/tests/lib/js/static_interop_test/inline_class/external_static_member_test.dart b/tests/lib/js/static_interop_test/inline_class/external_static_member_test.dart
index 51a2a5b..d598c4f 100644
--- a/tests/lib/js/static_interop_test/inline_class/external_static_member_test.dart
+++ b/tests/lib/js/static_interop_test/inline_class/external_static_member_test.dart
@@ -18,9 +18,7 @@
 @JS()
 extension type ExternalStatic._(JSObject obj) {
   external ExternalStatic();
-  // TODO(srujzs): Uncomment the external factory test once the CFE supports
-  // them.
-  // external factory ExternalStatic.factory();
+  external factory ExternalStatic.factory();
   external ExternalStatic.multipleArgs(double a, String b);
   external ExternalStatic.differentArgs(double a, [String b = '']);
   ExternalStatic.nonExternal() : this.obj = ExternalStatic() as JSObject;
@@ -68,7 +66,7 @@
   }
 
   testExternalConstructorCall(ExternalStatic());
-  // testExternalConstructorCall(ExternalStatic.factory());
+  testExternalConstructorCall(ExternalStatic.factory());
   testExternalConstructorCall(ExternalStatic.multipleArgs(0, ''));
   testExternalConstructorCall(ExternalStatic.differentArgs(0));
   testExternalConstructorCall(ExternalStatic.nonExternal());
diff --git a/tests/lib/js/static_interop_test/inline_class/external_static_member_with_namespaces_test.dart b/tests/lib/js/static_interop_test/inline_class/external_static_member_with_namespaces_test.dart
index 945c04e..e37379c 100644
--- a/tests/lib/js/static_interop_test/inline_class/external_static_member_with_namespaces_test.dart
+++ b/tests/lib/js/static_interop_test/inline_class/external_static_member_with_namespaces_test.dart
@@ -18,9 +18,7 @@
 @JS('library3.ExternalStatic')
 extension type ExternalStatic._(JSObject obj) {
   external ExternalStatic();
-  // TODO(srujzs): Uncomment the external factory test once the CFE supports
-  // them.
-  // external factory ExternalStatic.factory();
+  external factory ExternalStatic.factory();
   external ExternalStatic.multipleArgs(double a, String b);
   external ExternalStatic.differentArgs(double a, [String b = '']);
   ExternalStatic.nonExternal() : this.obj = ExternalStatic() as JSObject;
@@ -77,7 +75,7 @@
   }
 
   testExternalConstructorCall(ExternalStatic());
-  // testExternalConstructorCall(ExternalStatic.factory());
+  testExternalConstructorCall(ExternalStatic.factory());
   testExternalConstructorCall(ExternalStatic.multipleArgs(0, ''));
   testExternalConstructorCall(ExternalStatic.differentArgs(0));
   testExternalConstructorCall(ExternalStatic.nonExternal());
diff --git a/tests/lib/js/static_interop_test/inline_class/object_literal_constructor_test.dart b/tests/lib/js/static_interop_test/inline_class/object_literal_constructor_test.dart
index 547c8f5..f44f44c 100644
--- a/tests/lib/js/static_interop_test/inline_class/object_literal_constructor_test.dart
+++ b/tests/lib/js/static_interop_test/inline_class/object_literal_constructor_test.dart
@@ -15,6 +15,7 @@
 @JS()
 extension type Literal._(JSObject _) {
   external Literal({double? a, String b, bool? c});
+  external factory Literal.fact({double? a, String b, bool? c});
 }
 
 @JS('Object.keys')
@@ -41,17 +42,17 @@
   }
 
   testProperties(Literal());
-  testProperties(Literal(a: 0.0), a: 0.0);
+  testProperties(Literal.fact(a: 0.0), a: 0.0);
   testProperties(Literal(b: ''), b: '');
-  testProperties(Literal(c: true), c: true);
+  testProperties(Literal.fact(c: true), c: true);
 
   testProperties(Literal(a: 0.0, b: ''), a: 0.0, b: '');
-  testProperties(Literal(a: 0.0, c: true), a: 0.0, c: true);
+  testProperties(Literal.fact(a: 0.0, c: true), a: 0.0, c: true);
   testProperties(Literal(b: '', c: true), b: '', c: true);
 
-  testProperties(Literal(a: 0.0, b: '', c: true), a: 0.0, b: '', c: true);
+  testProperties(Literal.fact(a: 0.0, b: '', c: true), a: 0.0, b: '', c: true);
   // Re-run with the same shape for dart2wasm optimization check.
   testProperties(Literal(a: 0.0, b: '', c: true), a: 0.0, b: '', c: true);
   // Test that passing in a different order doesn't change the values.
-  testProperties(Literal(c: true, a: 0.0, b: ''), a: 0.0, b: '', c: true);
+  testProperties(Literal.fact(c: true, a: 0.0, b: ''), a: 0.0, b: '', c: true);
 }