+import { ECHO_BACK_URL } from "./env/shared";
+ onBeforeLoad: (cw: any) => {
+ cw.XMLHttpRequest.prototype.open = getNewXhrOpen(cw.XMLHttpRequest.prototype.open)
+ cw.XMLHttpRequest.prototype.send = getNewSender(cw.XMLHttpRequest.prototype.send);
+const getNewSender = (oldSend: any) => function(this: any, body: any) {
+ // get the body mapper or an identity fn
+ const newBody = (this.bodyMappers as any[])
+ return oldSend.bind(this)(
+const getNewXhrOpen = (oldOpen: any) => function(this: any, method: any, url: any) {
+ this.bodyMappers = (cy.routeBodyMatchers || [])
+ .map(matcher => matcher(method, url))
+ return oldOpen.bind(this)(
+ this.bodyMappers.length ? ECHO_BACK_URL : url,
+const doesBodyMatch = (res: any) => res !== '__NO_MATCH__';
+const stringify = (v: any) => JSON.stringify(v);
+const parseOrValue = (v: any) => {
+const safeFn = (fn: ((...args: any[]) => any)) => (...args: any[]): any => {
+ try { return fn(...args); } catch (e) { }
+const improvedRouterCommandHandler = (method: string, url: string, tester: (body:any) => boolean, response: any, ...responses: any[]) => {
+ let allResponses = [response, ...responses];
+ tester = safeFn(tester);
+ // make a mapper to determine if we should replace the body
+ let routeToBodyMapper = (method2: string, fullUrl: string) => {
+ if (method2.toUpperCase() !== method.toUpperCase()) {
+ if (!fullUrl.match(new RegExp(url.split('**').join('.+?'), 'i'))) {
+ // this __NO_MATCH__ is so that the user can force false or undefined or whatever they want though
+ return (body: any) => allResponses.length || !tester(parseOrValue(body)) ? '__NO_MATCH__' : allResponses.shift();
+ // registerUrlBodyMatch(method, url, tester, response);
+ cy.routeBodyMatchers = (cy.routeBodyMatchers || []).concat(routeToBodyMapper);
+Cypress.Commands.overwrite('visit', (orig, [one, two]) => {
+ // default visit can be structured in a few differnt ways
+ const [url, conf] = two === 'object'
+ return orig(url, {...conf, ...visitConf});
+Cypress.Commands.overwrite('route', (orig, ...args: any[]) => {
+ if (args.length < 4) return orig(...args);
+ const [method, url, maybeFnMaybeResponse, ...responses] = args;
+ const fn = typeof maybeFnMaybeResponse === 'function'
+ : () => true; // we are in subsequent call mode so all bodies match
+ const allResponses = typeof maybeFnMaybeResponse === 'function'
+ : [maybeFnMaybeResponse, ...responses]
+ return (improvedRouterCommandHandler as any)(method, url, fn, ...allResponses);