sinonjs / nise Goto Github PK
View Code? Open in Web Editor NEWFake XHR and fake server
License: Other
Fake XHR and fake server
License: Other
When using fetch api to request a url, the fake server can't match the url and the browser returns 404
As sinonjs/sinon#2218 (comment) showed, we have a bit of a feature disparity between this project and the fake timers: When using projects such as JSDOM it would be useful to explicitly state which target we want to install the fake XHR into to avoid issues such as the one in #2218, where the "global detection" will fail tests in "mixed environments", such as Node+JSDOM.
Not sure about the API, but perhaps something like
fakeXhr.useFakeXMLHttpRequest({target});
There are more methods that would need this, of course.
Alternatively, do like fake-timers
and wrap everything in a factory method to do nise.withGlobal(target).useFakeXMLHttpRequest()
, etc.
Expected behaviour:
xhr.ontimeout
is called after xhr.timeout
xhr.triggerTimeout
is called after xhr.timeout
Actual behaviour:
xhr.ontimeout
is NOT called after xhr.timeout
xhr.triggerTimeout
is NOT called after xhr.timeout
Code:
import { expect } from 'chai';
import { createSandbox, fakeServer, FakeXMLHttpRequest } from 'sinon';
const sleep = (duration: number): Promise<void> =>
new Promise((resolve) => {
setTimeout(resolve, duration);
});
describe('send', () => {
it('should be timeout', async () => {
const sandboxInstance = createSandbox();
const xhr = new FakeXMLHttpRequest();
(xhr as any).open('GET', '/');
(xhr as any).timeout = 1_000;
(xhr as any).triggerTimeout = sandboxInstance.spy();
(xhr as any).send();
let isTimeout = false;
(xhr as any).ontimeout = () => {
isTimeout = true;
};
await sleep(2_000);
(fakeServer as any).respond();
expect((xhr as any).triggerTimeout.getCalls().length).to.eq(1);
expect(isTimeout).to.eq(true);
});
});
Additional data
"nise": "1.4.3",
"chai": "4.2.0",
"@types/chai": "4.1.7",
The test below fails for me, but I think it should work. It is possible that i don't correctly understand what i am doing.
I think that FakeXMLHttpRequest.dispatchEvent ought to set the target of the event, but it does not.
import { fakeXhr } from 'nise';
let xhrControl;
beforeEach(() => {
xhrControl = fakeXhr.useFakeXMLHttpRequest();
});
afterEach(() => {
xhrControl.restore();
});
test('Event target should be set', (done) => {
const xhr = new XMLHttpRequest();
xhr.addEventListener('error', (evt) => {
expect(evt.target).toBe(xhr);
done();
}, false);
const err = new ErrorEvent('error');
xhr.dispatchEvent(err);
});
Hello,
Since the latest release 1.4.9
I'm getting the following error:
Error: Cannot find module 'text-encoding'
Apparently the fix is already committed but not yet released:
fb3b595
Any plan to release it quickly?
Many thanks!
Related to #49.
Minimal repro: https://github.com/pswai/nise-defake-issue
Considering this case:
sinon.FakeXMLHttpRequest.useFilters = true;
sinon.FakeXMLHttpRequest.addFilter(() => true);
const server = sinon.fakeServer.create();
const xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.mocky.io/v2/5e8aa67e2d00003c1a1a473e", true);
// Setting `withCredentials` applies only to the FakeXhr instance.
// The `workingXHR` in `defake` does not receive this.
xhr.withCredentials = true;
xhr.send();
xhr.send()
calls the send
function defined in the defake
function. Since defake
is called during open
, any modification to the fake XHR does not reflect on the actual XHR. In this example, if we put a breakpoint in send
, we can see that withCredentials
is false
for the actual XHR.
I think we can either utilise Proxy to setup trap for setting properties after defake
, or do copyAttrs
again in send
.
This was discovered when I was trying to use unsafeHeadersEnabled: false
with fake server and noticed that withCredentials
didn't work ๐
Migrated from sinonjs/sinon#1678
Originally created by @Ninerian on Fri, 26 Jan 2018 14:41:19 GMT
What did you expect to happen?
When a invalid xml file is loaded with XMLHttpRequest, the responseXML is null.
What actually happens
The FakeXMLHttpRequest fills the responseXML with the parsed xml document with included parseErrors.
How to reproduce
const invalidXMLData = `!!!<?xml version="1.0" encoding="UTF-8"?><start>`;
function testXMLRequest(options) {
var xhr = new XMLHttpRequest();
xhr.open('GET', options.url, true);
// If specified, responseType must be empty string or "document"
xhr.responseType = 'document';
// overrideMimeType() can be used to force the response to be parsed as XML
xhr.overrideMimeType('text/xml');
xhr.onload = function() {
if (xhr.readyState === xhr.DONE) {
if (xhr.status === 200) {
if (xhr.responseXML) {
options.onSuccess();
} else {
options.onErrorCallback();
}
}
}
};
xhr.send(null);
}
let xhr, requests, requestor;
before(() => {
xhr = sinon.useFakeXMLHttpRequest();
requests = [];
xhr.onCreate = function(xhr) {
requests.push(xhr);
};
});
after(() => {
xhr.restore();
});
it('Should throw an error, when the xml is invalid', () => {
let successCallback = sinon.spy();
let errorCallback = sinon.spy();
const reqSettings = {
url: '/xml',
onSuccess: successCallback,
onErrorCallback: errorCallback,
};
testXMLRequest(reqSettings);
requests[0].respond(200, { 'Content-Type': 'text/text' }, invalidXMLData);
expect(successCallback.notCalled, 'Success callback is not called').to.be.true;
expect(errorCallback.calledOnce, 'Error callback is called').to.be.true;
});
Solution
After parsing the response, you should check for parseerrors and return null.
Hi there!
I noticed that nise is sending the readystatechange event with an "OPENED" readystate when calling the xhr.send()
function, while the native XHR doesn't.
As it's pretty hard to explain, here is an example of what the native XHR triggers and what nise does: https://jsfiddle.net/1djoqatw/2/
We can see that nise triggers an "OPENED" event for both xhr.open()
and xhr.send()
, while the native XHR only triggers it once when xhr.open()
is being called.
It's pretty problematic for us as we are doing some actions on the readystatechange event listener which gets called too many times in our unit tests.
Is there a particular reason for "OPENED" to be triggered when send()
is called?
Thank you very much,
Have a nice day!
After an update up to 1.2.1 version I found that error message:
Error: Cannot find module './event'
at Function.Module._resolveFilename (module.js:469:15)
at Function.Module._load (module.js:417:25)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (/home/kantora.pro/node-backend-skeleton/node_modules/.registry.npmjs.org/nise/1.2.1/node_modules/nise/lib/event/index.js:4:12)
Believe that happens because directory lib/event
doesn't contain 'event.js' module
Hi, AFAIK there is no way to get the fake server to trigger progress events during an upload.
It would be very useful this was possible in a simple way. Maybe:
server = sinon.fakeServer.create()
server.responWith((r) => {...})
// this fires for all requests - not ideal but very accessable and would solve 80% of all usecases
server.updateProgress({lengthComputable: true, loaded: 100, total: 200 })
**What did you expect to happen?
I would expect the progress event to fire for all requests.
It looks like there is an error attempting to determine what a parse error may look like.
https://github.com/sinonjs/nise/blob/master/lib/fake-xhr/index.js#L345
I have a situation running with a DOMParser stub in node where the document INVALID
does not return any elements with a parseerror tag name. In this situation my XML is failing to parse even though my XML is valid. The check for getElementsByTagName("parsererror")
should verify that it got a result prior to checking the item at index 0. In my situation I have valid XML but no parsererror
for the "INVALID" document.
Can you please update all of your dependencies to resolve some security issues?
We need to update the documentation to include the changes made in #35
Version 1.2.1 of nise is broken - there are missing files in the package on npm, eg. all contents of lib/events
is missing, except for index.js
.
In lib/fake-xhr/index.js#L3 you require text-encoding but you have no dependency on it.
EventTarget methods: addEventListener and removeEventListener can optionally support options object https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
For XHR objects once
flag seems to be the only one that makes sense, and major browsers support it.
This is follow-up for #19
the dependency 'text-encoding' of 'nise' is no longer maintained:
gms@orion:~/work/RESEARCH/loopback4-example-todo$ npm i
npm WARN deprecated [email protected]: no longer maintained
npm notice created a lockfile as package-lock.json. You should commit this file.
added 623 packages from 1418 contributors and audited 3053 packages in 19.523s
found 1 low severity vulnerability
run `npm audit fix` to fix them, or `npm audit` for details
gms@orion:~/work/RESEARCH/loopback4-example-todo$ npm ls text-encoding
@loopback/[email protected] /home/gms/work/RESEARCH/loopback4-example-todo
โโโฌ @loopback/[email protected]
โโโฌ [email protected]
โโโฌ [email protected]
โโโ [email protected]
When registering a response with a fake-server instance and the URL specifies port number, the corresponding requests receive a HTTP 404 Not Found error even though the URLs match.
Error Reproduction:
this.server.respondWith("GET", "http://localhost:5000/ping", "Pong");
var xhr = new FakeXMLHttpRequest();
xhr.open("GET", "http://localhost:5000/ping", true);
xhr.send();
// HTTP 404 Not Found
Expected behavior: HTTP 200 OK, "Pong"
Context
This error comes up when testing a Vue.js app which is a Web UI that is communicating back to a API server. The API server is running on the same host on the separate port (ie same domain/origin, different port). For the purpose of unit testing, the API server is being abstracted by the Sinon fake-server which is how the issue arose.
Library version: [email protected]
Environment: Node v12.16.2, Vue.js v4.3.1, [email protected], [email protected], [email protected]
import 'nise'
throws Uncaught ReferenceError: global is not defined
.
From @scottohara on May 31, 2018 7:10
Describe the bug
In [email protected]
, using jQuery's $.ajax()
to fetch a non-existent URL from fakeServer
returns a 404 Not Found
response, as expected.
In [email protected]
and later, the same fetch now returns a 0
status.
To Reproduce
npm install [email protected]
, and run the tests belownpm install [email protected]
, and re-run the tests againdescribe.only("404 Not Found", () => {
let fakeServer;
beforeEach(() => (fakeServer = sinon.fakeServer.create({respondImmediately: true})));
it("should work without headers", done => {
$.ajax({
url: "/bad",
headers: {},
error(response) {
response.status.should.equal(404);
response.statusText.should.equal("Not Found");
done();
}
});
});
it("should work with headers", done => {
$.ajax({
url: "/bad",
headers: {"X-FOO": 1},
error(response) {
response.status.should.equal(404);
response.statusText.should.equal("Not Found");
done();
}
});
});
afterEach(() => fakeServer.restore());
});
Expected behavior
The specs above create a fakeServer
and then attempt to fetch a non-existant URL (/bad
).
The only difference between the two specs is the second includes a request header, X-FOO: 1
.
The specs assert the response returned from fakeServer
is a 404 Not Found
In [email protected]
, both specs pass.
In [email protected]
and later, the spec with the X-FOO
request header fails
Screenshots
Results from [email protected]
:
Results from [email protected]
:
Context (please complete the following information):
Copied from original issue: sinonjs/sinon#1817
The headers like Cookie
are missing for the requests which pass though the fakeServer
and filter.
This is causing the requests to lose the sessions.
const server = sinon.fakeServer.create({ logger: console.log, unsafeHeadersEnabled: true });
server.autoRespond = true;
server.xhr.filters = [];
server.xhr.useFilters = true;
//If the filter returns true, the request will not be faked - leave original
server.xhr.addFilter(function(method, url, async, username, password) {
// have some condition to allow some requests to pass through
});
server.respondWith((xhr, id) => {
xhr.respond(200, { "Content-Type": "application/text" },"Hello World");
});
Hey,
First of all: I really like the nise fake server.
Is it possible to intercept and manipulate a request? I tried several approaches.
My last approach was to intercept a request, make the same call with the fetch api and return the result from the fetch api as mock. Please see the following code snippet:
const server = nise.fakeServer.create({
autoRespond: true,
autoRespondAfter: 100,
});
// devices
server.respondWith(
'GET',
/.*(rest\/devices)/,
async (xhr) => {
const devices = await fetch(xhr.url)
.then(function(response) {
return response.json();
});
xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify(devices));
},
);
But I get the following error: Error: INVALID_STATE_ERR - 4.
I get the same error if I try to use the setTimeout
method in the callback function.
Is there any possibility to intercept requests with nise?
Thank you in advance!
Cheers,
Stefan
From @scottohara on May 31, 2018 7:10
Describe the bug
In [email protected]
, using jQuery's $.ajax()
to fetch a non-existent URL from fakeServer
returns a 404 Not Found
response, as expected.
In [email protected]
and later, the same fetch now returns a 0
status.
To Reproduce
npm install [email protected]
, and run the tests belownpm install [email protected]
, and re-run the tests againdescribe.only("404 Not Found", () => {
let fakeServer;
beforeEach(() => (fakeServer = sinon.fakeServer.create({respondImmediately: true})));
it("should work without headers", done => {
$.ajax({
url: "/bad",
headers: {},
error(response) {
response.status.should.equal(404);
response.statusText.should.equal("Not Found");
done();
}
});
});
it("should work with headers", done => {
$.ajax({
url: "/bad",
headers: {"X-FOO": 1},
error(response) {
response.status.should.equal(404);
response.statusText.should.equal("Not Found");
done();
}
});
});
afterEach(() => fakeServer.restore());
});
Expected behavior
The specs above create a fakeServer
and then attempt to fetch a non-existant URL (/bad
).
The only difference between the two specs is the second includes a request header, X-FOO: 1
.
The specs assert the response returned from fakeServer
is a 404 Not Found
In [email protected]
, both specs pass.
In [email protected]
and later, the spec with the X-FOO
request header fails
Screenshots
Results from [email protected]
:
Results from [email protected]
:
Context (please complete the following information):
Copied from original issue: sinonjs/sinon#1817
This change: angus-c/just@886a4ff#diff-3333af3f3ec7ec75ad2ea0a69dc86bbbR38 breaks this https://github.com/sinonjs/nise/blob/master/lib/fake-xhr/index.js#L651
As far as I can see, it is not possible anymore to use extend()
with a function as its first parameter.
This package should be published as @sinonjs/nise
, and the existing package deprecated.
Given that this is the only sinonjs/*
library that exclusively deals with browsers, it's perplexing that it's the only one not running tests in a browser ๐ฎ That makes it hard to verify run-time issues in browsers, such as #61 (and the fix in #67).
We should add mochito
(running Puppeteer) like in the other projects.
Hi.
var xhr = nise.fakeXhr.useFakeXMLHttpRequest();
xhr.useFilters = true;
xhr.addFilter(function () {
return true;
});
xhr.addEventListener('readystatechange', () => {
console.log(xhr.readyState) // will never been 4
});
....
xhr.open("GET", "http://example.com");
readyState in defaked request is being setted in stateChange handler
https://github.com/sinonjs/nise/blob/master/lib/fake-xhr/index.js#L225
that fires after other handlers.
It is nice for people who follow this project.
Hi team,
I've some general questions to this project which I can not answer by the documentation.
What is the way to go to use fakeServer in a JS project. Should I use sinon.js fakeserver or nise?
Is there a future roadmap to remove fakeServer from Sinon.js?
Thanks a lot for your work! FakeServer helped me so lot.
Migrated from sinonjs/sinon#1873
Originally created by @sebcanonica on Wed, 01 Aug 2018 17:16:00 GMT
Symptom
Using a fake server, if I try to filter a request (to let it go through normally) which is sent synchronously, then sinon throw an exception:
In Chrome
Uncaught DOMException: Failed to set the 'responseType' property on 'XMLHttpRequest': The response type cannot be changed for synchronous requests made from a document.
at y.u.send (https://cdnjs.cloudflare.com/ajax/libs/sinon.js/6.1.4/sinon.min.js:1:113357)
at window.onload (https://fiddle.jshell.net/_display/:36:9)
In Firefox
InvalidAccessError: synchronous XMLHttpRequests do not support timeout and responseType. sinon.min.js:1
[61]</</y.defake/u.send
https://cdnjs.cloudflare.com/ajax/libs/sinon.js/6.1.4/sinon.min.js:1:113343
window.onload
https://fiddle.jshell.net/_display/:36:1
To Reproduce
Steps to reproduce the behavior:
const server = sinon.fakeServer.create();
server.xhr.useFilters = true;
server.xhr.addFilter(() => true);
const request = new XMLHttpRequest();
request.open('GET', 'anything.html', false);
request.send();
console.log('Not reached');
Expected behavior
The request should be served normally and no exception should be thrown
Context
Additional context
The defake method put in place a send method which modify the responseType of the real xhr, which is forbidden for synchronous xhr not in a worker context.
If I comment out this line, the behavior is Ok.
According to documentation from MDN https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener, if listener is registered more than once it should be discarded. I haven't found any specific details on how to translate with the same parameters
in regards to XHR. Event type and listener are definitely part of this, and seems that options.once
should be added to equality comparison, as it works as expected for XHR.
There was a ticket on sinon from a while back: sinonjs/sinon#431. I attempted to fix this with the following PR: https://github.com/sinonjs/sinon/pull/1495/files.
It'd be pretty easy for me to port the PR, since the files haven't changed much.
My thought was to only set the timeout functionality if an instance of global XMLHttpRequest has the timeout variable and if send
is called while fake timers are activated. I've taken into account quirks like fakeServerWithClocks
forcing a tick for the longest timeout.
If this sounds reason let me know and I would be happy to create a PR for review.
Currently if setRequestHeader
is called twice with the same header name, value will be combined into one comma delimited list. But if header names passed to setRequestHeader
differ in case, it will produce 2 separate headers being set.
According to spec composition process should ignore case of header name:
Also value should be trimmed
I'm having the following situation:
function reloadApp() {
$.ajax({url: "first/url"}).then(() => {
$.ajax({url: "second/url"}).then(() => updateSomeDOMAttributes());
}).then((r1) => addSomeDOMAttributes());
renderDOMComponent();
}
There are two ajax requests nested but not chained to one another.
I'm using Sinon.js (which uses nise).
I have no way of waiting for the second request to fulfil unless I chain the Promise which is something I cannot do without breaking compatibility (let's assume that it cannot be done).
beforeEach(() => {
server = sinon.createFakeServer({respondImmediately: true});
spy = sinon.spy(tracking, "trackEvent");
});
afterEach(() => {
server.restore();
spy.restore();
});
it('ajax mocking works #1', (done) => {
server.respondWith("GET", 'first/url', [ 200, { "Content-Type": "text/html" }, `mocked1` ]);
server.respondWith("GET", 'second/url', [ 200, { "Content-Type": "text/html" }, `mocked2` ]);
reloadApp().then((r1) => {
expect(r1).to.equal(`mocked1`);
expect(spy.callCount).to.equal(2); <------- fails
done();
});
// server.respond();
});
I tried both strategies with respondImmediately
and with the server.respond()
.
My solution is to make a helper:
/**
* Wait for the Sinon.js nise XHR mocks to finish their registered
* responses.
*
* @param server Server created with sinon.createFakeServer
* @param timeout Optional, how much to wait before failing.
* @returns {Promise<any>}
*/
function waitForServerToFulfillRequests(server, timeout) {
timeout = timeout || 100;
return new Promise((resolve, reject) => {
let checkCount = 0;
const i = setInterval(() => {
if (server.requests.length === server.responses.length) {
clearInterval(i);
resolve();
}
if (checkCount === 100) {
clearInterval(i);
reject(`Maximum waiting count of ${checkCount * 16} has passed.`);
}
checkCount++;
}, 16);
});
}
This is obviously an edge case but my goal is to test the final outcome of the code and wait for all the requests to finish because they modify the HTML component that I'm testing.
Working example: https://github.com/serbanghita/karma-mocha-chai-sinon ;
Let me know your thoughts on the situation and waitForServerToFulfillRequests
Although this package is most likely only rarely used in the browser, and it is (hopefully) never used on a live site, I'm still concerned by the huge overhead the text-encoding
dependency adds. The package size is about 500kb with text-encoding
and 40kb without.
I'm using this package to fake XHR requests in automated acceptance tests with Nightwatch.js and although loading is not too much of an issue when the file isn't sent over the network, parsing it in the browser is a significant burden on the performance of the test system.
As a quick workaround, I've just forked this package and removed everything text-encoding
related (maoberlehner@64db34e).
Is there any chance to get rid of this dependency? Maybe it is possible to make it optional, so people who actually need ArrayBuffers and Blobs, can add it manually?
This repository has a lot of old deps, with many security vulnz. It would be great to install greenkeeper so we get PRs with updates. If you'd like getting this rolling - I'm interested in helping as a maintainer of the lib.
I tried passing a function into server.respondWith() but i think there is a bug in processing response results.
here's my call:
var server = sinon.fakeServer.create();
server.respondWith("POST", "/foo/api", function(request) {
var req = JSON.parse(request.requestBody);
return [200, {"Content-Type": "application/json"},JSON.stringify({ req.bar === 'hello world' ? 'yes' : 'no'})}];
});
The problem seems to be here:
node_modules/nise/lib/fake-server/index.js:261
request.respond(response[0], response[1], response[2]);
Instead it should do something like this:
if (typeof response.response === "function") {
response = response();
}
return request.respond(response[0], response[1], response[2]);
Moved from sinonjs/sinon#1528.
Running the test case where only the /foo
route should be matched results in both being matched. To reproduce:
$ npm i -g phantomic phantomjs-prebuilt browserify
$ npm i babelify babel-preset-es2015
$ browserify test.js -t [ babelify --presets [ es2015 ] ] -o bundle.js && phantomic bundle.js
requesting foo
foo requested
default requested
INVALID_STATE_ERR - 4 Error: INVALID_STATE_ERR - 4
status == 200? true
// when testing locally in the repo: const nise = require('./lib/')
const nise = require('nise');
const server = nise.fakeServer.create();
// each response should be triggered exactly once
let fooResponded = false;
let defaultResponded = false;
// default responder
server.respondWith(xhr=>{
console.log('default requested')
if (defaultResponded)
console.log("default requested more than once!");
defaultResponded = true;
try {
xhr.respond(404, {}, '');
}catch(err) {
console.log(err);
}
});
// foo responder
server.respondWith('/foo', xhr=>{
console.log('foo requested')
if (fooResponded)
console.log("foo requested more than once!");
fooResponded = true;
return xhr.respond(200, {}, '');
});
// request foo
let r = new XMLHttpRequest();
console.log('requesting foo');
r.open('GET', '/foo', false);
r.send();
console.log('status == 200?', r.status === 200);
From @bennyn on March 26, 2017 15:34
Sinon version: Sinon v2.1.0
Environment: Node.js v7.7.3
Other libraries you are using:
I always used Sinon in combination with Jasmine and a Karma test runner (to execute Browser tests). Now I want to use Sinon in a Node.js environment and I want to mock server responses.
In my Node.js application I don't use jQuery, so I cannot make use of sinon.spy(jQuery, 'ajax');
. In your documentation I read that I can fake the XMLHttpRequest
object (if not using jQuery), but it also looks like Node.js doesn't make use of the standard XMLHttpRequest
.
So do I need a wrapping module for Node.js requests like node-XMLHttpRequest to make it work?
Here is the code I have written so far:
const sinon = require('sinon');
const EndpointValidator = require('./../src/EndpointValidator');
let server = undefined;
let validator = undefined;
beforeAll(() => {
server = sinon.fakeServer.create();
server.autoRespond = true;
server.respondWith('GET', 'http://www.mypage.com/online', [
200, {
'Content-Type': 'application/json'
}, JSON.stringify({
"status": "online"
})
]);
});
beforeEach(() => {
validator = new EndpointValidator();
});
afterEach(() => {
server.restore();
});
describe('EndpointValidator', () => {
it('checks for a valid endpoint', (done) => {
validator.isValidEndpoint('http://www.mypage.com/online')
.then((data) => {
const json = JSON.parse(data);
expect(json.status).toBe('online');
done();
})
.catch(done.fail);
});
});
EndpointValidator.js
const request = require('request');
class EndpointValidator {
constructor() {
}
isValidEndpoint(url, minimumBodyLength = 0) {
return new Promise((resolve, reject) => {
request.get(url, function(error, response, body) {
if (response.statusCode !== 200) {
reject(new Error('Service is temporarily unavailable.'));
} else {
if (response.body.length > minimumBodyLength) {
resolve(body);
} else {
resolve(false);
}
}
});
});
}
}
module.exports = EndpointValidator;
Copied from original issue: sinonjs/sinon#1367
Migrated from sinonjs/sinon#607
Originally created by @terinjokes on Thu, 20 Nov 2014 00:47:58 GMT
FakeXMLHttpRequest's send
method currently clobbers the "Content-Type" header if set, by removing anything after the first ";" and forcibly appending ";charset=utf-8".
A real XHR object allows sending binary data via TypedArray
s, ArrayBuffer
s, and Blob
s. They also correctly form encode when sent with FormData
values. As "Content-Type" might have application-specific behavior, blindingly clobbering them makes it difficult for developers to properly test the functionality.
Rollup bundler complains the usage of eval
as it poses a security risk.
https://rollupjs.org/guide/en/#avoiding-eval
Screenshot of the error is as follows.
Related issues -
ionic-team/ionic-app-scripts#129
ionic-team/ionic-cli#1500
tus/tus-js-client#147
Wondering if it is posable to bind this library to use a different window / global context programatically ?
Experimenting with PollyJs and CypressJs. Need to bind this lib to a different window to get this to work.
Happy to fo the work needed, just wondering if this is something this lib will embrace?
Thx
I wanted to report the same issue as #5 but I found out it is already fixed. Could you please do NPM publish of 1.0.2?
I've got some non-trivial unit tests that may trigger multiple AJAX requests. I usually mock out the various responses I should handle in my tests and then call the function that will trigger those requests.
At the end of the test I'd like to be able to know if any or a particular response didn't get sent. Similar to https://github.com/node-nock/nock#pendingmocks
This would be useful to test not only that all the relevant requests were made, but also to validate that a particular request wasn't made, if its conditional.
Im writing a chrome extension that is essentially a proxy. I'm getting an invalid state error when trying to respond to a fake xhr request. When the proxyRequest
method executes I'm seeing in the console that onload
is triggered before I call respond
. Thank you in advance for any help.
import { fakeXhr, FakeXMLHttpRequest, fakeServer, FakeServer } from 'nise'
import { isM3u8Url, isTsUrl, PROXY_REQUEST, Message, PROXY_RESPONSE } from './common'
import { generateId } from 'utils-and-helpers/helpers'
import { HttpMethod } from 'utils-and-helpers/enums'
import axios from 'axios'
let server: FakeServer
function createShim() {
fakeXhr.FakeXMLHttpRequest.useFilters = true
fakeXhr.FakeXMLHttpRequest.addFilter(xhrFilter)
server = fakeServer.create({
autoRespond: true
})
server.respondWith(proxyRequest)
}
function xhrFilter(method: string, url: string): boolean {
if((method.toLocaleUpperCase() == HttpMethod.GET) && (isM3u8Url(url) || isTsUrl(url))) return false
else return true
}
function proxyRequest(xhr: FakeXMLHttpRequest) {
let id = generateId(25)
let message: Message = {
id,
action: PROXY_REQUEST,
async: xhr.async,
method: xhr.method,
requestBody: xhr.requestBody,
requestHeaders: xhr.requestHeaders,
url: xhr.url,
username: xhr.username,
withCredentials: xhr.withCredentials
}
xhr.onload = () => console.log(`${id}: load start`)
chrome.runtime.sendMessage(message, response => {
switch(response.action) {
case PROXY_RESPONSE:
console.log(`${id}: trying to respond`)
xhr.respond(response.status, response.responseHeaders, response.responseBody)
break
default:
xhr.error()
}
})
}
createShim()
//test
setInterval(() => {
axios.get('https://5g9s179kfgx9wn8tqwj9-cul47i.p5cdn.com/dlive/transcode-93-29/dlive-47692714/1583938810/src/live.m3u8')
.then(res => console.log('res: ' + res))
.catch(error => console.error('error: ' + error))
}, 3000)
Hi!
If you add a filter, call .restore()
on fakeXhr and call useFakeXMLHttpRequest()
, previously added filters are not cleared. Is that a bug or a desired behaviour?
We use sinon with jsdom and recently updated sinon to 8.0.1 and starts to fail with
Mozilla/5.0 (darwin) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/15.2.1
Fake server request processing threw exception: GlobalTextEncoder is not a constructor
TypeError: GlobalTextEncoder is not a constructor
at convertToArrayBuffer (webpack:///./node_modules/nise/nise.js?:756:12)
at convertResponseBody (webpack:///./node_modules/nise/nise.js?:960:30)
at FakeXMLHttpRequest.setResponseBody (webpack:///./node_modules/nise/nise.js?:1317:29)
at FakeXMLHttpRequest.respond (webpack:///./node_modules/nise/nise.js?:1333:18)
at Object.processRequest (webpack:///./node_modules/nise/nise.js?:584:25)
at eval (webpack:///./node_modules/nise/nise.js?:547:18)
at Array.forEach (<anonymous>)
at Object.respond (webpack:///./node_modules/nise/nise.js?:546:18)
jsdom does not implement TextEncoder (ref) and in ./node_modules/nise/nise.js @sinonjs/text-encoding
is embed as empty module.
},{"./create-matcher":32,"./deep-equal":41,"./identical":43,"./is-arguments":44,"./is-element":46,"./is-map":47,"./is-neg-zero":49,"./is-set":51,"./match":54}],56:[function(require,module,exports){
// empty!
},{}],57:[function(require,module,exports){
// abbrev...
module.exports = extend(fakeXMLHttpRequestFor(globalObject), {
fakeXMLHttpRequestFor: fakeXMLHttpRequestFor
});
},{"../configure-logger":1,"../event":5,"./blob":10,"@sinonjs/commons":19,"@sinonjs/text-encoding":56,"just-extend":58}],12:[function(require,module,exports){ // the number is 56
I expect nise loads sinonjs/text-encoding properly. How can I use sinon with jsdom?
Hi,
Recently come across a need to use xhr.useFilters = true;
where we allow real requests to go through, and only mock parts that shouldn't be allowed.
However I've tracked down an issue where when we are "defaking" a request, we're missing some more of the real-ish type properties on the event.
Specifically for us, currentTarget
is not beside target
.
fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
currently needs currentTarget: fakeXhr
added.
Is this something that other people are seeing, or kind of an edge case for us?
Happy to present a PR, but at this stage all we need in addition to target
, is currentTarget
, but there's still a lot of other native-ish properties that are dropped when un-faking it, it may be better to not fake the request before checking filters (and thus remove the need to recreate the original event).
Thoughts?
When i am trying to install nise version 1.4.4 i am getting the below error
Tried commands
npm install -g nise
npm install -g [email protected]
Error
npm ERR! code ETARGET
npm ERR! notarget No matching version found for just-extend@^3.0.0
npm ERR! notarget In most cases you or one of your dependencies are requesting
npm ERR! notarget a package version that doesn't exist.
npm ERR! notarget
But when i am trying to install nise version 1.4.3 then it doesnt throw any error
npm install -g [email protected]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.