Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests do not finish or hangs when asserting window - structuredClone errors #2802

Open
josephsintum opened this issue Sep 5, 2024 · 4 comments

Comments

@josephsintum
Copy link

When asserting with and object that contains or reference the window, the test never finish and in the browser it show a structuredClone error in the test framework
Here's a test case

import { expect } from '@esm-bundle/chai';

describe('suite', function () {
    it('window test', () => {
        let cloneWindow = window.Window;
        expect(cloneWindow).to.be.a('object');
    });
});

The test finishes but gets stuck, in the CLI, there are no errors but in the browser, you can see this error message DataCloneError: Failed to execute 'structuredClone' on 'Window': function Window() { [native code] } could not be cloned. at stable (__web-dev-server__web-socket.js:23:24)

Screenshot 2024-09-05 at 11 02 38
@lucaelin
Copy link
Contributor

lucaelin commented Sep 6, 2024

This is related to #2728 and #2731 , maybe some check is required for special cases like window, document and such or the other way around?

@denilsonsa
Copy link

denilsonsa commented Sep 10, 2024

I'm getting the same error, but with a slightly different error message:

DOMException: Failed to execute 'structuredClone' on 'Window': function proxy(a, b) {
                return p.invoke(func, this, slice(arguments));
            } could not be cloned.

A quick and dirty pseudo-solution:

--- node_modules/@web/dev-server-core/dist/web-sockets/webSocketsPlugin.js.bak	2024-09-10 13:52:55
+++ node_modules/@web/dev-server-core/dist/web-sockets/webSocketsPlugin.js	2024-09-10 13:48:32
@@ -38,7 +38,12 @@
         }

         export function stable (obj, replacer, spacer) {
-          var target = structuredClone(obj)
+          var target;
+          try {
+            target = structuredClone(obj)
+          } catch (e) {
+            target = obj;
+          }
           var tmp = deterministicDecirc(target, '', [], undefined) || target
           var res
           if (replacerStack.length === 0) {

This isn't production code, but at least it lets my tests report correctly, which is much better than waiting for two minutes for a random timeout on a test code that can't timeout.

As a side note, I see the upstream code has been updated over time. The function name stable has been replaced 6½ years ago.

@laino
Copy link

laino commented Sep 16, 2024

The Workaround

Before getting into an explanation of the problem, here's a workaround:

  1. Install @ungap/structured-clone
  2. Add this to your config:
export default {
    // ...
    testRunnerHtml(testFramework) {                                                                         
        return `<html><body><script type="module">import structuredClone from '@ungap/structured-clone';window.structuredClone = (value) => structuredClone(value, { lossy: true });</script><script type="module" src="${testFramework}"></script></body></html>`;    
    },          
   // ...                                                                                            
}

That replaces the browser's built-in structuredClone algorithm with a polyfill that is more forgiving.

Just be aware the diffs shown could be incomplete:

image

Here the function instances differed, but get replaced by undefined before the diff was shown. Better than nothing though.

The Problem

The root cause appears to be that Chai's AssertionError has an actual property, which contains the actual object differing from the expected one. This AssertionError (or a shallow copy) is in the data structure that we attempt to clone and serialize:

swappy-20240916_083339

Obviously this is going to go badly if there's anything in there that can't be cloned/serialized. I believe this is the place creating the error object in that structure:

At the end of the day there's no good and easy way out of this, since afaik those properties are used to calculate diffs on the server side, and thus must be sent for that work. Fixing this either requires calculating diffs client-side, or coming up a with a representation of expected/actual objects which cleanly serialize and can be used to calculate diffs without reducing their quality.

@lucaelin
Copy link
Contributor

I think this is a duplicate of #2772 which I was made aware of

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants