twd-js 1.7.0 → 1.7.1

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.
@@ -1276,7 +1276,7 @@ var Ot = (e) => {
1276
1276
  }
1277
1277
  };
1278
1278
  window.__testRunner = et;
1279
- var we = "1.7.0", Ut = () => typeof window < "u" ? (window.__TWD_MOCK_STATE__ || (window.__TWD_MOCK_STATE__ = {
1279
+ var we = "1.7.1", Ut = () => typeof window < "u" ? (window.__TWD_MOCK_STATE__ || (window.__TWD_MOCK_STATE__ = {
1280
1280
  rules: [],
1281
1281
  counts: {}
1282
1282
  }), window.__TWD_MOCK_STATE__) : {
package/dist/index.cjs.js CHANGED
@@ -1,5 +1,5 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var Pl=Object.create,lr=Object.defineProperty,ql=Object.getOwnPropertyDescriptor,Rl=Object.getOwnPropertyNames,Tl=Object.getPrototypeOf,Sl=Object.prototype.hasOwnProperty,P=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),xl=(e,t)=>{let r={};for(var n in e)lr(r,n,{get:e[n],enumerable:!0});return t||lr(r,Symbol.toStringTag,{value:"Module"}),r},Ol=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(var a=Rl(t),o=0,i=a.length,s;o<i;o++)s=a[o],!Sl.call(e,s)&&s!==r&&lr(e,s,{get:(u=>t[u]).bind(null,s),enumerable:!(n=ql(t,s))||n.enumerable});return e},An=(e,t,r)=>(r=e!=null?Pl(Tl(e)):{},Ol(t||!e||!e.__esModule?lr(r,"default",{value:e,enumerable:!0}):r,e));const Mt=require("./runner-Dr_mUWED.cjs"),en=require("./componentMocks-CwMyWCu5.cjs");let oe=require("react"),j=require("react/jsx-runtime");var Ml=(e,t,r=2e3,n=50)=>new Promise((a,o)=>{const i=Date.now(),s=()=>{const u=t();if(u)return a(u);if(Date.now()-i>r)return o(new Error(`Timeout waiting for element ${e}`));setTimeout(s,n)};s()}),Al=(e,t,r=2e3,n=50)=>new Promise((a,o)=>{const i=Date.now(),s=()=>{const u=t();if(u&&u.length>0)return a(Array.from(u));if(Date.now()-i>r)return o(new Error(`Timeout waiting for elements ${e}`));setTimeout(s,n)};s()}),ur=e=>new Promise(t=>setTimeout(t,e)),te=e=>{const t=Mt.handlers.size?Array.from(Mt.handlers.values()).find(r=>r.status==="running"):null;t&&t.logs?.push(e)},Il=(e,t)=>{const r=t?.timeout??2e3,n=t?.interval??50,a=t?.message;return new Promise((o,i)=>{const s=Date.now();let u=!1;const l=async()=>{try{if(await e(),u)return;u=!0,te(a?`waitFor: resolved (${a})`:"waitFor: resolved"),o()}catch(c){if(u)return;const d=c instanceof Error?c:new Error(String(c));if(Date.now()-s>=r){u=!0;const p=`waitFor timed out after ${r}ms`,f=a?` waiting for: ${a}`:"",g=`
2
- Last error: ${d.message}`;i(new Error(`${p}${f}.${g}`));return}setTimeout(l,n)}};l()})},tn=(e,t,r,n)=>{if(!e&&!t)throw new Error(n);if(e&&t)throw new Error(n.replace("to be","to not be").replace("to have","to not have").replace("to contain","to not contain"));return r};function Nl(e){if(!e.isConnected)return!1;let t=e;for(;t;){const r=getComputedStyle(t);if(r.display==="none"||r.visibility==="hidden"||r.visibility==="collapse")return!1;t=t.parentElement}return!0}var kl={"have.text":{positive:{pass:e=>`Assertion passed: Text is exactly "${e[0]}"`,fail:(e,t)=>`Assertion failed: Expected text to be "${e[0]}", but got "${t}"`},negative:{pass:e=>`Assertion passed: Text is not exactly "${e[0]}"`,fail:(e,t)=>`Assertion failed: Expected text to not be "${e[0]}", but got "${t}"`}},"contain.text":{positive:{pass:e=>`Assertion passed: Text contains "${e[0]}"`,fail:(e,t)=>`Assertion failed: Expected text to contain "${e[0]}", but got "${t}"`},negative:{pass:e=>`Assertion passed: Text does not contain "${e[0]}"`,fail:(e,t)=>`Assertion failed: Expected text to not contain "${e[0]}", but got "${t}"`}},"be.empty":{positive:{pass:()=>"Assertion passed: Text is empty",fail:(e,t)=>`Assertion failed: Expected text to be empty, but got "${t}"`},negative:{pass:()=>"Assertion passed: Text is not empty",fail:(e,t)=>`Assertion failed: Expected text to not be empty, but got "${t}"`}},"have.attr":{positive:{pass:e=>`Assertion passed: Attribute "${e[0]}" is "${e[1]}"`,fail:(e,t)=>`Assertion failed: Expected attribute "${e[0]}" to be "${e[1]}", but got "${t}"`},negative:{pass:e=>`Assertion passed: Attribute "${e[0]}" is not "${e[1]}"`,fail:(e,t)=>`Assertion failed: Expected attribute "${e[0]}" to not be "${e[1]}", but got "${t}"`}},"have.value":{positive:{pass:e=>`Assertion passed: Value is "${e[0]}"`,fail:(e,t)=>`Assertion failed: Expected value to be "${e[0]}", but got "${t}"`},negative:{pass:e=>`Assertion passed: Value is not "${e[0]}"`,fail:(e,t)=>`Assertion failed: Expected value to not be "${e[0]}", but got "${t}"`}},"be.disabled":{positive:{pass:()=>"Assertion passed: Element is disabled",fail:()=>"Assertion failed: Expected element to be disabled"},negative:{pass:()=>"Assertion passed: Element is not disabled",fail:()=>"Assertion failed: Expected element to not be disabled"}},"be.enabled":{positive:{pass:()=>"Assertion passed: Element is enabled",fail:()=>"Assertion failed: Expected element to be enabled"},negative:{pass:()=>"Assertion passed: Element is not enabled",fail:()=>"Assertion failed: Expected element to not be enabled"}},"be.checked":{positive:{pass:()=>"Assertion passed: Element is checked",fail:()=>"Assertion failed: Expected element to be checked"},negative:{pass:()=>"Assertion passed: Element is not checked",fail:()=>"Assertion failed: Expected element to not be checked"}},"be.selected":{positive:{pass:()=>"Assertion passed: Element is selected",fail:()=>"Assertion failed: Expected element to be selected"},negative:{pass:()=>"Assertion passed: Element is not selected",fail:()=>"Assertion failed: Expected element to not be selected"}},"be.focused":{positive:{pass:()=>"Assertion passed: Element is focused",fail:()=>"Assertion failed: Expected element to be focused"},negative:{pass:()=>"Assertion passed: Element is not focused",fail:()=>"Assertion failed: Expected element to not be focused"}},"be.visible":{positive:{pass:()=>"Assertion passed: Element is visible",fail:()=>"Assertion failed: Expected element to be visible"},negative:{pass:()=>"Assertion passed: Element is not visible",fail:()=>"Assertion failed: Expected element to not be visible"}},"have.class":{positive:{pass:e=>`Assertion passed: Element has class "${e[0]}"`,fail:e=>`Assertion failed: Expected element to have class "${e[0]}"`},negative:{pass:e=>`Assertion passed: Element does not have class "${e[0]}"`,fail:e=>`Assertion failed: Expected element to not have class "${e[0]}"`}}},zr=(e,t,...r)=>{const n=t.startsWith("not."),a=n?t.slice(4):t,o=(e.textContent||"").trim(),i=kl[a];if(!i)throw new Error(`Unknown assertion: ${a}`);const s=n?"negative":"positive";let u,l;switch(a){case"have.text":u=o===r[0],l=o;break;case"contain.text":u=o.includes(r[0]),l=o;break;case"be.empty":u=o.length===0,l=o;break;case"have.attr":l=e.getAttribute(r[0]),u=l===r[1];break;case"have.value":l=e.value,u=l===r[0];break;case"be.disabled":u=e.disabled===!0;break;case"be.enabled":u=e.disabled===!1;break;case"be.checked":u=e.checked===!0;break;case"be.selected":u=e.selected===!0;break;case"be.focused":u=document.activeElement===e;break;case"be.visible":u=Nl(e);break;case"have.class":u=e.classList.contains(r[0]);break;default:throw new Error(`Unknown assertion: ${a}`)}return tn(u,n,i[s].pass(r),i[s].fail(r,l))},Rr="1.7.0",jl=()=>typeof window<"u"?(window.__TWD_MOCK_STATE__||(window.__TWD_MOCK_STATE__={rules:[],counts:{}}),window.__TWD_MOCK_STATE__):{rules:[],counts:{}},tt=jl(),Ce=tt.rules,Dl=100,Na=!1,Ll=async e=>{if(Na){console.warn("[TWD] Request mocking already initialized");return}if("serviceWorker"in navigator){Na=!0;const t=e??"/mock-sw.js";await navigator.serviceWorker.register(`${t}?v=${Rr}`),navigator.serviceWorker.controller||await new Promise(r=>{navigator.serviceWorker.addEventListener("controllerchange",r,{once:!0})}),navigator.serviceWorker.addEventListener("message",r=>{if(r.data?.type==="EXECUTED"){const{alias:n,request:a,hitCount:o}=r.data,i=Ce.find(s=>s.alias===n);i&&(i.executed=!0,i.request=a,i.hitCount=o),tt.counts[n]=o??(tt.counts[n]??0)+1}})}},Bl=async(e,t)=>{const r={alias:e,...t,executed:!1},n=Ce.findIndex(a=>a.alias===e);if(n!==-1?Ce[n]=r:Ce.push(r),typeof window.__twdCollectMock=="function"){const a=window.__TWD_STATE__?.handlers,o=a&&[...a.values()].find(i=>i.status==="running");o&&window.__twdCollectMock({alias:e,url:String(t.url),method:t.method,status:t.status||200,response:t.response,urlRegex:t.urlRegex||!1,testId:o.id})}navigator.serviceWorker.controller?.postMessage({type:"ADD_RULE",rule:r,version:Rr}),await ur(Dl),await Promise.resolve()},$l=async e=>await Promise.all(e.map(t=>Ro(t))),Ro=async(e,t=10,r=100)=>{const n=Ce.find(u=>u.alias===e);if(!n)throw new Error(`Rule ${e} not found`);for(let u=0;u<t;u++){const l=Ce.find(c=>c.alias===e&&c.executed);if(l)return Promise.resolve(l);u<t-1&&await new Promise(c=>setTimeout(c,r))}const a=t*r,o=Ce.filter(u=>u.executed).map(u=>`${u.alias} (${u.method} ${u.url})`).join(", "),i=Ce.filter(u=>!u.executed).map(u=>`${u.alias} (${u.method} ${u.url})`).join(", "),s=[`Rule "${e}" was not executed within ${a}ms.`,` Expected: ${n.method} ${n.url}`,` Executed rules: ${o||"none"}`,` Not executed rules: ${i||"none"}`].join(`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var Pl=Object.create,lr=Object.defineProperty,ql=Object.getOwnPropertyDescriptor,Rl=Object.getOwnPropertyNames,Tl=Object.getPrototypeOf,Sl=Object.prototype.hasOwnProperty,P=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),xl=(e,t)=>{let r={};for(var n in e)lr(r,n,{get:e[n],enumerable:!0});return t||lr(r,Symbol.toStringTag,{value:"Module"}),r},Ol=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(var a=Rl(t),o=0,i=a.length,s;o<i;o++)s=a[o],!Sl.call(e,s)&&s!==r&&lr(e,s,{get:(u=>t[u]).bind(null,s),enumerable:!(n=ql(t,s))||n.enumerable});return e},An=(e,t,r)=>(r=e!=null?Pl(Tl(e)):{},Ol(t||!e||!e.__esModule?lr(r,"default",{value:e,enumerable:!0}):r,e));const Mt=require("./runner-Dr_mUWED.cjs"),en=require("./componentMocks-CwMyWCu5.cjs");let oe=require("react"),j=require("react/jsx-runtime");var Ml=(e,t,r=2e3,n=50)=>new Promise((a,o)=>{const i=Date.now(),s=()=>{const u=t();if(u)return a(u);if(Date.now()-i>r)return o(new Error(`Timeout waiting for element ${e}`));setTimeout(s,n)};s()}),Al=(e,t,r=2e3,n=50)=>new Promise((a,o)=>{const i=Date.now(),s=()=>{const u=t();if(u&&u.length>0)return a(Array.from(u));if(Date.now()-i>r)return o(new Error(`Timeout waiting for elements ${e}`));setTimeout(s,n)};s()}),ur=e=>new Promise(t=>setTimeout(t,e)),te=e=>{const t=Mt.handlers.size?Array.from(Mt.handlers.values()).find(r=>r.status==="running"):null;t&&t.logs?.push(e)},Il=(e,t)=>{const r=t?.timeout??2e3,n=t?.interval??50,a=t?.message;return new Promise((o,i)=>{const s=Date.now();let u=!1;const l=async()=>{try{const c=await e();if(u)return;u=!0,te(a?`waitFor: resolved (${a})`:"waitFor: resolved"),o(c)}catch(c){if(u)return;const d=c instanceof Error?c:new Error(String(c));if(Date.now()-s>=r){u=!0;const p=`waitFor timed out after ${r}ms`,f=a?` waiting for: ${a}`:"",g=`
2
+ Last error: ${d.message}`;i(new Error(`${p}${f}.${g}`));return}setTimeout(l,n)}};l()})},tn=(e,t,r,n)=>{if(!e&&!t)throw new Error(n);if(e&&t)throw new Error(n.replace("to be","to not be").replace("to have","to not have").replace("to contain","to not contain"));return r};function Nl(e){if(!e.isConnected)return!1;let t=e;for(;t;){const r=getComputedStyle(t);if(r.display==="none"||r.visibility==="hidden"||r.visibility==="collapse")return!1;t=t.parentElement}return!0}var kl={"have.text":{positive:{pass:e=>`Assertion passed: Text is exactly "${e[0]}"`,fail:(e,t)=>`Assertion failed: Expected text to be "${e[0]}", but got "${t}"`},negative:{pass:e=>`Assertion passed: Text is not exactly "${e[0]}"`,fail:(e,t)=>`Assertion failed: Expected text to not be "${e[0]}", but got "${t}"`}},"contain.text":{positive:{pass:e=>`Assertion passed: Text contains "${e[0]}"`,fail:(e,t)=>`Assertion failed: Expected text to contain "${e[0]}", but got "${t}"`},negative:{pass:e=>`Assertion passed: Text does not contain "${e[0]}"`,fail:(e,t)=>`Assertion failed: Expected text to not contain "${e[0]}", but got "${t}"`}},"be.empty":{positive:{pass:()=>"Assertion passed: Text is empty",fail:(e,t)=>`Assertion failed: Expected text to be empty, but got "${t}"`},negative:{pass:()=>"Assertion passed: Text is not empty",fail:(e,t)=>`Assertion failed: Expected text to not be empty, but got "${t}"`}},"have.attr":{positive:{pass:e=>`Assertion passed: Attribute "${e[0]}" is "${e[1]}"`,fail:(e,t)=>`Assertion failed: Expected attribute "${e[0]}" to be "${e[1]}", but got "${t}"`},negative:{pass:e=>`Assertion passed: Attribute "${e[0]}" is not "${e[1]}"`,fail:(e,t)=>`Assertion failed: Expected attribute "${e[0]}" to not be "${e[1]}", but got "${t}"`}},"have.value":{positive:{pass:e=>`Assertion passed: Value is "${e[0]}"`,fail:(e,t)=>`Assertion failed: Expected value to be "${e[0]}", but got "${t}"`},negative:{pass:e=>`Assertion passed: Value is not "${e[0]}"`,fail:(e,t)=>`Assertion failed: Expected value to not be "${e[0]}", but got "${t}"`}},"be.disabled":{positive:{pass:()=>"Assertion passed: Element is disabled",fail:()=>"Assertion failed: Expected element to be disabled"},negative:{pass:()=>"Assertion passed: Element is not disabled",fail:()=>"Assertion failed: Expected element to not be disabled"}},"be.enabled":{positive:{pass:()=>"Assertion passed: Element is enabled",fail:()=>"Assertion failed: Expected element to be enabled"},negative:{pass:()=>"Assertion passed: Element is not enabled",fail:()=>"Assertion failed: Expected element to not be enabled"}},"be.checked":{positive:{pass:()=>"Assertion passed: Element is checked",fail:()=>"Assertion failed: Expected element to be checked"},negative:{pass:()=>"Assertion passed: Element is not checked",fail:()=>"Assertion failed: Expected element to not be checked"}},"be.selected":{positive:{pass:()=>"Assertion passed: Element is selected",fail:()=>"Assertion failed: Expected element to be selected"},negative:{pass:()=>"Assertion passed: Element is not selected",fail:()=>"Assertion failed: Expected element to not be selected"}},"be.focused":{positive:{pass:()=>"Assertion passed: Element is focused",fail:()=>"Assertion failed: Expected element to be focused"},negative:{pass:()=>"Assertion passed: Element is not focused",fail:()=>"Assertion failed: Expected element to not be focused"}},"be.visible":{positive:{pass:()=>"Assertion passed: Element is visible",fail:()=>"Assertion failed: Expected element to be visible"},negative:{pass:()=>"Assertion passed: Element is not visible",fail:()=>"Assertion failed: Expected element to not be visible"}},"have.class":{positive:{pass:e=>`Assertion passed: Element has class "${e[0]}"`,fail:e=>`Assertion failed: Expected element to have class "${e[0]}"`},negative:{pass:e=>`Assertion passed: Element does not have class "${e[0]}"`,fail:e=>`Assertion failed: Expected element to not have class "${e[0]}"`}}},zr=(e,t,...r)=>{const n=t.startsWith("not."),a=n?t.slice(4):t,o=(e.textContent||"").trim(),i=kl[a];if(!i)throw new Error(`Unknown assertion: ${a}`);const s=n?"negative":"positive";let u,l;switch(a){case"have.text":u=o===r[0],l=o;break;case"contain.text":u=o.includes(r[0]),l=o;break;case"be.empty":u=o.length===0,l=o;break;case"have.attr":l=e.getAttribute(r[0]),u=l===r[1];break;case"have.value":l=e.value,u=l===r[0];break;case"be.disabled":u=e.disabled===!0;break;case"be.enabled":u=e.disabled===!1;break;case"be.checked":u=e.checked===!0;break;case"be.selected":u=e.selected===!0;break;case"be.focused":u=document.activeElement===e;break;case"be.visible":u=Nl(e);break;case"have.class":u=e.classList.contains(r[0]);break;default:throw new Error(`Unknown assertion: ${a}`)}return tn(u,n,i[s].pass(r),i[s].fail(r,l))},Rr="1.7.1",jl=()=>typeof window<"u"?(window.__TWD_MOCK_STATE__||(window.__TWD_MOCK_STATE__={rules:[],counts:{}}),window.__TWD_MOCK_STATE__):{rules:[],counts:{}},tt=jl(),Ce=tt.rules,Dl=100,Na=!1,Ll=async e=>{if(Na){console.warn("[TWD] Request mocking already initialized");return}if("serviceWorker"in navigator){Na=!0;const t=e??"/mock-sw.js";await navigator.serviceWorker.register(`${t}?v=${Rr}`),navigator.serviceWorker.controller||await new Promise(r=>{navigator.serviceWorker.addEventListener("controllerchange",r,{once:!0})}),navigator.serviceWorker.addEventListener("message",r=>{if(r.data?.type==="EXECUTED"){const{alias:n,request:a,hitCount:o}=r.data,i=Ce.find(s=>s.alias===n);i&&(i.executed=!0,i.request=a,i.hitCount=o),tt.counts[n]=o??(tt.counts[n]??0)+1}})}},Bl=async(e,t)=>{const r={alias:e,...t,executed:!1},n=Ce.findIndex(a=>a.alias===e);if(n!==-1?Ce[n]=r:Ce.push(r),typeof window.__twdCollectMock=="function"){const a=window.__TWD_STATE__?.handlers,o=a&&[...a.values()].find(i=>i.status==="running");o&&window.__twdCollectMock({alias:e,url:String(t.url),method:t.method,status:t.status||200,response:t.response,urlRegex:t.urlRegex||!1,testId:o.id})}navigator.serviceWorker.controller?.postMessage({type:"ADD_RULE",rule:r,version:Rr}),await ur(Dl),await Promise.resolve()},$l=async e=>await Promise.all(e.map(t=>Ro(t))),Ro=async(e,t=10,r=100)=>{const n=Ce.find(u=>u.alias===e);if(!n)throw new Error(`Rule ${e} not found`);for(let u=0;u<t;u++){const l=Ce.find(c=>c.alias===e&&c.executed);if(l)return Promise.resolve(l);u<t-1&&await new Promise(c=>setTimeout(c,r))}const a=t*r,o=Ce.filter(u=>u.executed).map(u=>`${u.alias} (${u.method} ${u.url})`).join(", "),i=Ce.filter(u=>!u.executed).map(u=>`${u.alias} (${u.method} ${u.url})`).join(", "),s=[`Rule "${e}" was not executed within ${a}ms.`,` Expected: ${n.method} ${n.url}`,` Executed rules: ${o||"none"}`,` Not executed rules: ${i||"none"}`].join(`
3
3
  `);throw console.log(s),new Error(s)},To=()=>Ce,So=()=>{navigator.serviceWorker.controller?.postMessage({type:"CLEAR_RULES",version:Rr}),Ce.length=0;for(const e in tt.counts)delete tt.counts[e]},Fl=e=>tt.counts[e]??0,Ul=()=>({...tt.counts}),zl=(e,t)=>{const r=e.startsWith("not.");switch(r?e.slice(4):e){case"eq":return tn(window.location.href===t,r,`Assertion passed: URL is ${t}`,`Assertion failed: Expected URL to be ${t}, but got ${window.location.href}`);case"contain.url":return tn(window.location.href.includes(t),r,`Assertion passed: URL contains ${t}`,`Assertion failed: Expected URL to contain ${t}, but got ${window.location.href}`);default:throw new Error(`Unknown assertion: ${e}`)}},Vl=()=>({location:window.location,should:async(e,t,r=5)=>{let n="",a;for(let o=0;o<r;o++)try{n=zl(e,t),te(n);break}catch(i){await new Promise(s=>setTimeout(s,100)),a=i}if(a)throw a;return n}}),Hl=100,Wl=async(e,t)=>{if(te(`visit("${e}")`),window.location.pathname===e||t){const r=`/__dummy_${Math.random().toString(36).slice(2)}`;window.history.pushState({},"",r),window.dispatchEvent(new PopStateEvent("popstate")),await ur(10)}window.history.pushState({},"",e),window.dispatchEvent(new PopStateEvent("popstate")),await ur(Hl)},rn="twd-viewport-styles",nn="twd-viewport-iframe",fe=null,ut=null,Kl=()=>{if(fe)return;const{style:e}=document.body;fe={maxWidth:e.maxWidth,maxHeight:e.maxHeight,minHeight:e.minHeight,overflow:e.overflow,margin:e.margin,boxSizing:e.boxSizing,boxShadow:e.boxShadow}},Gl=(e,t)=>{let r=document.getElementById(rn);r||(r=document.createElement("style"),r.id=rn,document.head.appendChild(r));const n=t?`${e} × ${t}`:`${e}`;r.textContent=`
4
4
  #twd-viewport-badge {
5
5
  position: fixed;
package/dist/index.d.ts CHANGED
@@ -418,24 +418,27 @@ declare interface TWDAPI {
418
418
  *
419
419
  * @param callback Function to retry — can be sync or async. Should throw if the condition is not yet met.
420
420
  * @param options Optional timeout, interval, and message settings
421
- * @returns A promise that resolves when the callback succeeds
421
+ * @returns A promise that resolves with the callback's return value when it succeeds
422
422
  *
423
423
  * @example
424
424
  * ```ts
425
- * // Wait for an analytics event
426
- * await twd.waitFor(() => {
427
- * const event = findEvent("purchase");
428
- * expect(event).to.exist;
425
+ * // Wait for an analytics event and return it
426
+ * const event = await twd.waitFor(() => {
427
+ * const ev = findEvent("purchase");
428
+ * expect(ev).to.exist;
429
+ * return ev;
429
430
  * }, { message: "purchase event to fire" });
430
431
  *
431
- * // Wait with custom timeout
432
+ * // Wait for an element (single expression)
433
+ * const heading = await twd.waitFor(() => screenDom.getByRole("heading", { name: /checkout/i }));
434
+ *
435
+ * // Fire-and-forget (void) — still works as before
432
436
  * await twd.waitFor(() => {
433
- * const el = document.querySelector(".loaded");
434
- * if (!el) throw new Error("not loaded");
435
- * }, { timeout: 5000 });
437
+ * expect(submitButton.disabled).to.be.false;
438
+ * });
436
439
  * ```
437
440
  */
438
- waitFor: (callback: () => void | Promise<void>, options?: WaitForOptions) => Promise<void>;
441
+ waitFor: <T>(callback: () => T | Promise<T>, options?: WaitForOptions) => Promise<T>;
439
442
  /**
440
443
  * Asserts something about the element.
441
444
  * @param el The element to assert on
package/dist/index.es.js CHANGED
@@ -47,8 +47,9 @@ var Ol = Object.create, ur = Object.defineProperty, Ml = Object.getOwnPropertyDe
47
47
  let u = !1;
48
48
  const l = async () => {
49
49
  try {
50
- if (await e(), u) return;
51
- u = !0, re(a ? `waitFor: resolved (${a})` : "waitFor: resolved"), o();
50
+ const c = await e();
51
+ if (u) return;
52
+ u = !0, re(a ? `waitFor: resolved (${a})` : "waitFor: resolved"), o(c);
52
53
  } catch (c) {
53
54
  if (u) return;
54
55
  const d = c instanceof Error ? c : new Error(String(c));
@@ -246,7 +247,7 @@ var $l = {
246
247
  throw new Error(`Unknown assertion: ${a}`);
247
248
  }
248
249
  return an(u, n, i[s].pass(r), i[s].fail(r, l));
249
- }, Or = "1.7.0", Fl = () => typeof window < "u" ? (window.__TWD_MOCK_STATE__ || (window.__TWD_MOCK_STATE__ = {
250
+ }, Or = "1.7.1", Fl = () => typeof window < "u" ? (window.__TWD_MOCK_STATE__ || (window.__TWD_MOCK_STATE__ = {
250
251
  rules: [],
251
252
  counts: {}
252
253
  }), window.__TWD_MOCK_STATE__) : {
package/dist/mock-sw.js CHANGED
@@ -1,4 +1,4 @@
1
- (function(){var d=t=>{try{return new RegExp(t),!0}catch{return!1}},f=new Set(["js","mjs","cjs","ts","tsx","jsx","mts","cts","css","scss","sass","less","styl","html","htm","xml","xhtml","vue","svelte","json","yaml","yml","toml","csv","txt","md","mdx","pdf","doc","docx","png","jpg","jpeg","gif","svg","webp","ico","bmp","avif","woff","woff2","ttf","eot","otf","mp3","mp4","webm","ogg","wav","zip","tar","gz","rar","map"]),c=t=>{const s=t.split("?")[0].match(/\.([a-zA-Z0-9]+)$/);return s?f.has(s[1].toLowerCase()):!1},h=(t,s)=>{const i=t.indexOf(s);if(i===-1)return!1;const e=i+s.length,a=t[e];if(a===void 0)return!0;const n=t.indexOf("?");return n!==-1&&e>n?!0:"?#&".includes(a)};function m(t,s,i){return i.find(e=>{const a=e.method.toLowerCase()===t.toLowerCase();if(e.urlRegex&&d(e.url)){const l=new RegExp(e.url);return a&&l.test(s)}if(c(e.url))return a&&s.includes(e.url);const n=e.url===s||h(s,e.url);return a&&n&&!c(s)})}function p(t,s,i,e){t.forEach(a=>a.postMessage({type:"EXECUTED",alias:s.alias,request:i,hitCount:e}))}var y=(t,s,i)=>{const e=![204,205,304].includes(s),a=e?JSON.stringify(t):null;return new Response(a,{status:s,headers:e?i||{"Content-Type":"application/json"}:i||{}})},u="1.7.0",r=[],o={},g=async t=>{const{method:s}=t.request,i=t.request.url,e=m(s,i,r);e&&(console.log("[TWD] Mock hit:",e.alias,s,i),t.respondWith((async()=>{let a=null;const n=t.request.headers.get("content-type")||"application/json";if(n.includes("application/json"))try{a=await t.request.clone().json()}catch{}else if(n.includes("form"))try{const l=await t.request.clone().formData();a={},l.forEach((x,E)=>{a[E]=x})}catch{}else if(n.includes("text"))try{a=await t.request.clone().text()}catch{}else if(n.includes("octet-stream"))try{a=await t.request.clone().arrayBuffer()}catch{}else if(n.includes("image"))try{a=await t.request.clone().blob()}catch{}else try{a=await t.request.clone().text()}catch{}return o[e.alias]||(o[e.alias]=0),o[e.alias]++,p(await self.clients.matchAll(),e,a,o[e.alias]),e.delay&&e.delay>0&&await new Promise(l=>setTimeout(l,e.delay)),y(e.response,e.status??200,e.responseHeaders)})()))},w=t=>{t!=="1.7.0"&&console.warn(`[TWD] ⚠️ Version mismatch detected:
1
+ (function(){var d=t=>{try{return new RegExp(t),!0}catch{return!1}},f=new Set(["js","mjs","cjs","ts","tsx","jsx","mts","cts","css","scss","sass","less","styl","html","htm","xml","xhtml","vue","svelte","json","yaml","yml","toml","csv","txt","md","mdx","pdf","doc","docx","png","jpg","jpeg","gif","svg","webp","ico","bmp","avif","woff","woff2","ttf","eot","otf","mp3","mp4","webm","ogg","wav","zip","tar","gz","rar","map"]),c=t=>{const s=t.split("?")[0].match(/\.([a-zA-Z0-9]+)$/);return s?f.has(s[1].toLowerCase()):!1},h=(t,s)=>{const i=t.indexOf(s);if(i===-1)return!1;const e=i+s.length,a=t[e];if(a===void 0)return!0;const n=t.indexOf("?");return n!==-1&&e>n?!0:"?#&".includes(a)};function m(t,s,i){return i.find(e=>{const a=e.method.toLowerCase()===t.toLowerCase();if(e.urlRegex&&d(e.url)){const l=new RegExp(e.url);return a&&l.test(s)}if(c(e.url))return a&&s.includes(e.url);const n=e.url===s||h(s,e.url);return a&&n&&!c(s)})}function p(t,s,i,e){t.forEach(a=>a.postMessage({type:"EXECUTED",alias:s.alias,request:i,hitCount:e}))}var y=(t,s,i)=>{const e=![204,205,304].includes(s),a=e?JSON.stringify(t):null;return new Response(a,{status:s,headers:e?i||{"Content-Type":"application/json"}:i||{}})},u="1.7.1",r=[],o={},g=async t=>{const{method:s}=t.request,i=t.request.url,e=m(s,i,r);e&&(console.log("[TWD] Mock hit:",e.alias,s,i),t.respondWith((async()=>{let a=null;const n=t.request.headers.get("content-type")||"application/json";if(n.includes("application/json"))try{a=await t.request.clone().json()}catch{}else if(n.includes("form"))try{const l=await t.request.clone().formData();a={},l.forEach((x,E)=>{a[E]=x})}catch{}else if(n.includes("text"))try{a=await t.request.clone().text()}catch{}else if(n.includes("octet-stream"))try{a=await t.request.clone().arrayBuffer()}catch{}else if(n.includes("image"))try{a=await t.request.clone().blob()}catch{}else try{a=await t.request.clone().text()}catch{}return o[e.alias]||(o[e.alias]=0),o[e.alias]++,p(await self.clients.matchAll(),e,a,o[e.alias]),e.delay&&e.delay>0&&await new Promise(l=>setTimeout(l,e.delay)),y(e.response,e.status??200,e.responseHeaders)})()))},w=t=>{t!=="1.7.1"&&console.warn(`[TWD] ⚠️ Version mismatch detected:
2
2
  Client version: ${t}
3
3
  Service Worker version: ${u}
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "twd-js",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "description": "Test While Developing (TWD) - in-browser testing",
5
5
  "type": "module",
6
6
  "license": "MIT",