dart-lang / web

Lightweight browser API bindings built around JS static interop.
https://pub.dev/packages/web
BSD 3-Clause "New" or "Revised" License
135 stars 23 forks source link

Instance of 'EventTarget': type 'EventTarget' is not a subtype of type 'JSObject?' thrown when calling window.parent in version 0.5.1 #240

Open lijy91 opened 6 months ago

lijy91 commented 6 months ago

Error Log:

➜  example git:(main) ✗ dart test test/main_test.dart --debug
00:03 +0: loading test/main_test.dart                                                                                                                                                                                           
Hint: When run on the command-line, the compiled output might require a preamble file located in:
  <sdk>/lib/_internal/js_runtime/lib/preambles.
Compiled 12,964,524 input bytes (7,984,837 characters source) to 1,131,766 characters JavaScript in 3.31 seconds using 324.688 MB of memory

00:04 +0 -1: should render [E]                                                                                                                                                                                                  
  TypeError: Instance of 'EventTarget': type 'EventTarget' is not a subtype of type 'JSObject?'
  org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_helper.dart 1196:37   Object.wrapException
  org-dartlang-sdk:///lib/_internal/js_shared/lib/rti.dart 1385:3           Object._failedAsCheck
  org-dartlang-sdk:///lib/_internal/js_shared/lib/rti.dart 1375:3           Rti._generalNullableAsCheckImplementation
  org-dartlang-sdk:///lib/_internal/js_shared/lib/js_util_patch.dart 81:5   <fn>
  org-dartlang-sdk:///lib/_internal/js_runtime/lib/async_patch.dart 303:19  _wrapJsFunctionForAsync.closure.$protected
  org-dartlang-sdk:///lib/_internal/js_runtime/lib/async_patch.dart 328:23  _wrapJsFunctionForAsync.<fn>
  org-dartlang-sdk:///lib/_internal/js_runtime/lib/async_patch.dart 233:3   Object._asyncStartSync
  test/main_test.dart 8:20                                                  main.<fn>
  package:test_api                                                          <fn>
  org-dartlang-sdk:///lib/_internal/js_runtime/lib/async_patch.dart 303:19  _wrapJsFunctionForAsync.closure.$protected

To run this test again: /Users/lijy91/fvm/versions/3.19.6/bin/cache/dart-sdk/bin/dart test test/main_test.dart -p chrome --plain-name 'should render'
00:04 +0 -1: Some tests failed.                                                                                                                                                                                                 

Consider enabling the flag chain-stack-traces to receive more detailed exceptions.
For example, 'dart test --chain-stack-traces'.

Steps to Reproduce:

  1. Create main_test.dart file
    
    @TestOn('chrome')

import 'package:test/test.dart'; import 'package:web/web.dart';

void main() { test('should render', () async { document.body!.append(HTMLSpanElement()..text = 'Hello World!!'); print(window.parent); // An error will be thrown here expect(document.body!.children.length, 1); }); }


2. Run this test 

dart test test/main_test.dart --debug

srujzs commented 6 months ago

Hmm, this is a bit of a head-scratcher and probably related to package:test. You can repro with an even smaller example:

@TestOn('browser')
library;

import 'package:test/test.dart';
import 'package:web/web.dart';

void main() {
  test('should render', () async {
    print(window.parent);
  });
}

This same code (window.parent) succeeds when compiled directly with dart compile js. The reason why there's a cast failure is because dart2js never set up the interceptors fully. When there's a cast from window.parent to JSObject?, we check the object's interceptor. The interceptor doesn't have the $isJSObject property, because it never ran the code that set that up:

J.JavaScriptObject.prototype = {$isJSObject: 1};

This then leads to the cast failure.

It seems like we directly call the closure which contains the body of the test and never set up any of the dart2js runtime. I believe there's a postMessage somewhere to execute the test, and maybe that's not calling the right entrypoint, but I'm not too familiar with the package:test code that does this or who would know more. @jakemac53 any ideas perhaps? I've been using dart test test/smoke_test.dart --platform=chrome --pause-after-load with the test contents replaced with the above to single step through this.