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

Cannot programmatically abort an xhr #42

Closed
warpdesign opened this issue Feb 24, 2023 · 8 comments · Fixed by #45
Closed

Cannot programmatically abort an xhr #42

warpdesign opened this issue Feb 24, 2023 · 8 comments · Fixed by #45

Comments

@warpdesign
Copy link

warpdesign commented Feb 24, 2023

Describe the bug

In version 7.0.4 I was able to programmatically abort a request.

In version 8.1.0 this doesn't seem to work anymore: abort isn't defined anymore in MockXhrRequest.

Is there a way to programmatically abort the request in the new version?

Steps to reproduce the behavior:

      beforeAll(() => {
        const MockXhr = MockXMLHttpRequest.newMockXhr()
        global.XMLHttpRequest = MockXhr
    })

    //...
    it('my test', () => {
      global.XMLHttpRequest as any).onSend = (xhr) => {
          // crashes here in version 8.1.0 because abort method isn't defined anymore
          // works as expected in 7.0.4
          xhr.abort()
     }
     // execute code that creates & sends a new XHR
   })

Environment in which you encounter the issue:

  • mock-xmlhttprequest version: 8.1.0
  • Node.js version: 18.14.1
  • OS version: Darwin 21.6.0
@berniegp
Copy link
Owner

Hi, the onSend method now receives a MockXhrRequest instance of the current request instead of the XMLHttpRequest instance as explained here: https://github.com/berniegp/mock-xmlhttprequest#onsend

You read more about the rationale for this change here: #30

I can see that your usage pattern doesn't fit directly with this change. Could you explain some more what you're trying to achieve by calling abort in onSend? Perhaps a more fleshed out example of your test case that works in the 7.0.4?

@warpdesign
Copy link
Author

warpdesign commented Feb 28, 2023

In my app the user is uploading some content using an xhr. Whenever this xhr gets cancelled by the user (by clicking on the stop button of the browser for eg.), I receive an abort event on the xhr, and display some information to the user.

I want to check that the correct information is displayed to the when the xhr is aborted this way.

    xhr.addEventListener('abort', () => {
      // display some info to the user
    })

That's the reason why I need to call abort.

@berniegp
Copy link
Owner

berniegp commented Mar 1, 2023

Ok I understand the use-case. Any chance you can show more of the test case?

There's one workaround which is to do something like this:

it('my test', () => {
  let xhr;
  (global.XMLHttpRequest as any).onSend = (request) => {
      xhr.abort(); // xhr is captured and available here
  };
  // something that creates an xhr
  xhr = ...

If that doesn't work for you I can see other options, including making the xhr available in onSend.

@warpdesign
Copy link
Author

warpdesign commented Mar 2, 2023

I am testing a service, I don't have access to the underlying xhr.

Service code:

const service = () => new Promise((resolve, reject) => {
  const xhr = new XMLHTTPRequest();
  xhr.addEventListener('abort', () => reject('user cancelled the upload'))
  // ...
})

Test:

// This used to work in 7.0.4
;(global.XMLHttpRequest as any).onSend = (xhr: XMLHttpRequest) => {
  xhr.abort()
}

await expect(service()).rejects.toEqual('user cancelled the upload')

I guess adding a new setAbortRequest that aborts the xhr, much like existing setNetworkError would solve the problem.

Another way would be to expose the xhr on the onSend method as you suggested.

berniegp added a commit that referenced this issue Mar 3, 2023
@berniegp
Copy link
Owner

berniegp commented Mar 3, 2023

Can you try with ced7ace? I added the XMLHttpRequest as the second argument of onSend.

@warpdesign
Copy link
Author

warpdesign commented Mar 7, 2023

I retrieved the branch and built it but I don't have access to the second parameter. This is how I am using it:

      import * as MockXMLHttpRequest from 'mock-xmlhttprequest'
      // ...
      const MockXhr = MockXMLHttpRequest.newMockXhr()
      global.XMLHttpRequest = MockXhr
      // ...
      it('test', () => {
        // onSend appears to be defined like this (see types/MockXhr.d.ts) and only receives one parameter:
        //  onSend?: (xhr: MockXhr) => void;
        ;(global.XMLHttpRequest as any).onSend = (xhr: XMLHttpRequest) => {
          xhr.abort()
        }
     }

@berniegp
Copy link
Owner

berniegp commented Mar 8, 2023

That's unexpected. Here's what my dist\types\MockXhr.d.ts file looks like after a build (notice the last OnSendCallback line):

import MockXhrRequest from './MockXhrRequest';
import RequestData from './RequestData';
import XhrEventTarget from './XhrEventTarget';
import type { MockXhrResponseReceiver } from './MockXhrResponseReceiver';
export type OnCreateCallback = (xhr: MockXhr) => void;
export type OnSendCallback = (this: MockXhrRequest, request: MockXhrRequest, xhr: MockXhr) => void;
// [...]

I even included a unit test to test that the xhr gets passed to the callback: ced7ace#diff-c98920d8a38c44bd1bcddb36d810958f375925f7c60957d780816f09c4fd2ded

@warpdesign
Copy link
Author

Ah, my bad!
Looks good to me: there was so cache so vscode still used previous type definition file.

berniegp added a commit that referenced this issue Apr 12, 2023
berniegp added a commit that referenced this issue Apr 12, 2023
* Remove useless Promise resolution value

* Add MockXhr argument to the onSend hook.

Fixes #42
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

Successfully merging a pull request may close this issue.

2 participants