modernweb-dev / web

Guides, tools and libraries for modern web development.
https://modern-web.dev
MIT License
2.2k stars 278 forks source link

Sinon Chai calledWithMatch causes structuredClone to error in the test runner #2772

Open Sanderovich opened 1 month ago

Sanderovich commented 1 month ago

See this repo for a reproduction https://github.com/Sanderovich/web-test-runner-called-with-match-error-reproduction.

When an expect(spy).to.be.calledWithMatch() is unsuccesful the expect throws an AssertionError that web test runner can not handle which causes the following exception. image

The crash seems to happen because of the actual property inside the AssertionError. The actual property is set to a function called proxy and structuredClone cannot handle functions (https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm).

A possible solution could be to JSON.stringify() and JSON.parse() the AssertionError before the structuredClone.

CendioOssman commented 1 month ago

This is blocking our (@noVNC) migration to web test runner, as we make heavy use of sinon. :/

Have you found any way to work around the issue?

Sanderovich commented 1 month ago

@CendioOssman A quick work around would be to delete the actual property from the error thrown by the expect on failure and re-throw the error so web-test-runner can handle it.

it('stops working when errors', () => {
    const sinonSpy = spy();

    sinonSpy();

    try {
        expect(sinonSpy).to.be.calledWithMatch({ foo: 'bar' });
    } catch (e) {
        delete e.actual;
        throw e;
    }
});
CendioOssman commented 1 month ago

Thanks. That doesn't scale terribly well. And we have 765 such assertions. Any workaround would need to be somewhere more central. :/

Sanderovich commented 1 month ago

For a central work around I would implement the work around in a Chai plugin:

import { use, Assertion } from 'chai';
import sinonChai from 'sinon-chai';

function overrideCallWithMatch() {
    Assertion.overwriteMethod('calledWithMatch', _super => {
        return function() {
            try {
                _super.apply(this, arguments)
            } catch (error) {
                delete error.actual;
                throw error;
            }
        }
    });
}

use(sinonChai);
use(overrideCallWithMatch);

Depending on for which Sinon Chai methods you want to implement the work around you can extend the plugin. Would this help you @CendioOssman ?

lideen commented 3 weeks ago

I have the same issue. This is an issue with any value that structuredClone cannot handle. In my projects tests started failing for HTMLElements as well as they also cannot be cloned.

My current workaround is to lock @web/dev-server-core@0.7.1

rschristian commented 3 weeks ago

I was running into this with sinon-chai but saw no errors in the browser console at all -- seemingly just a failed test that wasn't properly detected. Wasn't using calledWithMatch either.

Both workarounds (wrapper and pinning to @web/dev-server-core@0.7.1) worked for me though.