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

Unable to fetch to third party using Remix with error: TypeError: Expected signal to be an instanceof AbortSignal #1097

Closed
Afsoon opened this issue Sep 26, 2023 · 0 comments · Fixed by #1098
Labels
bug Something isn't working

Comments

@Afsoon
Copy link
Contributor

Afsoon commented Sep 26, 2023

Describe the bug
While I was trying to implement unit testing for my authenticate loaders and actions on my Remix project, I could not launch my test using Happy-DOM. I tried the same tests using JSDOM, and they passed without error.

After digging into the problem, I found the problem is that the AbortSignal and EventTarget classes don't implement the Symbol.toStringTag method. Remix is using this method to detect if the signal attached to a Request is an AbortSignal or EventTarget.

As a result, this check fails and throws an exception.

To Reproduce
Steps to reproduce the behavior (See Additional context for the link to the repository with the minimal code to reproduce it):

  1. Create a loader that has a fetch to a third-party API
  2. Create a test expecting the result of a loader
  3. Launch the test, and it will fail with TypeError: Expected signal to be an instanceof AbortSignal

Expected behavior
I expected that it would work as on JSDOM.

Additional context
I made a repository where you can find a minimal reproduction of the bug and a possible workaround until a fix lands in the repository.

If it has low priority, I can make a PR to fix it. Nevermind, I had patched locally the package, I will open an PR ASAP with the fix.

This is the workaround

const Signal = new AbortSignal();

const SignalProxied = new Proxy(Signal, {
  get: (target, prop, receiver) => {
    if (prop === Symbol.toStringTag) {
      return "AbortSignal";
    }

    return Reflect.get(target, prop, receiver);
  },
});

const controller = new AbortController();
const ControllerProxied = new Proxy(controller, {
  get: (target, prop, receiver) => {
    if (prop === "signal") {
      return SignalProxied;
    }

    return Reflect.get(target, prop, receiver);
  },
});

global.AbortController = new Proxy(global.AbortController, {
  construct: () => {
    return ControllerProxied;
  },
});

The workaround is based on proxify AbortController and AbortSignal to intercept the call to the method Symbol.toStringTag

@Afsoon Afsoon added the bug Something isn't working label Sep 26, 2023
Afsoon added a commit to Afsoon/happy-dom that referenced this issue Sep 26, 2023
Afsoon added a commit to Afsoon/happy-dom that referenced this issue Sep 27, 2023
Afsoon added a commit to Afsoon/happy-dom that referenced this issue Sep 27, 2023
capricorn86 added a commit that referenced this issue Sep 27, 2023
…ringTag

#1097@patch: Implements Symbol.toStringTag on EventTarget and AbortSignal.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant