wrapito 13.3.1-beta7 → 13.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -84,6 +84,58 @@ Add this line in your project setup (vite/cra):
84
84
  setupFiles: ['./src/setupTests.tsx']
85
85
  ```
86
86
 
87
+ #### warnOnPendingRequests
88
+
89
+ When rendering a full application, some API calls may still be pending when the test finishes. This can lead to flaky
90
+ tests if those pending requests resolve after the test cleanup phase.
91
+
92
+ By enabling `warnOnPendingRequests`, wrapito will log a warning to the console whenever a fetch call is detected after
93
+ a test has finished, including the request URL, method and the name of the test that left it pending. This helps
94
+ identify tests that need proper cleanup or `await` handling.
95
+
96
+ ```js
97
+ import { configure } from 'wrapito'
98
+
99
+ configure({
100
+ ...configuration,
101
+ warnOnPendingRequests: true,
102
+ })
103
+ ```
104
+
105
+ When a pending request is detected, you will see a warning like:
106
+
107
+ ```
108
+ 🌯 wrapito
109
+ ⚠️ pending request detected after test finished:
110
+ URL: https://my-host/api/products/
111
+ METHOD: get
112
+ TEST: should render the product list
113
+ ```
114
+
115
+ #### defaultResponses
116
+
117
+ If your tests share common network mocks (e.g. auth, config, feature flags), you can define them once via `defaultResponses` instead of repeating them in every test or extension.
118
+
119
+ These responses are automatically included in every `wrap(...).mount()` call. Test-specific mocks added via `withNetwork` or extensions take precedence over default responses.
120
+
121
+ ```js
122
+ import { configure } from 'wrapito'
123
+
124
+ configure({
125
+ ...configuration,
126
+ defaultResponses: [
127
+ {
128
+ path: '/api/auth/',
129
+ responseBody: { user: 'authenticated-user' },
130
+ },
131
+ {
132
+ path: '/api/feature-flags/',
133
+ responseBody: { newFeature: true },
134
+ },
135
+ ],
136
+ })
137
+ ```
138
+
87
139
  ## 🏰 Builder API
88
140
 
89
141
  #### withMocks (Deprecated)
package/dist/index.d.cts CHANGED
@@ -84,6 +84,7 @@ interface Config<UserInteraction extends InteractionDescriptor = InteractionDesc
84
84
  handleQueryParams?: boolean;
85
85
  interaction?: InteractionOptions<UserInteraction>;
86
86
  warnOnPendingRequests?: boolean;
87
+ defaultResponses?: WrapResponse[];
87
88
  }
88
89
  interface BrowserHistory extends History {
89
90
  push: (path: string, historyState?: object) => void;
package/dist/index.d.ts CHANGED
@@ -84,6 +84,7 @@ interface Config<UserInteraction extends InteractionDescriptor = InteractionDesc
84
84
  handleQueryParams?: boolean;
85
85
  interaction?: InteractionOptions<UserInteraction>;
86
86
  warnOnPendingRequests?: boolean;
87
+ defaultResponses?: WrapResponse[];
87
88
  }
88
89
  interface BrowserHistory extends History {
89
90
  push: (path: string, historyState?: object) => void;
package/dist/index.js CHANGED
@@ -1,18 +1,18 @@
1
- "use strict";var ye=Object.create;var T=Object.defineProperty;var Re=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames;var be=Object.getPrototypeOf,Ie=Object.prototype.hasOwnProperty;var xe=(e,t)=>{for(var n in t)T(e,n,{get:t[n],enumerable:!0})},N=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of we(t))!Ie.call(e,r)&&r!==n&&T(e,r,{get:()=>t[r],enumerable:!(s=Re(t,r))||s.enumerable});return e};var E=(e,t,n)=>(n=e!=null?ye(be(e)):{},N(t||!e||!e.__esModule?T(n,"default",{value:e,enumerable:!0}):n,e)),ke=e=>N(T({},"__esModule",{value:!0}),e);var et={};xe(et,{assertions:()=>Ze,configure:()=>Me,getConfig:()=>h,matchers:()=>Ze,wrap:()=>He});module.exports=ke(et);var K=E(require("react"),1);var d=E(require("chalk"),1);var v=E(require("object-hash"),1);var j=require("@testing-library/react"),A={defaultHost:"",extend:{},mount:j.render,changeRoute:e=>window.history.replaceState(null,"",e)};function Me(e){A={...A,...e}}var h=()=>({...A});var $=e=>t=>{let{method:n="GET",path:s,host:r=h().defaultHost,requestBody:o=void 0,catchParams:i}=t,l=r+s,c=!h().handleQueryParams||i,u=(0,v.default)({url:c?l:l.split("?")[0],method:n.toUpperCase(),requestBody:o}),a;return"_bodyInit"in e&&e._bodyInit!==void 0&&(a=JSON.parse(e._bodyInit)),(0,v.default)({url:c?e.url:e.url.split("?")[0],method:e.method,requestBody:a})===u};var _=async()=>{let e={json:()=>Promise.resolve(),status:200,ok:!0,headers:new Headers({"Content-Type":"application/json"})};return Promise.resolve(e)},L=async e=>{let{responseBody:t,status:n=200,headers:s={},delay:r}=e,o={json:()=>Promise.resolve(t),status:n,ok:n>=200&&n<=299,headers:new Headers({"Content-Type":"application/json",...s})};return r?new Promise(i=>setTimeout(()=>i(o),r)):Promise.resolve(o)},Oe=e=>console.warn(`
2
- ${d.default.white.bold.bgRed("wrapito")} ${d.default.redBright.bold("cannot find any mock matching:")}
3
- ${d.default.greenBright(`URL: ${e.url}`)}
4
- ${d.default.greenBright(`METHOD: ${e.method?.toLowerCase()}`)}
5
- ${d.default.greenBright(`REQUEST BODY: ${e._bodyInit}`)}
6
- `),F=async(e,t,n)=>{let s=e.find($(t));if(!s)return n&&Oe(t),_();let{multipleResponses:r}=s;if(!r)return L(s);let o=r.find(i=>!i.hasBeenReturned);if(!o){n&&Te(s);return}return o.hasBeenReturned=!0,L(o)},G=(e=[],t=!1)=>{global.window.fetch.mockImplementation((s,r)=>{if(typeof s=="string"){let i=new Request(s,r);return F(e,i,t)}return F(e,s,t)})},Te=e=>{let t=`\u{1F32F} Wrapito: Missing response in the multipleResponses array for path ${e.path} and method ${e.method}.`,n=d.default.greenBright(t);console.warn(n)},V=e=>{let t=global.window.fetch.getMockImplementation();global.window.fetch.mockImplementation((n,s)=>{let r=typeof n=="string"?n:n.url,o=s?.method||(typeof n!="string"?n.method:"GET");return console.warn(`
7
- ${d.default.white.bold.bgYellow(" \u{1F32F} wrapito ")}
8
- ${d.default.yellowBright.bold("\u26A0\uFE0F pending request detected after test finished:")}
9
- ${d.default.greenBright(`URL: ${r}`)}
10
- ${d.default.greenBright(`METHOD: ${o?.toLowerCase()}`)}
11
- ${e?` ${d.default.greenBright(`TEST: ${e}`)}
12
- `:""}`),t?t(n,s):_()})};var C,R=e=>{C={...C,...e}},w=()=>({...C});function q(e,t){if(!e)throw new Error(t)}function I(e,t){return typeof t===e}function Ee(e){return e instanceof Promise}function D(e,t,n){Object.defineProperty(e,t,n)}function x(e,t,n){Object.defineProperty(e,t,{value:n})}var M=Symbol.for("tinyspy:spy"),qe=new Set,Pe=e=>{e.called=!1,e.callCount=0,e.calls=[],e.results=[],e.next=[]},Ue=e=>(D(e,M,{value:{reset:()=>Pe(e[M])}}),e[M]),P=e=>e[M]||Ue(e);function We(e){q(I("function",e)||I("undefined",e),"cannot spy on a non-function value");let t=function(...s){let r=P(t);r.called=!0,r.callCount++,r.calls.push(s);let o=r.next.shift();if(o){r.results.push(o);let[u,a]=o;if(u==="ok")return a;throw a}let i,l="ok";if(r.impl)try{new.target?i=Reflect.construct(r.impl,s,new.target):i=r.impl.apply(this,s),l="ok"}catch(u){throw i=u,l="error",r.results.push([l,u]),u}let c=[l,i];if(Ee(i)){let u=i.then(a=>c[1]=a).catch(a=>{throw c[0]="error",c[1]=a,a});Object.assign(u,i),i=u}return r.results.push(c),i};x(t,"_isMockFunction",!0),x(t,"length",e?e.length:0),x(t,"name",e&&e.name||"spy");let n=P(t);return n.reset(),n.impl=e,t}var Q=(e,t)=>Object.getOwnPropertyDescriptor(e,t),J=(e,t)=>{t!=null&&typeof t=="function"&&t.prototype!=null&&Object.setPrototypeOf(e.prototype,t.prototype)};function Y(e,t,n){q(!I("undefined",e),"spyOn could not find an object to spy upon"),q(I("object",e)||I("function",e),"cannot spyOn on a primitive value");let[s,r]=(()=>{if(!I("object",t))return[t,"value"];if("getter"in t&&"setter"in t)throw new Error("cannot spy on both getter and setter");if("getter"in t)return[t.getter,"get"];if("setter"in t)return[t.setter,"set"];throw new Error("specify getter or setter to spy on")})(),o=Q(e,s),i=Object.getPrototypeOf(e),l=i&&Q(i,s),c=o||l;q(c||s in e,`${String(s)} does not exist`);let u=!1;r==="value"&&c&&!c.value&&c.get&&(r="get",u=!0,n=c.get());let a;c?a=c[r]:r!=="value"?a=()=>e[s]:a=e[s],n||(n=a);let m=We(n);r==="value"&&J(m,a);let p=f=>{let{value:k,...W}=c||{configurable:!0,writable:!0};r!=="value"&&delete W.writable,W[r]=f,D(e,s,W)},y=()=>c?D(e,s,c):p(a),g=m[M];return x(g,"restore",y),x(g,"getOriginal",()=>u?a():a),x(g,"willCall",f=>(g.impl=f,m)),p(u?()=>(J(m,n),m):m),qe.add(m),m}var ve=new Set,Ce=0;function De(e){let t=e,n,s=[],r=[],o=P(e),i={get calls(){return o.calls},get instances(){return s},get invocationCallOrder(){return r},get results(){return o.results.map(([p,y])=>({type:p==="error"?"throw":"return",value:y}))},get lastCall(){return o.calls[o.calls.length-1]}},l=[],c=!1;function u(...p){return s.push(this),r.push(++Ce),(c?n:l.shift()||n||o.getOriginal()||(()=>{})).apply(this,p)}let a=t.name;t.getMockName=()=>a||"vi.fn()",t.mockName=p=>(a=p,t),t.mockClear=()=>(o.reset(),s=[],r=[],t),t.mockReset=()=>(t.mockClear(),n=()=>{},l=[],t),t.mockRestore=()=>(t.mockReset(),o.restore(),n=void 0,t),t.getMockImplementation=()=>n,t.mockImplementation=p=>(n=p,o.willCall(u),t),t.mockImplementationOnce=p=>(l.push(p),t);function m(p,y){let g=n;n=p,o.willCall(u),c=!0;let f=()=>{n=g,c=!1},k=y();return k instanceof Promise?k.then(()=>(f(),t)):(f(),t)}return t.withImplementation=m,t.mockReturnThis=()=>t.mockImplementation(function(){return this}),t.mockReturnValue=p=>t.mockImplementation(()=>p),t.mockReturnValueOnce=p=>t.mockImplementationOnce(()=>p),t.mockResolvedValue=p=>t.mockImplementation(()=>Promise.resolve(p)),t.mockResolvedValueOnce=p=>t.mockImplementationOnce(()=>Promise.resolve(p)),t.mockRejectedValue=p=>t.mockImplementation(()=>Promise.reject(p)),t.mockRejectedValueOnce=p=>t.mockImplementationOnce(()=>Promise.reject(p)),Object.defineProperty(t,"mock",{get:()=>i}),o.willCall(u),ve.add(t),t}var z=e=>De(Y({spy:e||(()=>{})},"spy"));beforeEach(()=>{global.fetch=z()});afterEach(()=>{let{warnOnPendingRequests:e}=h();if(e){let t=expect.getState?.()?.currentTestName;V(t)}});var He=e=>(R({Component:e,responses:[],props:{},path:"",hasPath:!1,interactionConfig:void 0,debug:process.env.npm_config_debugRequests==="true"}),b()),b=()=>{let e=je();return{withProps:$e,withNetwork:Fe,withInteraction:Le,atPath:_e,debugRequests:Ge,mount:Ve,...e}},Se=e=>{let t=w(),n=[...t.responses,...e];R({...t,responses:n})},Be=(e,t)=>(t({addResponses:Se},e),b()),Ne=(e,t)=>{let{extend:n}=h(),s=n[t];return{...e,[t]:(...r)=>Be(r,s)}},je=()=>{let{extend:e}=h();return Object.keys(e).reduce(Ne,{})},$e=e=>{let t=w();return R({...t,props:e}),b()},Le=e=>{let t=w();return R({...t,interactionConfig:e}),b()},Fe=(e=[])=>{let t=w(),n=Array.isArray(e)?e:[e];return R({...t,responses:[...t.responses,...n]}),b()},_e=(e,t)=>{let n=w();return R({...n,historyState:t,path:e,hasPath:!0}),b()},Ge=()=>{let e=w();return R({...e,debug:!0}),b()},Ve=()=>{let{portal:e,portals:t,changeRoute:n,history:s,mount:r,interaction:o}=h(),{Component:i,props:l,responses:c,path:u,hasPath:a,debug:m,historyState:p,interactionConfig:y}=w(),g=i;e&&X(e),t&&Qe(t),a&&s&&(console.warn("wrapito WARNING: history is DEPRECATED. Pass a changeRoute function to the config instead."),console.warn("Read about changeRoute in: https://github.com/mercadona/wrapito#changeRoute"),s.push(u,p)),a&&!s&&n(u),G(c,m);let f=r(K.createElement(g,{...l}));if(o){let k=o.setup?o.setup(o.userLib,y):o.userLib;return{...f,user:k}}return{...f,user:void 0}},X=e=>{if(document.getElementById(e))return;let t=document.createElement("div");t.setAttribute("id",e),t.setAttribute("data-testid",e),document.body.appendChild(t)},Qe=e=>{e.forEach(t=>{X(t)})};var H=require("jest-diff"),S=(e,t)=>{let n=t?.host?`\u{1F32F} Wrapito: ${t?.host}${e} ain't got called`:`\u{1F32F} Wrapito: ${e} ain't got called`;return{pass:!1,message:()=>n}},Z=(e,t,n)=>({pass:!1,message:()=>`\u{1F32F} Wrapito: ${e} is called ${n} times, you expected ${t} times`}),ee=(e,t)=>({pass:!1,message:()=>`\u{1F32F} Wrapito: Fetch method does not match, expected ${e} received ${t??"none"}`}),te=(e,t)=>{let n=t.map(s=>(0,H.diff)(e,s)).join(`
1
+ "use strict";var ye=Object.create;var T=Object.defineProperty;var Re=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames;var be=Object.getPrototypeOf,Ie=Object.prototype.hasOwnProperty;var xe=(e,t)=>{for(var n in t)T(e,n,{get:t[n],enumerable:!0})},j=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of we(t))!Ie.call(e,r)&&r!==n&&T(e,r,{get:()=>t[r],enumerable:!(s=Re(t,r))||s.enumerable});return e};var E=(e,t,n)=>(n=e!=null?ye(be(e)):{},j(t||!e||!e.__esModule?T(n,"default",{value:e,enumerable:!0}):n,e)),ke=e=>j(T({},"__esModule",{value:!0}),e);var nt={};xe(nt,{assertions:()=>tt,configure:()=>Me,getConfig:()=>m,matchers:()=>tt,wrap:()=>He});module.exports=ke(nt);var K=E(require("react"),1);var g=E(require("chalk"),1);var A=E(require("object-hash"),1);var N=require("@testing-library/react"),v={defaultHost:"",extend:{},mount:N.render,changeRoute:e=>window.history.replaceState(null,"",e)};function Me(e){v={...v,...e}}var m=()=>({...v});var $=e=>t=>{let{method:n="GET",path:s,host:r=m().defaultHost,requestBody:o=void 0,catchParams:a}=t,l=r+s,c=!m().handleQueryParams||a,u=(0,A.default)({url:c?l:l.split("?")[0],method:n.toUpperCase(),requestBody:o}),i;return"_bodyInit"in e&&e._bodyInit!==void 0&&(i=JSON.parse(e._bodyInit)),(0,A.default)({url:c?e.url:e.url.split("?")[0],method:e.method,requestBody:i})===u};var _=async()=>{let e={json:()=>Promise.resolve(),status:200,ok:!0,headers:new Headers({"Content-Type":"application/json"})};return Promise.resolve(e)},L=async e=>{let{responseBody:t,status:n=200,headers:s={},delay:r}=e,o={json:()=>Promise.resolve(t),status:n,ok:n>=200&&n<=299,headers:new Headers({"Content-Type":"application/json",...s})};return r?new Promise(a=>setTimeout(()=>a(o),r)):Promise.resolve(o)},Oe=e=>console.warn(`
2
+ ${g.default.white.bold.bgRed("wrapito")} ${g.default.redBright.bold("cannot find any mock matching:")}
3
+ ${g.default.greenBright(`URL: ${e.url}`)}
4
+ ${g.default.greenBright(`METHOD: ${e.method?.toLowerCase()}`)}
5
+ ${g.default.greenBright(`REQUEST BODY: ${e._bodyInit}`)}
6
+ `),F=async(e,t,n)=>{let s=e.find($(t));if(!s)return n&&Oe(t),_();let{multipleResponses:r}=s;if(!r)return L(s);let o=r.find(a=>!a.hasBeenReturned);if(!o){n&&Te(s);return}return o.hasBeenReturned=!0,L(o)},G=(e=[],t=!1)=>{global.window.fetch.mockImplementation((s,r)=>{if(typeof s=="string"){let a=new Request(s,r);return F(e,a,t)}return F(e,s,t)})},Te=e=>{let t=`\u{1F32F} Wrapito: Missing response in the multipleResponses array for path ${e.path} and method ${e.method}.`,n=g.default.greenBright(t);console.warn(n)},V=e=>{let t=global.window.fetch.getMockImplementation();global.window.fetch.mockImplementation((n,s)=>{let r=typeof n=="string"?n:n.url,o=s?.method||(typeof n!="string"?n.method:"GET");return console.warn(`
7
+ ${g.default.white.bold.bgYellow(" \u{1F32F} wrapito ")}
8
+ ${g.default.yellowBright.bold("\u26A0\uFE0F pending request detected after test finished:")}
9
+ ${g.default.greenBright(`URL: ${r}`)}
10
+ ${g.default.greenBright(`METHOD: ${o?.toLowerCase()}`)}
11
+ ${e?` ${g.default.greenBright(`TEST: ${e}`)}
12
+ `:""}`),t?t(n,s):_()})};var C,R=e=>{C={...C,...e}},w=()=>({...C});function q(e,t){if(!e)throw new Error(t)}function I(e,t){return typeof t===e}function Ee(e){return e instanceof Promise}function D(e,t,n){Object.defineProperty(e,t,n)}function x(e,t,n){Object.defineProperty(e,t,{value:n})}var M=Symbol.for("tinyspy:spy"),qe=new Set,Pe=e=>{e.called=!1,e.callCount=0,e.calls=[],e.results=[],e.next=[]},Ue=e=>(D(e,M,{value:{reset:()=>Pe(e[M])}}),e[M]),P=e=>e[M]||Ue(e);function We(e){q(I("function",e)||I("undefined",e),"cannot spy on a non-function value");let t=function(...s){let r=P(t);r.called=!0,r.callCount++,r.calls.push(s);let o=r.next.shift();if(o){r.results.push(o);let[u,i]=o;if(u==="ok")return i;throw i}let a,l="ok";if(r.impl)try{new.target?a=Reflect.construct(r.impl,s,new.target):a=r.impl.apply(this,s),l="ok"}catch(u){throw a=u,l="error",r.results.push([l,u]),u}let c=[l,a];if(Ee(a)){let u=a.then(i=>c[1]=i).catch(i=>{throw c[0]="error",c[1]=i,i});Object.assign(u,a),a=u}return r.results.push(c),a};x(t,"_isMockFunction",!0),x(t,"length",e?e.length:0),x(t,"name",e&&e.name||"spy");let n=P(t);return n.reset(),n.impl=e,t}var Q=(e,t)=>Object.getOwnPropertyDescriptor(e,t),J=(e,t)=>{t!=null&&typeof t=="function"&&t.prototype!=null&&Object.setPrototypeOf(e.prototype,t.prototype)};function Y(e,t,n){q(!I("undefined",e),"spyOn could not find an object to spy upon"),q(I("object",e)||I("function",e),"cannot spyOn on a primitive value");let[s,r]=(()=>{if(!I("object",t))return[t,"value"];if("getter"in t&&"setter"in t)throw new Error("cannot spy on both getter and setter");if("getter"in t)return[t.getter,"get"];if("setter"in t)return[t.setter,"set"];throw new Error("specify getter or setter to spy on")})(),o=Q(e,s),a=Object.getPrototypeOf(e),l=a&&Q(a,s),c=o||l;q(c||s in e,`${String(s)} does not exist`);let u=!1;r==="value"&&c&&!c.value&&c.get&&(r="get",u=!0,n=c.get());let i;c?i=c[r]:r!=="value"?i=()=>e[s]:i=e[s],n||(n=i);let d=We(n);r==="value"&&J(d,i);let p=f=>{let{value:k,...W}=c||{configurable:!0,writable:!0};r!=="value"&&delete W.writable,W[r]=f,D(e,s,W)},y=()=>c?D(e,s,c):p(i),h=d[M];return x(h,"restore",y),x(h,"getOriginal",()=>u?i():i),x(h,"willCall",f=>(h.impl=f,d)),p(u?()=>(J(d,n),d):d),qe.add(d),d}var Ae=new Set,Ce=0;function De(e){let t=e,n,s=[],r=[],o=P(e),a={get calls(){return o.calls},get instances(){return s},get invocationCallOrder(){return r},get results(){return o.results.map(([p,y])=>({type:p==="error"?"throw":"return",value:y}))},get lastCall(){return o.calls[o.calls.length-1]}},l=[],c=!1;function u(...p){return s.push(this),r.push(++Ce),(c?n:l.shift()||n||o.getOriginal()||(()=>{})).apply(this,p)}let i=t.name;t.getMockName=()=>i||"vi.fn()",t.mockName=p=>(i=p,t),t.mockClear=()=>(o.reset(),s=[],r=[],t),t.mockReset=()=>(t.mockClear(),n=()=>{},l=[],t),t.mockRestore=()=>(t.mockReset(),o.restore(),n=void 0,t),t.getMockImplementation=()=>n,t.mockImplementation=p=>(n=p,o.willCall(u),t),t.mockImplementationOnce=p=>(l.push(p),t);function d(p,y){let h=n;n=p,o.willCall(u),c=!0;let f=()=>{n=h,c=!1},k=y();return k instanceof Promise?k.then(()=>(f(),t)):(f(),t)}return t.withImplementation=d,t.mockReturnThis=()=>t.mockImplementation(function(){return this}),t.mockReturnValue=p=>t.mockImplementation(()=>p),t.mockReturnValueOnce=p=>t.mockImplementationOnce(()=>p),t.mockResolvedValue=p=>t.mockImplementation(()=>Promise.resolve(p)),t.mockResolvedValueOnce=p=>t.mockImplementationOnce(()=>Promise.resolve(p)),t.mockRejectedValue=p=>t.mockImplementation(()=>Promise.reject(p)),t.mockRejectedValueOnce=p=>t.mockImplementationOnce(()=>Promise.reject(p)),Object.defineProperty(t,"mock",{get:()=>a}),o.willCall(u),Ae.add(t),t}var z=e=>De(Y({spy:e||(()=>{})},"spy"));beforeEach(()=>{global.fetch=z()});afterEach(()=>{let{warnOnPendingRequests:e}=m();if(e){let t=expect.getState?.()?.currentTestName;V(t)}});var He=e=>(R({Component:e,responses:[],props:{},path:"",hasPath:!1,interactionConfig:void 0,debug:process.env.npm_config_debugRequests==="true"}),b()),b=()=>{let e=Ne();return{withProps:$e,withNetwork:Fe,withInteraction:Le,atPath:_e,debugRequests:Ge,mount:Je,...e}},Be=e=>{let t=w(),n=[...t.responses,...e];R({...t,responses:n})},Se=(e,t)=>(t({addResponses:Be},e),b()),je=(e,t)=>{let{extend:n}=m(),s=n[t];return{...e,[t]:(...r)=>Se(r,s)}},Ne=()=>{let{extend:e}=m();return Object.keys(e).reduce(je,{})},$e=e=>{let t=w();return R({...t,props:e}),b()},Le=e=>{let t=w();return R({...t,interactionConfig:e}),b()},Fe=(e=[])=>{let t=w(),n=Array.isArray(e)?e:[e];return R({...t,responses:[...t.responses,...n]}),b()},_e=(e,t)=>{let n=w();return R({...n,historyState:t,path:e,hasPath:!0}),b()},Ge=()=>{let e=w();return R({...e,debug:!0}),b()},Ve=e=>{let{defaultResponses:t=[]}=m();return[...e,...t]},Qe=(e,t,n,s,r)=>{if(e){if(s){console.warn("wrapito WARNING: history is DEPRECATED. Pass a changeRoute function to the config instead."),console.warn("Read about changeRoute in: https://github.com/mercadona/wrapito#changeRoute"),s.push(t,n);return}r(t)}},Je=()=>{let{portal:e,portals:t,changeRoute:n,history:s,mount:r,interaction:o}=m(),{Component:a,props:l,responses:c,path:u,hasPath:i,debug:d,historyState:p,interactionConfig:y}=w(),h=a;e&&X(e),t&&Ye(t),Qe(i,u,p,s,n),G(Ve(c),d);let f=r(K.createElement(h,{...l}));if(o){let k=o.setup?o.setup(o.userLib,y):o.userLib;return{...f,user:k}}return{...f,user:void 0}},X=e=>{if(document.getElementById(e))return;let t=document.createElement("div");t.setAttribute("id",e),t.setAttribute("data-testid",e),document.body.appendChild(t)},Ye=e=>{e.forEach(t=>{X(t)})};var H=require("jest-diff"),B=(e,t)=>{let n=t?.host?`\u{1F32F} Wrapito: ${t?.host}${e} ain't got called`:`\u{1F32F} Wrapito: ${e} ain't got called`;return{pass:!1,message:()=>n}},Z=(e,t,n)=>({pass:!1,message:()=>`\u{1F32F} Wrapito: ${e} is called ${n} times, you expected ${t} times`}),ee=(e,t)=>({pass:!1,message:()=>`\u{1F32F} Wrapito: Fetch method does not match, expected ${e} received ${t??"none"}`}),te=(e,t)=>{let n=t.map(s=>(0,H.diff)(e,s)).join(`
13
13
 
14
14
  `);return{pass:!1,message:()=>`\u{1F32F} Wrapito: Fetch body does not match.
15
15
  ${n}`}},ne=(e,t)=>{let n=t.find(s=>e!==s);return{pass:!1,message:()=>`\u{1F32F} Wrapito: Host request does not match, expected ${e} received ${n}`}},se=(e,t)=>{let n=t.map(s=>(0,H.diff)(e,s)).join(`
16
16
 
17
17
  `);return{pass:!1,message:()=>`\u{1F32F} Wrapito: Fetch headers do not match.
18
- ${n}`}},re=()=>({pass:!1,message:()=>"\u{1F32F} Wrapito: Unable to find body."}),B=()=>({pass:!0,message:()=>"Test passing"}),oe=(e,t)=>{let n=t?.host?`\u{1F32F} Wrapito: ${t.host}${e} is called`:`\u{1F32F} Wrapito: ${e} is called`;return{pass:!0,message:()=>n}};var ae=E(require("deep-equal"),1);var ie=()=>{let e=h().defaultHost;return e?.includes("http")?e:"https://default.com"},Je=(e="",t,n)=>t.includes(n)?t:e+t,O=e=>e instanceof Request,Ye=e=>O(e)?e.url:e,U=(e,t={method:"GET"})=>fetch.mock.calls.filter(([s])=>{let r=Ye(s),o=ie(),i=new URL(r,o),l=Je(t?.host,e,o),c=t?.host||o,u=new URL(l,c),a=i.pathname===u.pathname,m=i.search===u.search,p=i.host===u.host;return u.search?a&&m:t?.host?a&&p:a}),ce=e=>e.flat(1).filter(O).map(t=>t.method),pe=e=>e.flat(1).filter(O).map(t=>t._bodyInit?JSON.parse(t._bodyInit):{}),ue=e=>e.flat(1).filter(O).map(t=>new URL(t.url,ie()).hostname),le=e=>e.flat(1).filter(O).map(t=>{let n={};return t.headers.forEach((s,r)=>{n[r]=s}),n}),me=(e,t)=>e&&!t.includes(e),de=(e,t)=>t.map(s=>(0,ae.default)(e,s)).every(s=>s===!1),he=(e,t)=>t.every(s=>s!==e),ge=(e,t)=>t.every(s=>Object.entries(e).some(([r,o])=>s[r.toLowerCase()]!==o)),fe=e=>e.length===0;var ze=(e,t)=>{let n=U(e);if(fe(n))return S(e);let s=ce(n),r=t?.method;if(me(r,s))return ee(r,s);let o=pe(n),i=t?.body;if(!i)return re();if(de(i,o))return te(i,o);let l=ue(n),c=t?.host;if(c&&he(c,l))return ne(c,l);let u=le(n),a=t?.headers;return a&&ge(a,u)?se(a,u):B()},Ke=(e,t={method:"GET"})=>U(e,t).length?oe(e,t):S(e,t),Xe=(e,t,n={method:"GET"})=>{let s=U(e,n);return s.length!==t?Z(e,t,s.length):B()},Ze={toHaveBeenFetched:Ke,toHaveBeenFetchedWith:ze,toHaveBeenFetchedTimes:Xe};0&&(module.exports={assertions,configure,getConfig,matchers,wrap});
18
+ ${n}`}},re=()=>({pass:!1,message:()=>"\u{1F32F} Wrapito: Unable to find body."}),S=()=>({pass:!0,message:()=>"Test passing"}),oe=(e,t)=>{let n=t?.host?`\u{1F32F} Wrapito: ${t.host}${e} is called`:`\u{1F32F} Wrapito: ${e} is called`;return{pass:!0,message:()=>n}};var ae=E(require("deep-equal"),1);var ie=()=>{let e=m().defaultHost;return e?.includes("http")?e:"https://default.com"},ze=(e="",t,n)=>t.includes(n)?t:e+t,O=e=>e instanceof Request,Ke=e=>O(e)?e.url:e,U=(e,t={method:"GET"})=>fetch.mock.calls.filter(([s])=>{let r=Ke(s),o=ie(),a=new URL(r,o),l=ze(t?.host,e,o),c=t?.host||o,u=new URL(l,c),i=a.pathname===u.pathname,d=a.search===u.search,p=a.host===u.host;return u.search?i&&d:t?.host?i&&p:i}),ce=e=>e.flat(1).filter(O).map(t=>t.method),pe=e=>e.flat(1).filter(O).map(t=>t._bodyInit?JSON.parse(t._bodyInit):{}),ue=e=>e.flat(1).filter(O).map(t=>new URL(t.url,ie()).hostname),le=e=>e.flat(1).filter(O).map(t=>{let n={};return t.headers.forEach((s,r)=>{n[r]=s}),n}),de=(e,t)=>e&&!t.includes(e),me=(e,t)=>t.map(s=>(0,ae.default)(e,s)).every(s=>s===!1),ge=(e,t)=>t.every(s=>s!==e),he=(e,t)=>t.every(s=>Object.entries(e).some(([r,o])=>s[r.toLowerCase()]!==o)),fe=e=>e.length===0;var Xe=(e,t)=>{let n=U(e);if(fe(n))return B(e);let s=ce(n),r=t?.method;if(de(r,s))return ee(r,s);let o=pe(n),a=t?.body;if(!a)return re();if(me(a,o))return te(a,o);let l=ue(n),c=t?.host;if(c&&ge(c,l))return ne(c,l);let u=le(n),i=t?.headers;return i&&he(i,u)?se(i,u):S()},Ze=(e,t={method:"GET"})=>U(e,t).length?oe(e,t):B(e,t),et=(e,t,n={method:"GET"})=>{let s=U(e,n);return s.length!==t?Z(e,t,s.length):S()},tt={toHaveBeenFetched:Ze,toHaveBeenFetchedWith:Xe,toHaveBeenFetchedTimes:et};0&&(module.exports={assertions,configure,getConfig,matchers,wrap});
package/dist/index.mjs CHANGED
@@ -1,18 +1,18 @@
1
- import*as V from"react";import d from"chalk";import D from"object-hash";import{render as me}from"@testing-library/react";var U={defaultHost:"",extend:{},mount:me,changeRoute:e=>window.history.replaceState(null,"",e)};function Le(e){U={...U,...e}}var h=()=>({...U});var H=e=>t=>{let{method:n="GET",path:s,host:r=h().defaultHost,requestBody:o=void 0,catchParams:i}=t,l=r+s,c=!h().handleQueryParams||i,u=D({url:c?l:l.split("?")[0],method:n.toUpperCase(),requestBody:o}),a;return"_bodyInit"in e&&e._bodyInit!==void 0&&(a=JSON.parse(e._bodyInit)),D({url:c?e.url:e.url.split("?")[0],method:e.method,requestBody:a})===u};var N=async()=>{let e={json:()=>Promise.resolve(),status:200,ok:!0,headers:new Headers({"Content-Type":"application/json"})};return Promise.resolve(e)},S=async e=>{let{responseBody:t,status:n=200,headers:s={},delay:r}=e,o={json:()=>Promise.resolve(t),status:n,ok:n>=200&&n<=299,headers:new Headers({"Content-Type":"application/json",...s})};return r?new Promise(i=>setTimeout(()=>i(o),r)):Promise.resolve(o)},de=e=>console.warn(`
2
- ${d.white.bold.bgRed("wrapito")} ${d.redBright.bold("cannot find any mock matching:")}
3
- ${d.greenBright(`URL: ${e.url}`)}
4
- ${d.greenBright(`METHOD: ${e.method?.toLowerCase()}`)}
5
- ${d.greenBright(`REQUEST BODY: ${e._bodyInit}`)}
6
- `),B=async(e,t,n)=>{let s=e.find(H(t));if(!s)return n&&de(t),N();let{multipleResponses:r}=s;if(!r)return S(s);let o=r.find(i=>!i.hasBeenReturned);if(!o){n&&he(s);return}return o.hasBeenReturned=!0,S(o)},j=(e=[],t=!1)=>{global.window.fetch.mockImplementation((s,r)=>{if(typeof s=="string"){let i=new Request(s,r);return B(e,i,t)}return B(e,s,t)})},he=e=>{let t=`\u{1F32F} Wrapito: Missing response in the multipleResponses array for path ${e.path} and method ${e.method}.`,n=d.greenBright(t);console.warn(n)},$=e=>{let t=global.window.fetch.getMockImplementation();global.window.fetch.mockImplementation((n,s)=>{let r=typeof n=="string"?n:n.url,o=s?.method||(typeof n!="string"?n.method:"GET");return console.warn(`
7
- ${d.white.bold.bgYellow(" \u{1F32F} wrapito ")}
8
- ${d.yellowBright.bold("\u26A0\uFE0F pending request detected after test finished:")}
9
- ${d.greenBright(`URL: ${r}`)}
10
- ${d.greenBright(`METHOD: ${o?.toLowerCase()}`)}
11
- ${e?` ${d.greenBright(`TEST: ${e}`)}
12
- `:""}`),t?t(n,s):N()})};var W,R=e=>{W={...W,...e}},w=()=>({...W});function T(e,t){if(!e)throw new Error(t)}function I(e,t){return typeof t===e}function ge(e){return e instanceof Promise}function A(e,t,n){Object.defineProperty(e,t,n)}function x(e,t,n){Object.defineProperty(e,t,{value:n})}var M=Symbol.for("tinyspy:spy"),fe=new Set,ye=e=>{e.called=!1,e.callCount=0,e.calls=[],e.results=[],e.next=[]},Re=e=>(A(e,M,{value:{reset:()=>ye(e[M])}}),e[M]),E=e=>e[M]||Re(e);function we(e){T(I("function",e)||I("undefined",e),"cannot spy on a non-function value");let t=function(...s){let r=E(t);r.called=!0,r.callCount++,r.calls.push(s);let o=r.next.shift();if(o){r.results.push(o);let[u,a]=o;if(u==="ok")return a;throw a}let i,l="ok";if(r.impl)try{new.target?i=Reflect.construct(r.impl,s,new.target):i=r.impl.apply(this,s),l="ok"}catch(u){throw i=u,l="error",r.results.push([l,u]),u}let c=[l,i];if(ge(i)){let u=i.then(a=>c[1]=a).catch(a=>{throw c[0]="error",c[1]=a,a});Object.assign(u,i),i=u}return r.results.push(c),i};x(t,"_isMockFunction",!0),x(t,"length",e?e.length:0),x(t,"name",e&&e.name||"spy");let n=E(t);return n.reset(),n.impl=e,t}var L=(e,t)=>Object.getOwnPropertyDescriptor(e,t),F=(e,t)=>{t!=null&&typeof t=="function"&&t.prototype!=null&&Object.setPrototypeOf(e.prototype,t.prototype)};function _(e,t,n){T(!I("undefined",e),"spyOn could not find an object to spy upon"),T(I("object",e)||I("function",e),"cannot spyOn on a primitive value");let[s,r]=(()=>{if(!I("object",t))return[t,"value"];if("getter"in t&&"setter"in t)throw new Error("cannot spy on both getter and setter");if("getter"in t)return[t.getter,"get"];if("setter"in t)return[t.setter,"set"];throw new Error("specify getter or setter to spy on")})(),o=L(e,s),i=Object.getPrototypeOf(e),l=i&&L(i,s),c=o||l;T(c||s in e,`${String(s)} does not exist`);let u=!1;r==="value"&&c&&!c.value&&c.get&&(r="get",u=!0,n=c.get());let a;c?a=c[r]:r!=="value"?a=()=>e[s]:a=e[s],n||(n=a);let m=we(n);r==="value"&&F(m,a);let p=f=>{let{value:k,...P}=c||{configurable:!0,writable:!0};r!=="value"&&delete P.writable,P[r]=f,A(e,s,P)},y=()=>c?A(e,s,c):p(a),g=m[M];return x(g,"restore",y),x(g,"getOriginal",()=>u?a():a),x(g,"willCall",f=>(g.impl=f,m)),p(u?()=>(F(m,n),m):m),fe.add(m),m}var Ie=new Set,xe=0;function ke(e){let t=e,n,s=[],r=[],o=E(e),i={get calls(){return o.calls},get instances(){return s},get invocationCallOrder(){return r},get results(){return o.results.map(([p,y])=>({type:p==="error"?"throw":"return",value:y}))},get lastCall(){return o.calls[o.calls.length-1]}},l=[],c=!1;function u(...p){return s.push(this),r.push(++xe),(c?n:l.shift()||n||o.getOriginal()||(()=>{})).apply(this,p)}let a=t.name;t.getMockName=()=>a||"vi.fn()",t.mockName=p=>(a=p,t),t.mockClear=()=>(o.reset(),s=[],r=[],t),t.mockReset=()=>(t.mockClear(),n=()=>{},l=[],t),t.mockRestore=()=>(t.mockReset(),o.restore(),n=void 0,t),t.getMockImplementation=()=>n,t.mockImplementation=p=>(n=p,o.willCall(u),t),t.mockImplementationOnce=p=>(l.push(p),t);function m(p,y){let g=n;n=p,o.willCall(u),c=!0;let f=()=>{n=g,c=!1},k=y();return k instanceof Promise?k.then(()=>(f(),t)):(f(),t)}return t.withImplementation=m,t.mockReturnThis=()=>t.mockImplementation(function(){return this}),t.mockReturnValue=p=>t.mockImplementation(()=>p),t.mockReturnValueOnce=p=>t.mockImplementationOnce(()=>p),t.mockResolvedValue=p=>t.mockImplementation(()=>Promise.resolve(p)),t.mockResolvedValueOnce=p=>t.mockImplementationOnce(()=>Promise.resolve(p)),t.mockRejectedValue=p=>t.mockImplementation(()=>Promise.reject(p)),t.mockRejectedValueOnce=p=>t.mockImplementationOnce(()=>Promise.reject(p)),Object.defineProperty(t,"mock",{get:()=>i}),o.willCall(u),Ie.add(t),t}var G=e=>ke(_({spy:e||(()=>{})},"spy"));beforeEach(()=>{global.fetch=G()});afterEach(()=>{let{warnOnPendingRequests:e}=h();if(e){let t=expect.getState?.()?.currentTestName;$(t)}});var nt=e=>(R({Component:e,responses:[],props:{},path:"",hasPath:!1,interactionConfig:void 0,debug:process.env.npm_config_debugRequests==="true"}),b()),b=()=>{let e=Ee();return{withProps:qe,withNetwork:Ue,withInteraction:Pe,atPath:We,debugRequests:Ae,mount:ve,...e}},Me=e=>{let t=w(),n=[...t.responses,...e];R({...t,responses:n})},Oe=(e,t)=>(t({addResponses:Me},e),b()),Te=(e,t)=>{let{extend:n}=h(),s=n[t];return{...e,[t]:(...r)=>Oe(r,s)}},Ee=()=>{let{extend:e}=h();return Object.keys(e).reduce(Te,{})},qe=e=>{let t=w();return R({...t,props:e}),b()},Pe=e=>{let t=w();return R({...t,interactionConfig:e}),b()},Ue=(e=[])=>{let t=w(),n=Array.isArray(e)?e:[e];return R({...t,responses:[...t.responses,...n]}),b()},We=(e,t)=>{let n=w();return R({...n,historyState:t,path:e,hasPath:!0}),b()},Ae=()=>{let e=w();return R({...e,debug:!0}),b()},ve=()=>{let{portal:e,portals:t,changeRoute:n,history:s,mount:r,interaction:o}=h(),{Component:i,props:l,responses:c,path:u,hasPath:a,debug:m,historyState:p,interactionConfig:y}=w(),g=i;e&&Q(e),t&&Ce(t),a&&s&&(console.warn("wrapito WARNING: history is DEPRECATED. Pass a changeRoute function to the config instead."),console.warn("Read about changeRoute in: https://github.com/mercadona/wrapito#changeRoute"),s.push(u,p)),a&&!s&&n(u),j(c,m);let f=r(V.createElement(g,{...l}));if(o){let k=o.setup?o.setup(o.userLib,y):o.userLib;return{...f,user:k}}return{...f,user:void 0}},Q=e=>{if(document.getElementById(e))return;let t=document.createElement("div");t.setAttribute("id",e),t.setAttribute("data-testid",e),document.body.appendChild(t)},Ce=e=>{e.forEach(t=>{Q(t)})};import{diff as J}from"jest-diff";var v=(e,t)=>{let n=t?.host?`\u{1F32F} Wrapito: ${t?.host}${e} ain't got called`:`\u{1F32F} Wrapito: ${e} ain't got called`;return{pass:!1,message:()=>n}},Y=(e,t,n)=>({pass:!1,message:()=>`\u{1F32F} Wrapito: ${e} is called ${n} times, you expected ${t} times`}),z=(e,t)=>({pass:!1,message:()=>`\u{1F32F} Wrapito: Fetch method does not match, expected ${e} received ${t??"none"}`}),K=(e,t)=>{let n=t.map(s=>J(e,s)).join(`
1
+ import*as V from"react";import g from"chalk";import D from"object-hash";import{render as de}from"@testing-library/react";var U={defaultHost:"",extend:{},mount:de,changeRoute:e=>window.history.replaceState(null,"",e)};function _e(e){U={...U,...e}}var m=()=>({...U});var H=e=>t=>{let{method:n="GET",path:s,host:r=m().defaultHost,requestBody:o=void 0,catchParams:a}=t,l=r+s,c=!m().handleQueryParams||a,u=D({url:c?l:l.split("?")[0],method:n.toUpperCase(),requestBody:o}),i;return"_bodyInit"in e&&e._bodyInit!==void 0&&(i=JSON.parse(e._bodyInit)),D({url:c?e.url:e.url.split("?")[0],method:e.method,requestBody:i})===u};var j=async()=>{let e={json:()=>Promise.resolve(),status:200,ok:!0,headers:new Headers({"Content-Type":"application/json"})};return Promise.resolve(e)},B=async e=>{let{responseBody:t,status:n=200,headers:s={},delay:r}=e,o={json:()=>Promise.resolve(t),status:n,ok:n>=200&&n<=299,headers:new Headers({"Content-Type":"application/json",...s})};return r?new Promise(a=>setTimeout(()=>a(o),r)):Promise.resolve(o)},me=e=>console.warn(`
2
+ ${g.white.bold.bgRed("wrapito")} ${g.redBright.bold("cannot find any mock matching:")}
3
+ ${g.greenBright(`URL: ${e.url}`)}
4
+ ${g.greenBright(`METHOD: ${e.method?.toLowerCase()}`)}
5
+ ${g.greenBright(`REQUEST BODY: ${e._bodyInit}`)}
6
+ `),S=async(e,t,n)=>{let s=e.find(H(t));if(!s)return n&&me(t),j();let{multipleResponses:r}=s;if(!r)return B(s);let o=r.find(a=>!a.hasBeenReturned);if(!o){n&&ge(s);return}return o.hasBeenReturned=!0,B(o)},N=(e=[],t=!1)=>{global.window.fetch.mockImplementation((s,r)=>{if(typeof s=="string"){let a=new Request(s,r);return S(e,a,t)}return S(e,s,t)})},ge=e=>{let t=`\u{1F32F} Wrapito: Missing response in the multipleResponses array for path ${e.path} and method ${e.method}.`,n=g.greenBright(t);console.warn(n)},$=e=>{let t=global.window.fetch.getMockImplementation();global.window.fetch.mockImplementation((n,s)=>{let r=typeof n=="string"?n:n.url,o=s?.method||(typeof n!="string"?n.method:"GET");return console.warn(`
7
+ ${g.white.bold.bgYellow(" \u{1F32F} wrapito ")}
8
+ ${g.yellowBright.bold("\u26A0\uFE0F pending request detected after test finished:")}
9
+ ${g.greenBright(`URL: ${r}`)}
10
+ ${g.greenBright(`METHOD: ${o?.toLowerCase()}`)}
11
+ ${e?` ${g.greenBright(`TEST: ${e}`)}
12
+ `:""}`),t?t(n,s):j()})};var W,R=e=>{W={...W,...e}},w=()=>({...W});function T(e,t){if(!e)throw new Error(t)}function I(e,t){return typeof t===e}function he(e){return e instanceof Promise}function v(e,t,n){Object.defineProperty(e,t,n)}function x(e,t,n){Object.defineProperty(e,t,{value:n})}var M=Symbol.for("tinyspy:spy"),fe=new Set,ye=e=>{e.called=!1,e.callCount=0,e.calls=[],e.results=[],e.next=[]},Re=e=>(v(e,M,{value:{reset:()=>ye(e[M])}}),e[M]),E=e=>e[M]||Re(e);function we(e){T(I("function",e)||I("undefined",e),"cannot spy on a non-function value");let t=function(...s){let r=E(t);r.called=!0,r.callCount++,r.calls.push(s);let o=r.next.shift();if(o){r.results.push(o);let[u,i]=o;if(u==="ok")return i;throw i}let a,l="ok";if(r.impl)try{new.target?a=Reflect.construct(r.impl,s,new.target):a=r.impl.apply(this,s),l="ok"}catch(u){throw a=u,l="error",r.results.push([l,u]),u}let c=[l,a];if(he(a)){let u=a.then(i=>c[1]=i).catch(i=>{throw c[0]="error",c[1]=i,i});Object.assign(u,a),a=u}return r.results.push(c),a};x(t,"_isMockFunction",!0),x(t,"length",e?e.length:0),x(t,"name",e&&e.name||"spy");let n=E(t);return n.reset(),n.impl=e,t}var L=(e,t)=>Object.getOwnPropertyDescriptor(e,t),F=(e,t)=>{t!=null&&typeof t=="function"&&t.prototype!=null&&Object.setPrototypeOf(e.prototype,t.prototype)};function _(e,t,n){T(!I("undefined",e),"spyOn could not find an object to spy upon"),T(I("object",e)||I("function",e),"cannot spyOn on a primitive value");let[s,r]=(()=>{if(!I("object",t))return[t,"value"];if("getter"in t&&"setter"in t)throw new Error("cannot spy on both getter and setter");if("getter"in t)return[t.getter,"get"];if("setter"in t)return[t.setter,"set"];throw new Error("specify getter or setter to spy on")})(),o=L(e,s),a=Object.getPrototypeOf(e),l=a&&L(a,s),c=o||l;T(c||s in e,`${String(s)} does not exist`);let u=!1;r==="value"&&c&&!c.value&&c.get&&(r="get",u=!0,n=c.get());let i;c?i=c[r]:r!=="value"?i=()=>e[s]:i=e[s],n||(n=i);let d=we(n);r==="value"&&F(d,i);let p=f=>{let{value:k,...P}=c||{configurable:!0,writable:!0};r!=="value"&&delete P.writable,P[r]=f,v(e,s,P)},y=()=>c?v(e,s,c):p(i),h=d[M];return x(h,"restore",y),x(h,"getOriginal",()=>u?i():i),x(h,"willCall",f=>(h.impl=f,d)),p(u?()=>(F(d,n),d):d),fe.add(d),d}var Ie=new Set,xe=0;function ke(e){let t=e,n,s=[],r=[],o=E(e),a={get calls(){return o.calls},get instances(){return s},get invocationCallOrder(){return r},get results(){return o.results.map(([p,y])=>({type:p==="error"?"throw":"return",value:y}))},get lastCall(){return o.calls[o.calls.length-1]}},l=[],c=!1;function u(...p){return s.push(this),r.push(++xe),(c?n:l.shift()||n||o.getOriginal()||(()=>{})).apply(this,p)}let i=t.name;t.getMockName=()=>i||"vi.fn()",t.mockName=p=>(i=p,t),t.mockClear=()=>(o.reset(),s=[],r=[],t),t.mockReset=()=>(t.mockClear(),n=()=>{},l=[],t),t.mockRestore=()=>(t.mockReset(),o.restore(),n=void 0,t),t.getMockImplementation=()=>n,t.mockImplementation=p=>(n=p,o.willCall(u),t),t.mockImplementationOnce=p=>(l.push(p),t);function d(p,y){let h=n;n=p,o.willCall(u),c=!0;let f=()=>{n=h,c=!1},k=y();return k instanceof Promise?k.then(()=>(f(),t)):(f(),t)}return t.withImplementation=d,t.mockReturnThis=()=>t.mockImplementation(function(){return this}),t.mockReturnValue=p=>t.mockImplementation(()=>p),t.mockReturnValueOnce=p=>t.mockImplementationOnce(()=>p),t.mockResolvedValue=p=>t.mockImplementation(()=>Promise.resolve(p)),t.mockResolvedValueOnce=p=>t.mockImplementationOnce(()=>Promise.resolve(p)),t.mockRejectedValue=p=>t.mockImplementation(()=>Promise.reject(p)),t.mockRejectedValueOnce=p=>t.mockImplementationOnce(()=>Promise.reject(p)),Object.defineProperty(t,"mock",{get:()=>a}),o.willCall(u),Ie.add(t),t}var G=e=>ke(_({spy:e||(()=>{})},"spy"));beforeEach(()=>{global.fetch=G()});afterEach(()=>{let{warnOnPendingRequests:e}=m();if(e){let t=expect.getState?.()?.currentTestName;$(t)}});var rt=e=>(R({Component:e,responses:[],props:{},path:"",hasPath:!1,interactionConfig:void 0,debug:process.env.npm_config_debugRequests==="true"}),b()),b=()=>{let e=Ee();return{withProps:qe,withNetwork:Ue,withInteraction:Pe,atPath:We,debugRequests:ve,mount:De,...e}},Me=e=>{let t=w(),n=[...t.responses,...e];R({...t,responses:n})},Oe=(e,t)=>(t({addResponses:Me},e),b()),Te=(e,t)=>{let{extend:n}=m(),s=n[t];return{...e,[t]:(...r)=>Oe(r,s)}},Ee=()=>{let{extend:e}=m();return Object.keys(e).reduce(Te,{})},qe=e=>{let t=w();return R({...t,props:e}),b()},Pe=e=>{let t=w();return R({...t,interactionConfig:e}),b()},Ue=(e=[])=>{let t=w(),n=Array.isArray(e)?e:[e];return R({...t,responses:[...t.responses,...n]}),b()},We=(e,t)=>{let n=w();return R({...n,historyState:t,path:e,hasPath:!0}),b()},ve=()=>{let e=w();return R({...e,debug:!0}),b()},Ae=e=>{let{defaultResponses:t=[]}=m();return[...e,...t]},Ce=(e,t,n,s,r)=>{if(e){if(s){console.warn("wrapito WARNING: history is DEPRECATED. Pass a changeRoute function to the config instead."),console.warn("Read about changeRoute in: https://github.com/mercadona/wrapito#changeRoute"),s.push(t,n);return}r(t)}},De=()=>{let{portal:e,portals:t,changeRoute:n,history:s,mount:r,interaction:o}=m(),{Component:a,props:l,responses:c,path:u,hasPath:i,debug:d,historyState:p,interactionConfig:y}=w(),h=a;e&&Q(e),t&&He(t),Ce(i,u,p,s,n),N(Ae(c),d);let f=r(V.createElement(h,{...l}));if(o){let k=o.setup?o.setup(o.userLib,y):o.userLib;return{...f,user:k}}return{...f,user:void 0}},Q=e=>{if(document.getElementById(e))return;let t=document.createElement("div");t.setAttribute("id",e),t.setAttribute("data-testid",e),document.body.appendChild(t)},He=e=>{e.forEach(t=>{Q(t)})};import{diff as J}from"jest-diff";var A=(e,t)=>{let n=t?.host?`\u{1F32F} Wrapito: ${t?.host}${e} ain't got called`:`\u{1F32F} Wrapito: ${e} ain't got called`;return{pass:!1,message:()=>n}},Y=(e,t,n)=>({pass:!1,message:()=>`\u{1F32F} Wrapito: ${e} is called ${n} times, you expected ${t} times`}),z=(e,t)=>({pass:!1,message:()=>`\u{1F32F} Wrapito: Fetch method does not match, expected ${e} received ${t??"none"}`}),K=(e,t)=>{let n=t.map(s=>J(e,s)).join(`
13
13
 
14
14
  `);return{pass:!1,message:()=>`\u{1F32F} Wrapito: Fetch body does not match.
15
15
  ${n}`}},X=(e,t)=>{let n=t.find(s=>e!==s);return{pass:!1,message:()=>`\u{1F32F} Wrapito: Host request does not match, expected ${e} received ${n}`}},Z=(e,t)=>{let n=t.map(s=>J(e,s)).join(`
16
16
 
17
17
  `);return{pass:!1,message:()=>`\u{1F32F} Wrapito: Fetch headers do not match.
18
- ${n}`}},ee=()=>({pass:!1,message:()=>"\u{1F32F} Wrapito: Unable to find body."}),C=()=>({pass:!0,message:()=>"Test passing"}),te=(e,t)=>{let n=t?.host?`\u{1F32F} Wrapito: ${t.host}${e} is called`:`\u{1F32F} Wrapito: ${e} is called`;return{pass:!0,message:()=>n}};import De from"deep-equal";var ne=()=>{let e=h().defaultHost;return e?.includes("http")?e:"https://default.com"},He=(e="",t,n)=>t.includes(n)?t:e+t,O=e=>e instanceof Request,Se=e=>O(e)?e.url:e,q=(e,t={method:"GET"})=>fetch.mock.calls.filter(([s])=>{let r=Se(s),o=ne(),i=new URL(r,o),l=He(t?.host,e,o),c=t?.host||o,u=new URL(l,c),a=i.pathname===u.pathname,m=i.search===u.search,p=i.host===u.host;return u.search?a&&m:t?.host?a&&p:a}),se=e=>e.flat(1).filter(O).map(t=>t.method),re=e=>e.flat(1).filter(O).map(t=>t._bodyInit?JSON.parse(t._bodyInit):{}),oe=e=>e.flat(1).filter(O).map(t=>new URL(t.url,ne()).hostname),ae=e=>e.flat(1).filter(O).map(t=>{let n={};return t.headers.forEach((s,r)=>{n[r]=s}),n}),ie=(e,t)=>e&&!t.includes(e),ce=(e,t)=>t.map(s=>De(e,s)).every(s=>s===!1),pe=(e,t)=>t.every(s=>s!==e),ue=(e,t)=>t.every(s=>Object.entries(e).some(([r,o])=>s[r.toLowerCase()]!==o)),le=e=>e.length===0;var Be=(e,t)=>{let n=q(e);if(le(n))return v(e);let s=se(n),r=t?.method;if(ie(r,s))return z(r,s);let o=re(n),i=t?.body;if(!i)return ee();if(ce(i,o))return K(i,o);let l=oe(n),c=t?.host;if(c&&pe(c,l))return X(c,l);let u=ae(n),a=t?.headers;return a&&ue(a,u)?Z(a,u):C()},Ne=(e,t={method:"GET"})=>q(e,t).length?te(e,t):v(e,t),je=(e,t,n={method:"GET"})=>{let s=q(e,n);return s.length!==t?Y(e,t,s.length):C()},lt={toHaveBeenFetched:Ne,toHaveBeenFetchedWith:Be,toHaveBeenFetchedTimes:je};export{lt as assertions,Le as configure,h as getConfig,lt as matchers,nt as wrap};
18
+ ${n}`}},ee=()=>({pass:!1,message:()=>"\u{1F32F} Wrapito: Unable to find body."}),C=()=>({pass:!0,message:()=>"Test passing"}),te=(e,t)=>{let n=t?.host?`\u{1F32F} Wrapito: ${t.host}${e} is called`:`\u{1F32F} Wrapito: ${e} is called`;return{pass:!0,message:()=>n}};import Be from"deep-equal";var ne=()=>{let e=m().defaultHost;return e?.includes("http")?e:"https://default.com"},Se=(e="",t,n)=>t.includes(n)?t:e+t,O=e=>e instanceof Request,je=e=>O(e)?e.url:e,q=(e,t={method:"GET"})=>fetch.mock.calls.filter(([s])=>{let r=je(s),o=ne(),a=new URL(r,o),l=Se(t?.host,e,o),c=t?.host||o,u=new URL(l,c),i=a.pathname===u.pathname,d=a.search===u.search,p=a.host===u.host;return u.search?i&&d:t?.host?i&&p:i}),se=e=>e.flat(1).filter(O).map(t=>t.method),re=e=>e.flat(1).filter(O).map(t=>t._bodyInit?JSON.parse(t._bodyInit):{}),oe=e=>e.flat(1).filter(O).map(t=>new URL(t.url,ne()).hostname),ae=e=>e.flat(1).filter(O).map(t=>{let n={};return t.headers.forEach((s,r)=>{n[r]=s}),n}),ie=(e,t)=>e&&!t.includes(e),ce=(e,t)=>t.map(s=>Be(e,s)).every(s=>s===!1),pe=(e,t)=>t.every(s=>s!==e),ue=(e,t)=>t.every(s=>Object.entries(e).some(([r,o])=>s[r.toLowerCase()]!==o)),le=e=>e.length===0;var Ne=(e,t)=>{let n=q(e);if(le(n))return A(e);let s=se(n),r=t?.method;if(ie(r,s))return z(r,s);let o=re(n),a=t?.body;if(!a)return ee();if(ce(a,o))return K(a,o);let l=oe(n),c=t?.host;if(c&&pe(c,l))return X(c,l);let u=ae(n),i=t?.headers;return i&&ue(i,u)?Z(i,u):C()},$e=(e,t={method:"GET"})=>q(e,t).length?te(e,t):A(e,t),Le=(e,t,n={method:"GET"})=>{let s=q(e,n);return s.length!==t?Y(e,t,s.length):C()},mt={toHaveBeenFetched:$e,toHaveBeenFetchedWith:Ne,toHaveBeenFetchedTimes:Le};export{mt as assertions,_e as configure,m as getConfig,mt as matchers,rt as wrap};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wrapito",
3
- "version": "13.3.1-beta7",
3
+ "version": "13.4.0",
4
4
  "packageManager": "npm@10.8.2",
5
5
  "description": "🌯 🌯 Wrap you tests so that you can test both behaviour and components with less effort.",
6
6
  "type": "module",