Last active
September 16, 2021 08:46
-
-
Save yagudaev/2ad1ef4a21a2d1cfe0e7d96afc7170bc to your computer and use it in GitHub Desktop.
Cypress Fetch Support Workaround - replaces fetch request with traditional XHR so cypress can track them
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// cypress/support/hooks.js | |
// Cypress does not support listening to the fetch method | |
// Therefore, as a workaround we polyfill `fetch` with traditional XHR which | |
// are supported. See: https://github.com/cypress-io/cypress/issues/687 | |
enableFetchWorkaround() | |
// private helpers | |
function enableFetchWorkaround() { | |
let polyfill | |
before(() => { | |
console.info('Load fetch XHR polyfill') | |
cy.readFile('./cypress/support/polyfills/unfetch.umd.js').then((content) => { | |
polyfill = content | |
}) | |
}) | |
Cypress.on('window:before:load', (win) => { | |
delete win.fetch | |
// since the application code does not ship with a polyfill | |
// load a polyfilled "fetch" from the test | |
win.eval(polyfill) | |
win.fetch = win.unfetch | |
}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// cypress/support/index.js | |
import './hooks' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// cypress/support/polyfills/unfetch.umd.js | |
// Version: 4.1.0 | |
// from: https://unpkg.com/unfetch/dist/unfetch.umd.js | |
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):e.unfetch=n()}(this,function(){return function(e,n){return n=n||{},new Promise(function(t,o){var r=new XMLHttpRequest,s=[],u=[],i={},f=function(){return{ok:2==(r.status/100|0),statusText:r.statusText,status:r.status,url:r.responseURL,text:function(){return Promise.resolve(r.responseText)},json:function(){return Promise.resolve(JSON.parse(r.responseText))},blob:function(){return Promise.resolve(new Blob([r.response]))},clone:f,headers:{keys:function(){return s},entries:function(){return u},get:function(e){return i[e.toLowerCase()]},has:function(e){return e.toLowerCase()in i}}}};for(var a in r.open(n.method||"get",e,!0),r.onload=function(){r.getAllResponseHeaders().replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm,function(e,n,t){s.push(n=n.toLowerCase()),u.push([n,t]),i[n]=i[n]?i[n]+","+t:t}),t(f())},r.onerror=o,r.withCredentials="include"==n.credentials,n.headers)r.setRequestHeader(a,n.headers[a]);r.send(n.body||null)})}}); |
@stigkj Aye, hence the confusion.
// Cypress 3.3.1 and below do not support listening to the fetch method
Is confusing as it gives the impression that with higher versions you don't need this workaround, where in fact they do.
Comment should change to something like
// For Cypress versions not supporting listening to the fetch method
@Izhaki you are right, I should just remove it. I was hoping they would fix it already, but they have not even fixed it in 4.x.
There is an unofficial plugin listed on cypress plugins that does this - sad they haven't fixed this yet: https://github.com/RcKeller/cypress-unfetch
This does not work for me. I use can-ndjson-stream to make the fetch requests.
I rewrite the polyfill file to work in my case. I hope it's all ok.
!function (e, n) {
"object" == typeof exports && "undefined" != typeof module ? module.exports = n() : "function" == typeof define && define.amd ? define(n) : e.unfetch = n()
}(this, function () {
return function (request) {
return new Promise(function (success, rejected) {
var r = new XMLHttpRequest;
var keys = [];
var values = [];
var headers = {};
var convertRequest = function () {
var enc = new TextEncoder(); // always utf-8
return {
ok: 2 === (r.status / 100 | 0),
statusText: r.statusText,
status: r.status,
url: r.responseURL,
text: function () {
return Promise.resolve(r.responseText)
},
text: function(){
return Promise.resolve(r.responseText)
},
json: function(){
return Promise.resolve(JSON.parse(r.responseText))
},
body: {
getReader: function () {
var stream = new ReadableStream({
start(controller) {
controller.enqueue(enc.encode(r.responseText));
controller.close();
}
});
return new ReadableStreamDefaultReader(stream);
}
},
blob: function () {
return Promise.resolve(new Blob([r.response]))
},
clone: convertRequest,
headers: {
keys: function () {
return keys
}, entries: function () {
return values
}, get: function (header) {
return headers[header.toLowerCase()]
}, has: function (header) {
return header.toLowerCase() in headers
}
}
}
};
r.open(request.method || "get", request.url, true);
r.onload = function () {
r.getAllResponseHeaders().replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm, function (match, key, value) {
key = key.toLowerCase();
keys.push(key);
values.push([key, value]);
headers[key] = headers[key] ? headers[key] + "," + value : value;
});
success(convertRequest());
}
r.onerror = rejected;
r.withCredentials = "include" === request.credentials;
request.headers.forEach((value, key) => r.setRequestHeader(key, value));
request.text().then(body => r.send(body));
}
)
}
});
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@paulpruteanu Are you trying to mock out loading of a script? Or is the script that is loaded doing a fetch? The first one does not work as loading a script does not use fetch, but I would think the second one should work.
@Izhaki The issue mentioned (#687) is not implemented yet, so you still need to do this.