aria-ease 7.1.0 → 7.2.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/dist/ComboboxComponentStrategy-DHZS4NW6.js +5 -0
- package/dist/MenuComponentStrategy-L3QXLC6S.js +5 -0
- package/dist/cli.cjs +3 -3
- package/dist/cli.js +1 -1
- package/dist/{contractTestRunnerPlaywright-IUUAGMXP.js → contractTestRunnerPlaywright-2CEH3GPM.js} +2 -2
- package/dist/{contractTestRunnerPlaywright-44QPA5JG.js → contractTestRunnerPlaywright-RUKMUY5P.js} +2 -2
- package/dist/index.cjs +11 -11
- package/dist/index.js +9 -9
- package/dist/src/utils/test/ComboboxComponentStrategy-5AWO63DA.js +5 -0
- package/dist/src/utils/test/MenuComponentStrategy-QHVBLUBR.js +5 -0
- package/dist/src/utils/test/{contractTestRunnerPlaywright-VALOFEZZ.js → contractTestRunnerPlaywright-LUWM3RIL.js} +2 -2
- package/dist/src/utils/test/dsl/index.cjs +1 -1
- package/dist/src/utils/test/dsl/index.js +1 -1
- package/dist/src/utils/test/index.cjs +5 -5
- package/dist/src/utils/test/index.js +1 -1
- package/dist/{test-MWX7KH44.js → test-PCRWMQUO.js} +1 -1
- package/package.json +1 -1
- package/dist/ComboboxComponentStrategy-YSYLR2U5.js +0 -5
- package/dist/MenuComponentStrategy-C22BZEBH.js +0 -5
- package/dist/src/utils/test/ComboboxComponentStrategy-SICWLI27.js +0 -5
- package/dist/src/utils/test/MenuComponentStrategy-R4VPAHDE.js +0 -5
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{a as s}from"./chunk-SM6ZKEDR.js";import"./chunk-CNU4N4AY.js";var r=class{constructor(t,i,o=400,c=400){this.mainSelector=t;this.selectors=i;this.actionTimeoutMs=o;this.assertionTimeoutMs=c}async resetState(t){if(!this.selectors.popup)return;let i=this.selectors.popup,o=t.locator(i).first();if(!await o.isVisible().catch(()=>!1))return;let e=!1,n=this.selectors.main;if(n&&(await t.locator(n).first().focus(),await t.keyboard.press("Escape"),e=await(0,s.expect)(o).toBeHidden({timeout:this.assertionTimeoutMs}).then(()=>!0).catch(()=>!1)),!e&&this.selectors.button&&(await t.locator(this.selectors.button).first().click({timeout:this.actionTimeoutMs}),e=await(0,s.expect)(o).toBeHidden({timeout:this.assertionTimeoutMs}).then(()=>!0).catch(()=>!1)),e||(await t.mouse.click(10,10),e=await(0,s.expect)(o).toBeHidden({timeout:this.assertionTimeoutMs}).then(()=>!0).catch(()=>!1)),!e)throw new Error(`\u274C FATAL: Cannot close combobox popup between tests. Popup remains visible after trying:
|
|
2
|
+
1. Escape key
|
|
3
|
+
2. Clicking button
|
|
4
|
+
3. Clicking outside
|
|
5
|
+
This indicates a problem with the combobox component's close functionality.`);this.selectors.input&&await t.locator(this.selectors.input).first().clear()}async shouldSkipTest(){return!1}getMainSelector(){return this.mainSelector}};export{r as ComboboxComponentStrategy};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{a as r}from"./chunk-SM6ZKEDR.js";import"./chunk-CNU4N4AY.js";var c=class{constructor(e,o,i=400,n=400){this.mainSelector=e;this.selectors=o;this.actionTimeoutMs=i;this.assertionTimeoutMs=n}async resetState(e){if(!this.selectors.popup)return;let o=this.selectors.popup,i=e.locator(o).first();if(!await i.isVisible().catch(()=>!1))return;let s=!1,t=this.selectors.main;if(t&&(await e.locator(t).first().focus(),await e.keyboard.press("Escape"),s=await(0,r.expect)(i).toBeHidden({timeout:this.assertionTimeoutMs}).then(()=>!0).catch(()=>!1)),!s&&this.selectors.main&&(await e.locator(this.selectors.main).first().click({timeout:this.actionTimeoutMs}),s=await(0,r.expect)(i).toBeHidden({timeout:this.assertionTimeoutMs}).then(()=>!0).catch(()=>!1)),s||(await e.mouse.click(10,10),s=await(0,r.expect)(i).toBeHidden({timeout:this.assertionTimeoutMs}).then(()=>!0).catch(()=>!1)),!s)throw new Error(`\u274C FATAL: Cannot close menu between tests. Menu remains visible after trying:
|
|
2
|
+
1. Escape key
|
|
3
|
+
2. Clicking trigger
|
|
4
|
+
3. Clicking outside
|
|
5
|
+
This indicates a problem with the menu component's close functionality.`);this.selectors.input&&await e.locator(this.selectors.input).first().clear(),this.selectors.main&&await e.locator(this.selectors.main).first().focus()}async shouldSkipTest(e,o){if(!(e.action.some(t=>t.target==="submenu"||t.target==="submenuTrigger"||t.target==="submenuItems")||e.assertions.some(t=>t.target==="submenu"||t.target==="submenuTrigger"||t.target==="submenuItems")))return!1;let n=this.selectors.submenuTrigger;return n?await o.locator(n).count()===0:!0}getMainSelector(){return this.mainSelector}};export{c as MenuComponentStrategy};
|
package/dist/cli.cjs
CHANGED
|
@@ -103,11 +103,11 @@
|
|
|
103
103
|
</table>
|
|
104
104
|
</body>
|
|
105
105
|
</html>
|
|
106
|
-
`.trim()}function pe(c){return String(c??"").replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function vt(c){return String(c??"").toLowerCase().replace(/[^a-z0-9]+/g,"-")}var St=j(()=>{"use strict"});async function ws(){return ye||(ye=await Tt.chromium.launch({headless:!0,args:["--disable-extensions","--disable-blink-features=AutomationControlled"]})),ye}async function vs(){return be||(be=await(await ws()).newContext({permissions:[],ignoreHTTPSErrors:!0})),be}async function Ct(){return await(await vs()).newPage()}async function kt(){be&&(await be.close(),be=null),ye&&(await ye.close(),ye=null)}var Tt,ye,be,et=j(()=>{"use strict";Tt=require("playwright"),ye=null,be=null});function fe(c){return c==="required"||c==="recommended"||c==="optional"?c:$s}function $e(c){return c==="minimal"||c==="balanced"||c==="strict"||c==="paranoid"?c:"balanced"}function At(c,e){return{minimal:{required:"error",recommended:"ignore",optional:"ignore"},balanced:{required:"error",recommended:"warning",optional:"ignore"},strict:{required:"error",recommended:"error",optional:"warning"},paranoid:{required:"error",recommended:"error",optional:"error"}}[e][c]}var $s,tt=j(()=>{"use strict";$s="required"});var F={};X(F,{default:()=>Rt.default});var Rt,Se=j(()=>{"use strict";Ae(F,require("playwright/test"));Rt=I(require("playwright/test"),1)});var Et={};X(Et,{MenuComponentStrategy:()=>st});var st,xt=j(()=>{"use strict";Se();st=class{constructor(e,t,r=400,s=400){this.mainSelector=e;this.selectors=t;this.actionTimeoutMs=r;this.assertionTimeoutMs=s}async resetState(e){if(!this.selectors.popup)return;let t=this.selectors.popup,r=e.locator(t).first();if(!await r.isVisible().catch(()=>!1))return;let i=!1,n=this.selectors.
|
|
106
|
+
`.trim()}function pe(c){return String(c??"").replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function vt(c){return String(c??"").toLowerCase().replace(/[^a-z0-9]+/g,"-")}var St=j(()=>{"use strict"});async function ws(){return ye||(ye=await Tt.chromium.launch({headless:!0,args:["--disable-extensions","--disable-blink-features=AutomationControlled"]})),ye}async function vs(){return be||(be=await(await ws()).newContext({permissions:[],ignoreHTTPSErrors:!0})),be}async function Ct(){return await(await vs()).newPage()}async function kt(){be&&(await be.close(),be=null),ye&&(await ye.close(),ye=null)}var Tt,ye,be,et=j(()=>{"use strict";Tt=require("playwright"),ye=null,be=null});function fe(c){return c==="required"||c==="recommended"||c==="optional"?c:$s}function $e(c){return c==="minimal"||c==="balanced"||c==="strict"||c==="paranoid"?c:"balanced"}function At(c,e){return{minimal:{required:"error",recommended:"ignore",optional:"ignore"},balanced:{required:"error",recommended:"warning",optional:"ignore"},strict:{required:"error",recommended:"error",optional:"warning"},paranoid:{required:"error",recommended:"error",optional:"error"}}[e][c]}var $s,tt=j(()=>{"use strict";$s="required"});var F={};X(F,{default:()=>Rt.default});var Rt,Se=j(()=>{"use strict";Ae(F,require("playwright/test"));Rt=I(require("playwright/test"),1)});var Et={};X(Et,{MenuComponentStrategy:()=>st});var st,xt=j(()=>{"use strict";Se();st=class{constructor(e,t,r=400,s=400){this.mainSelector=e;this.selectors=t;this.actionTimeoutMs=r;this.assertionTimeoutMs=s}async resetState(e){if(!this.selectors.popup)return;let t=this.selectors.popup,r=e.locator(t).first();if(!await r.isVisible().catch(()=>!1))return;let i=!1,n=this.selectors.main;if(n&&(await e.locator(n).first().focus(),await e.keyboard.press("Escape"),i=await(0,F.expect)(r).toBeHidden({timeout:this.assertionTimeoutMs}).then(()=>!0).catch(()=>!1)),!i&&this.selectors.main&&(await e.locator(this.selectors.main).first().click({timeout:this.actionTimeoutMs}),i=await(0,F.expect)(r).toBeHidden({timeout:this.assertionTimeoutMs}).then(()=>!0).catch(()=>!1)),i||(await e.mouse.click(10,10),i=await(0,F.expect)(r).toBeHidden({timeout:this.assertionTimeoutMs}).then(()=>!0).catch(()=>!1)),!i)throw new Error(`\u274C FATAL: Cannot close menu between tests. Menu remains visible after trying:
|
|
107
107
|
1. Escape key
|
|
108
108
|
2. Clicking trigger
|
|
109
109
|
3. Clicking outside
|
|
110
|
-
This indicates a problem with the menu component's close functionality.`);this.selectors.input&&await e.locator(this.selectors.input).first().clear(),this.selectors.main&&await e.locator(this.selectors.main).first().focus()}async shouldSkipTest(e,t){if(!(e.action.some(n=>n.target==="submenu"||n.target==="submenuTrigger"||n.target==="submenuItems")||e.assertions.some(n=>n.target==="submenu"||n.target==="submenuTrigger"||n.target==="submenuItems")))return!1;let s=this.selectors.submenuTrigger;return s?await t.locator(s).count()===0:!0}getMainSelector(){return this.mainSelector}}});var Mt={};X(Mt,{AccordionComponentStrategy:()=>rt});var rt,Pt=j(()=>{"use strict";Se();rt=class{constructor(e,t,r=400,s=400){this.mainSelector=e;this.selectors=t;this.actionTimeoutMs=r;this.assertionTimeoutMs=s}async resetState(e){if(!this.selectors.panel||!this.selectors.trigger||this.selectors.popup)return;let t=this.selectors.trigger,r=this.selectors.panel;if(!t||!r)return;let s=await e.locator(t).all();for(let i of s){let n=await i.getAttribute("aria-expanded")==="true",a=await i.getAttribute("aria-controls");if(n&&a){await i.click({timeout:this.actionTimeoutMs});let l=e.locator(`#${a}`);await(0,F.expect)(l).toBeHidden({timeout:this.assertionTimeoutMs}).catch(()=>{})}}}async shouldSkipTest(){return!1}getMainSelector(){return this.mainSelector}}});var Bt={};X(Bt,{ComboboxComponentStrategy:()=>it});var it,Lt=j(()=>{"use strict";Se();it=class{constructor(e,t,r=400,s=400){this.mainSelector=e;this.selectors=t;this.actionTimeoutMs=r;this.assertionTimeoutMs=s}async resetState(e){if(!this.selectors.popup)return;let t=this.selectors.popup,r=e.locator(t).first();if(!await r.isVisible().catch(()=>!1))return;let i=!1,n=this.selectors.
|
|
110
|
+
This indicates a problem with the menu component's close functionality.`);this.selectors.input&&await e.locator(this.selectors.input).first().clear(),this.selectors.main&&await e.locator(this.selectors.main).first().focus()}async shouldSkipTest(e,t){if(!(e.action.some(n=>n.target==="submenu"||n.target==="submenuTrigger"||n.target==="submenuItems")||e.assertions.some(n=>n.target==="submenu"||n.target==="submenuTrigger"||n.target==="submenuItems")))return!1;let s=this.selectors.submenuTrigger;return s?await t.locator(s).count()===0:!0}getMainSelector(){return this.mainSelector}}});var Mt={};X(Mt,{AccordionComponentStrategy:()=>rt});var rt,Pt=j(()=>{"use strict";Se();rt=class{constructor(e,t,r=400,s=400){this.mainSelector=e;this.selectors=t;this.actionTimeoutMs=r;this.assertionTimeoutMs=s}async resetState(e){if(!this.selectors.panel||!this.selectors.trigger||this.selectors.popup)return;let t=this.selectors.trigger,r=this.selectors.panel;if(!t||!r)return;let s=await e.locator(t).all();for(let i of s){let n=await i.getAttribute("aria-expanded")==="true",a=await i.getAttribute("aria-controls");if(n&&a){await i.click({timeout:this.actionTimeoutMs});let l=e.locator(`#${a}`);await(0,F.expect)(l).toBeHidden({timeout:this.assertionTimeoutMs}).catch(()=>{})}}}async shouldSkipTest(){return!1}getMainSelector(){return this.mainSelector}}});var Bt={};X(Bt,{ComboboxComponentStrategy:()=>it});var it,Lt=j(()=>{"use strict";Se();it=class{constructor(e,t,r=400,s=400){this.mainSelector=e;this.selectors=t;this.actionTimeoutMs=r;this.assertionTimeoutMs=s}async resetState(e){if(!this.selectors.popup)return;let t=this.selectors.popup,r=e.locator(t).first();if(!await r.isVisible().catch(()=>!1))return;let i=!1,n=this.selectors.main;if(n&&(await e.locator(n).first().focus(),await e.keyboard.press("Escape"),i=await(0,F.expect)(r).toBeHidden({timeout:this.assertionTimeoutMs}).then(()=>!0).catch(()=>!1)),!i&&this.selectors.button&&(await e.locator(this.selectors.button).first().click({timeout:this.actionTimeoutMs}),i=await(0,F.expect)(r).toBeHidden({timeout:this.assertionTimeoutMs}).then(()=>!0).catch(()=>!1)),i||(await e.mouse.click(10,10),i=await(0,F.expect)(r).toBeHidden({timeout:this.assertionTimeoutMs}).then(()=>!0).catch(()=>!1)),!i)throw new Error(`\u274C FATAL: Cannot close combobox popup between tests. Popup remains visible after trying:
|
|
111
111
|
1. Escape key
|
|
112
112
|
2. Clicking button
|
|
113
113
|
3. Clicking outside
|
|
@@ -132,7 +132,7 @@ ${"\u2550".repeat(60)}`),this.log(`\u{1F4CA} Summary
|
|
|
132
132
|
`),a>0?(this.log("\u{1F527} Next Steps:"),this.log(" 1. Review the failures above"),this.log(" 2. Fix ARIA attributes and keyboard handlers"),this.log(` 3. Re-run tests to verify fixes
|
|
133
133
|
`)):!this.isPlaywright&&this.skipped>0&&this.log(`\u2728 Optional: Run Playwright tests for complete validation
|
|
134
134
|
`),{passes:n,failures:a,skipped:this.skipped,duration:t}}error(e,t){this.log(`
|
|
135
|
-
\u274C Error: ${e}`),t&&this.log(` Context: ${t}`),this.log("")}}});var qt={};X(qt,{RelativeTargetResolver:()=>se});var se,je=j(()=>{"use strict";se=class{static async resolve(e,t,r){let s=await e.locator(t).all();if(typeof r=="number")return s[r-1];switch(r){case"first":return s[0];case"second":return s[1];case"last":return s[s.length-1];case"next":{let n=(await e.evaluate(([a])=>Array.from(document.querySelectorAll(a)).indexOf(document.activeElement),[t])+1)%s.length;return s[n]}case"previous":{let n=(await e.evaluate(([a])=>Array.from(document.querySelectorAll(a)).indexOf(document.activeElement),[t])-1+s.length)%s.length;return s[n]}default:return null}}}});var we,Ot=j(()=>{"use strict";je();we=class{constructor(e,t,r=400){this.page=e;this.selectors=t;this.timeoutMs=r}isBrowserClosedError(e){return e instanceof Error&&e.message.includes("Target page, context or browser has been closed")}async focus(e,t,r){try{if(e==="virtual"&&r){let i=this.selectors.main;if(!i)return{success:!1,error:"Main selector not defined for virtual focus."};let n=this.page.locator(i).first();return await n.count()?(await n.evaluate((l,u)=>{l.setAttribute("aria-activedescendant",u)},r),{success:!0}):{success:!1,error:"Main element not found for virtual focus."}}if(e==="relative"&&t){let i=this.selectors.relative;if(!i)return{success:!1,error:"Relative selector not defined for focus action."};let n=await se.resolve(this.page,i,t);return n?(await n.focus({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${t} for focus.`}}let s=this.selectors[e];return s?(await this.page.locator(s).first().focus({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for focus target ${e} not found.`}}catch(s){return this.isBrowserClosedError(s)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to focus ${e}: ${s instanceof Error?s.message:String(s)}`}}}async type(e,t){try{let r=this.selectors[e];return r?(await this.page.locator(r).first().fill(t,{timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for type target ${e} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to type into ${e}: ${r instanceof Error?r.message:String(r)}`}}}async click(e,t){try{if(e==="document")return await this.page.mouse.click(10,10),{success:!0};if(e==="relative"&&t){let s=this.selectors.relative;if(!s)return{success:!1,error:"Relative selector not defined for click action."};let i=await se.resolve(this.page,s,t);return i?(await i.click({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${t} for click.`}}let r=this.selectors[e];return r?(await this.page.locator(r).first().click({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for action target ${e} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to click ${e}: ${r instanceof Error?r.message:String(r)}`}}}async keypress(e,t,r){try{let i={Space:"Space",Enter:"Enter",Escape:"Escape","Arrow Up":"ArrowUp","Arrow Down":"ArrowDown","Arrow Left":"ArrowLeft","Arrow Right":"ArrowRight",Home:"Home",End:"End",Tab:"Tab"}[t]||t;if(i==="Space"?i=" ":i.includes(" ")&&(i=i.replace(/ /g,"")),e==="focusable"&&["ArrowUp","ArrowDown","ArrowLeft","ArrowRight","Escape","Home","End","Tab","Shift+Tab"].includes(i))return await this.page.keyboard.press(i),{success:!0};if(e==="relative"){if(r==null)return{success:!1,error:"relativeTarget must be provided for relative keypress."};let u=this.selectors.relative;if(!u)return{success:!1,error:"Relative selector not defined for keypress action."};let f=await se.resolve(this.page,u,r);return f?(await f.press(i,{timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${r} for keypress.`}}let n=this.selectors[e];if(!n)return{success:!1,error:`Selector for keypress target ${e} not found.`};let a=this.page.locator(n).first();return await a.count()===0?{success:!1,error:`${e} element not found.`,shouldBreak:!0}:(await a.press(i,{timeout:this.timeoutMs}),{success:!0})}catch(s){return this.isBrowserClosedError(s)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to press ${t} on ${e}: ${s instanceof Error?s.message:String(s)}`}}}async hover(e,t){try{if(e==="relative"&&t){let s=this.selectors.relative;if(!s)return{success:!1,error:"Relative selector not defined for hover action."};let i=await se.resolve(this.page,s,t);return i?(await i.hover({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${t} for hover.`}}let r=this.selectors[e];return r?(await this.page.locator(r).first().hover({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for hover target ${e} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to hover ${e}: ${r instanceof Error?r.message:String(r)}`}}}}});var Te,Ht=j(()=>{"use strict";Se();je();Te=class{constructor(e,t,r=400){this.page=e;this.selectors=t;this.timeoutMs=r}async resolveTarget(e,t,r){try{if(e==="relative"){let i=r?this.selectors[r]:this.selectors.relative;if(!i)return{target:null,error:"Relative selector is not defined in the contract."};if(!t)return{target:null,error:"Relative target or expected value is not defined."};let n=await se.resolve(this.page,i,t);return n?{target:n}:{target:null,error:`Target ${e} not found.`}}let s=this.selectors[e];return s?{target:this.page.locator(s).first()}:{target:null,error:`Selector for assertion target ${e} not found.`}}catch(s){return{target:null,error:`Failed to resolve target ${e}: ${s instanceof Error?s.message:String(s)}`}}}async validateVisibility(e,t,r,s,i){try{return r?(await(0,F.expect)(e).toBeVisible({timeout:this.timeoutMs}),{success:!0,passMessage:`${t} is visible as expected. Test: "${i}".`}):(await(0,F.expect)(e).toBeHidden({timeout:this.timeoutMs}),{success:!0,passMessage:`${t} is not visible as expected. Test: "${i}".`})}catch{let n=this.selectors[t]||"",a=await this.page.evaluate(l=>{let u=l?document.querySelector(l):null;if(!u)return"element not found";let f=window.getComputedStyle(u);return`display:${f.display}, visibility:${f.visibility}, opacity:${f.opacity}`},n);return r?{success:!1,failMessage:`${s} (actual: ${a})`}:{success:!1,failMessage:`${s} ${t} is still visible (actual: ${a}).`}}}async validateAttribute(e,t,r,s,i,n){if(s==="!empty"){let u=await e.getAttribute(r);return u&&u.trim()!==""?{success:!0,passMessage:`${t} has non-empty "${r}". Test: "${n}".`}:{success:!1,failMessage:`${i} ${t} "${r}" should not be empty, found "${u}".`}}if(typeof s!="string")throw console.error("[AssertionRunner] expectedValue is not a string:",s),new Error(`AssertionRunner: expectedValue for attribute assertion must be a string, but got: ${JSON.stringify(s)}`);let a=s.split(" | ").map(u=>u.trim()),l=await e.getAttribute(r);return l!==null&&a.includes(l)?{success:!0,passMessage:`${t} has expected "${r}". Test: "${n}".`}:{success:!1,failMessage:`${i} ${t} "${r}" should be "${s}", found "${l}".`}}async validateValue(e,t,r,s,i){let n=await e.inputValue().catch(()=>"");return r==="!empty"?n&&n.trim()!==""?{success:!0,passMessage:`${t} has non-empty value. Test: "${i}".`}:{success:!1,failMessage:`${s} ${t} value should not be empty, found "${n}".`}:r===""?n===""?{success:!0,passMessage:`${t} has empty value. Test: "${i}".`}:{success:!1,failMessage:`${s} ${t} value should be empty, found "${n}".`}:n===r?{success:!0,passMessage:`${t} has expected value. Test: "${i}".`}:{success:!1,failMessage:`${s} ${t} value should be "${r}", found "${n}".`}}async validateFocus(e,t,r,s,i){try{return r?(await(0,F.expect)(e).toBeFocused({timeout:this.timeoutMs}),{success:!0,passMessage:`${t} has focus as expected. Test: "${i}".`}):(await(0,F.expect)(e).not.toBeFocused({timeout:this.timeoutMs}),{success:!0,passMessage:`${t} does not have focus as expected. Test: "${i}".`})}catch{let n=await this.page.evaluate(()=>{let a=document.activeElement;return a?`${a.tagName}#${a.id||"no-id"}.${a.className||"no-class"}`:"no element focused"});return{success:!1,failMessage:`${s} (actual focus: ${n})`}}}async validateRole(e,t,r,s,i){let n=await e.getAttribute("role");return n===r?{success:!0,passMessage:`${t} has role "${r}". Test: "${i}".`}:{success:!1,failMessage:`${s} Expected role "${r}", found "${n}".`}}async validate(e,t){if(this.page.isClosed())return{success:!1,failMessage:"CRITICAL: Browser/page closed before completing all tests. Increase test timeout or reduce test complexity."};let r=null,s;if(e.controlledBy){let i=e.controlledBy,n=this.selectors[i.target];if(!n)return{success:!1,failMessage:`Selector for controlledBy.target '${i.target}' not found.`,target:null};let a=null;if(i.relativeTarget?a=await se.resolve(this.page,n,i.relativeTarget):a=this.page.locator(n).first(),!a)return{success:!1,failMessage:"Controlling element for controlledBy not found.",target:null};let l=i.attribute||"aria-controls",u=await a.getAttribute(l);if(!u)return{success:!1,failMessage:`Controlling element does not have attribute '${l}'.`,target:null};if(r=this.page.locator(`#${u}`),!r||await r.count()===0)return{success:!1,failMessage:`Controlled element with id '${u}' not found.`,target:null}}else{let i=await this.resolveTarget(e.target,e.relativeTarget||e.expectedValue,e.selectorKey);if(r=i.target,s=i.error,s||!r)return{success:!1,failMessage:s||`Target ${e.target} not found.`,target:null}}if(e.target==="input"&&e.attribute==="aria-activedescendant"&&e.expectedValue==="!empty"&&e.relativeTarget&&e.selectorKey){let i=await se.resolve(this.page,this.selectors[e.selectorKey],e.relativeTarget),n=i?await i.getAttribute("id"):null,a=await r.getAttribute("aria-activedescendant");return n&&a===n?{success:!0,passMessage:`input[aria-activedescendant] matches id of ${e.relativeTarget}(${e.selectorKey}). Test: "${t}".`}:{success:!1,failMessage:`input[aria-activedescendant] should match id of ${e.relativeTarget}(${e.selectorKey}), found "${a}".`}}switch(e.assertion){case"toBeVisible":return this.validateVisibility(r,e.target,!0,e.failureMessage||"",t);case"notToBeVisible":return this.validateVisibility(r,e.target,!1,e.failureMessage||"",t);case"toHaveAttribute":return e.attribute&&e.expectedValue!==void 0?this.validateAttribute(r,e.target,e.attribute,e.expectedValue,e.failureMessage||"",t):{success:!1,failMessage:"Missing attribute or expectedValue for toHaveAttribute assertion"};case"toHaveValue":return e.expectedValue!==void 0?this.validateValue(r,e.target,e.expectedValue,e.failureMessage||"",t):{success:!1,failMessage:"Missing expectedValue for toHaveValue assertion"};case"toHaveFocus":return this.validateFocus(r,e.target,!0,e.failureMessage||"",t);case"notToHaveFocus":return this.validateFocus(r,e.target,!1,e.failureMessage||"",t);case"toHaveRole":return e.expectedValue!==void 0?this.validateRole(r,e.target,e.expectedValue,e.failureMessage||"",t):{success:!1,failMessage:"Missing expectedValue for toHaveRole assertion"};default:return{success:!1,failMessage:`Unknown assertion type: ${e.assertion}`}}}}});var Nt={};X(Nt,{runContractTestsPlaywright:()=>Ts});async function Ts(c,e,t,r,s){let i=r?.test?.components?.find(S=>S.name===c),n=!!i?.contractPath,a=new Le(!0,n),l={actionTimeoutMs:400,assertionTimeoutMs:400,navigationTimeoutMs:3e4,componentReadyTimeoutMs:5e3},u=r?.test?.disableTimeouts===!0,h=i?.disableTimeouts===!0||u,y=(S,ie,oe)=>{if(h)return 0;let ee=S??ie;return typeof ee!="number"||!Number.isFinite(ee)||ee<0?oe:ee},L=y(i?.actionTimeoutMs,r?.test?.actionTimeoutMs,l.actionTimeoutMs),H=y(i?.assertionTimeoutMs,r?.test?.assertionTimeoutMs,l.assertionTimeoutMs),M=y(i?.navigationTimeoutMs,r?.test?.navigationTimeoutMs,l.navigationTimeoutMs),U=y(i?.componentReadyTimeoutMs,r?.test?.componentReadyTimeoutMs,l.componentReadyTimeoutMs),W=$e(t),J=i?.contractPath;if(!J)throw new Error(`Contract path not found for component: ${c}`);let G=(()=>{if(Fe.default.isAbsolute(J))return J;if(s){let ie=Fe.default.resolve(s,J);try{return(0,Ie.readFileSync)(ie,"utf-8"),ie}catch{}}let S=Fe.default.resolve(process.cwd(),J);try{return(0,Ie.readFileSync)(S,"utf-8"),S}catch{return new URL(J,Cs.url).pathname}})(),Y=(0,Ie.readFileSync)(G,"utf-8"),v=JSON.parse(Y),Ce=(v.relationships?.length||0)+(v.static[0]?.assertions.length||0)+v.dynamic.length,Ue=v.meta?.source?.apg,Z=[],ae=[],ce=[],N=[],A=null,q=(S,ie)=>{let oe=fe(ie),ee=At(oe,W);if(ee==="error")return Z.push(S),{status:"fail",level:oe,detail:S};if(ee==="warning")return ae.push(S),{status:"warn",level:oe,detail:S};let ne=`${S} (ignored by strictness=${W}, level=${oe})`;return N.push(ne),{status:"skip",level:oe,detail:ne}};try{if(A=await Ct(),e){try{await A.goto(e,{waitUntil:"domcontentloaded",timeout:M})}catch(o){throw new Error(`Failed to navigate to ${e}. Ensure dev server is running and accessible. Original error: ${o instanceof Error?o.message:String(o)}`)}await A.addStyleTag({content:"* { transition: none !important; animation: none !important; }"})}let S=await Be.detect(c,i,L,H,s);if(!S)throw new Error(`Unsupported component: ${c}`);let ie=S.getMainSelector();if(!ie)throw new Error(`CRITICAL: No selector found in contract for ${c}`);try{await A.locator(ie).first().waitFor({state:"attached",timeout:U})}catch(o){throw new Error(`
|
|
135
|
+
\u274C Error: ${e}`),t&&this.log(` Context: ${t}`),this.log("")}}});var qt={};X(qt,{RelativeTargetResolver:()=>se});var se,je=j(()=>{"use strict";se=class{static async resolve(e,t,r){let s=await e.locator(t).all();if(typeof r=="number")return s[r-1];switch(r){case"first":return s[0];case"second":return s[1];case"last":return s[s.length-1];case"next":{let n=(await e.evaluate(([a])=>Array.from(document.querySelectorAll(a)).indexOf(document.activeElement),[t])+1)%s.length;return s[n]}case"previous":{let n=(await e.evaluate(([a])=>Array.from(document.querySelectorAll(a)).indexOf(document.activeElement),[t])-1+s.length)%s.length;return s[n]}default:return null}}}});var we,Ot=j(()=>{"use strict";je();we=class{constructor(e,t,r=400){this.page=e;this.selectors=t;this.timeoutMs=r}isBrowserClosedError(e){return e instanceof Error&&e.message.includes("Target page, context or browser has been closed")}async focus(e,t,r){try{if(e==="virtual"&&r){let i=this.selectors.main;if(!i)return{success:!1,error:"Main selector not defined for virtual focus."};let n=this.page.locator(i).first();return await n.count()?(await n.evaluate((l,u)=>{l.setAttribute("aria-activedescendant",u)},r),{success:!0}):{success:!1,error:"Main element not found for virtual focus."}}if(e==="relative"&&t){let i=this.selectors.relative;if(!i)return{success:!1,error:"Relative selector not defined for focus action."};let n=await se.resolve(this.page,i,t);return n?(await n.focus({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${t} for focus.`}}let s=this.selectors[e];return s?(await this.page.locator(s).first().focus({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for focus target ${e} not found.`}}catch(s){return this.isBrowserClosedError(s)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to focus ${e}: ${s instanceof Error?s.message:String(s)}`}}}async type(e,t){try{let r=this.selectors[e];return r?(await this.page.locator(r).first().fill(t,{timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for type target ${e} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to type into ${e}: ${r instanceof Error?r.message:String(r)}`}}}async click(e,t){try{if(e==="document")return await this.page.mouse.click(10,10),{success:!0};if(e==="relative"&&t){let s=this.selectors.relative;if(!s)return{success:!1,error:"Relative selector not defined for click action."};let i=await se.resolve(this.page,s,t);return i?(await i.click({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${t} for click.`}}let r=this.selectors[e];return r?(await this.page.locator(r).first().click({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for action target ${e} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to click ${e}: ${r instanceof Error?r.message:String(r)}`}}}async keypress(e,t,r){try{let i={Space:"Space",Enter:"Enter",Escape:"Escape","Arrow Up":"ArrowUp","Arrow Down":"ArrowDown","Arrow Left":"ArrowLeft","Arrow Right":"ArrowRight",Home:"Home",End:"End",Tab:"Tab"}[t]||t;if(i==="Space"?i=" ":i.includes(" ")&&(i=i.replace(/ /g,"")),e==="relative"){if(r==null)return{success:!1,error:"relativeTarget must be provided for relative keypress."};let u=this.selectors.relative;if(!u)return{success:!1,error:"Relative selector not defined for keypress action."};let f=await se.resolve(this.page,u,r);return f?(await f.press(i,{timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${r} for keypress.`}}let n=this.selectors[e];if(!n)return{success:!1,error:`Selector for keypress target ${e} not found.`};let a=this.page.locator(n).first();return await a.count()===0?{success:!1,error:`${e} element not found.`,shouldBreak:!0}:(await a.press(i,{timeout:this.timeoutMs}),{success:!0})}catch(s){return this.isBrowserClosedError(s)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to press ${t} on ${e}: ${s instanceof Error?s.message:String(s)}`}}}async hover(e,t){try{if(e==="relative"&&t){let s=this.selectors.relative;if(!s)return{success:!1,error:"Relative selector not defined for hover action."};let i=await se.resolve(this.page,s,t);return i?(await i.hover({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${t} for hover.`}}let r=this.selectors[e];return r?(await this.page.locator(r).first().hover({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for hover target ${e} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to hover ${e}: ${r instanceof Error?r.message:String(r)}`}}}}});var Te,Ht=j(()=>{"use strict";Se();je();Te=class{constructor(e,t,r=400){this.page=e;this.selectors=t;this.timeoutMs=r}async resolveTarget(e,t,r){try{if(e==="relative"){let i=r?this.selectors[r]:this.selectors.relative;if(!i)return{target:null,error:"Relative selector is not defined in the contract."};if(!t)return{target:null,error:"Relative target or expected value is not defined."};let n=await se.resolve(this.page,i,t);return n?{target:n}:{target:null,error:`Target ${e} not found.`}}let s=this.selectors[e];return s?{target:this.page.locator(s).first()}:{target:null,error:`Selector for assertion target ${e} not found.`}}catch(s){return{target:null,error:`Failed to resolve target ${e}: ${s instanceof Error?s.message:String(s)}`}}}async validateVisibility(e,t,r,s,i){try{return r?(await(0,F.expect)(e).toBeVisible({timeout:this.timeoutMs}),{success:!0,passMessage:`${t} is visible as expected. Test: "${i}".`}):(await(0,F.expect)(e).toBeHidden({timeout:this.timeoutMs}),{success:!0,passMessage:`${t} is not visible as expected. Test: "${i}".`})}catch{let n=this.selectors[t]||"",a=await this.page.evaluate(l=>{let u=l?document.querySelector(l):null;if(!u)return"element not found";let f=window.getComputedStyle(u);return`display:${f.display}, visibility:${f.visibility}, opacity:${f.opacity}`},n);return r?{success:!1,failMessage:`${s} (actual: ${a})`}:{success:!1,failMessage:`${s} ${t} is still visible (actual: ${a}).`}}}async validateAttribute(e,t,r,s,i,n){if(s==="!empty"){let u=await e.getAttribute(r);return u&&u.trim()!==""?{success:!0,passMessage:`${t} has non-empty "${r}". Test: "${n}".`}:{success:!1,failMessage:`${i} ${t} "${r}" should not be empty, found "${u}".`}}if(typeof s!="string")throw console.error("[AssertionRunner] expectedValue is not a string:",s),new Error(`AssertionRunner: expectedValue for attribute assertion must be a string, but got: ${JSON.stringify(s)}`);let a=s.split(" | ").map(u=>u.trim()),l=await e.getAttribute(r);return l!==null&&a.includes(l)?{success:!0,passMessage:`${t} has expected "${r}". Test: "${n}".`}:{success:!1,failMessage:`${i} ${t} "${r}" should be "${s}", found "${l}".`}}async validateValue(e,t,r,s,i){let n=await e.inputValue().catch(()=>"");return r==="!empty"?n&&n.trim()!==""?{success:!0,passMessage:`${t} has non-empty value. Test: "${i}".`}:{success:!1,failMessage:`${s} ${t} value should not be empty, found "${n}".`}:r===""?n===""?{success:!0,passMessage:`${t} has empty value. Test: "${i}".`}:{success:!1,failMessage:`${s} ${t} value should be empty, found "${n}".`}:n===r?{success:!0,passMessage:`${t} has expected value. Test: "${i}".`}:{success:!1,failMessage:`${s} ${t} value should be "${r}", found "${n}".`}}async validateFocus(e,t,r,s,i){try{return r?(await(0,F.expect)(e).toBeFocused({timeout:this.timeoutMs}),{success:!0,passMessage:`${t} has focus as expected. Test: "${i}".`}):(await(0,F.expect)(e).not.toBeFocused({timeout:this.timeoutMs}),{success:!0,passMessage:`${t} does not have focus as expected. Test: "${i}".`})}catch{let n=await this.page.evaluate(()=>{let a=document.activeElement;return a?`${a.tagName}#${a.id||"no-id"}.${a.className||"no-class"}`:"no element focused"});return{success:!1,failMessage:`${s} (actual focus: ${n})`}}}async validateRole(e,t,r,s,i){let n=await e.getAttribute("role");return n===r?{success:!0,passMessage:`${t} has role "${r}". Test: "${i}".`}:{success:!1,failMessage:`${s} Expected role "${r}", found "${n}".`}}async validate(e,t){if(this.page.isClosed())return{success:!1,failMessage:"CRITICAL: Browser/page closed before completing all tests. Increase test timeout or reduce test complexity."};let r=null,s;if(e.controlledBy){let i=e.controlledBy,n=this.selectors[i.target];if(!n)return{success:!1,failMessage:`Selector for controlledBy.target '${i.target}' not found.`,target:null};let a=null;if(i.relativeTarget?a=await se.resolve(this.page,n,i.relativeTarget):a=this.page.locator(n).first(),!a)return{success:!1,failMessage:"Controlling element for controlledBy not found.",target:null};let l=i.attribute||"aria-controls",u=await a.getAttribute(l);if(!u)return{success:!1,failMessage:`Controlling element does not have attribute '${l}'.`,target:null};if(r=this.page.locator(`#${u}`),!r||await r.count()===0)return{success:!1,failMessage:`Controlled element with id '${u}' not found.`,target:null}}else{let i=await this.resolveTarget(e.target,e.relativeTarget||e.expectedValue,e.selectorKey);if(r=i.target,s=i.error,s||!r)return{success:!1,failMessage:s||`Target ${e.target} not found.`,target:null}}if(e.target==="input"&&e.attribute==="aria-activedescendant"&&e.expectedValue==="!empty"&&e.relativeTarget&&e.selectorKey){let i=await se.resolve(this.page,this.selectors[e.selectorKey],e.relativeTarget),n=i?await i.getAttribute("id"):null,a=await r.getAttribute("aria-activedescendant");return n&&a===n?{success:!0,passMessage:`input[aria-activedescendant] matches id of ${e.relativeTarget}(${e.selectorKey}). Test: "${t}".`}:{success:!1,failMessage:`input[aria-activedescendant] should match id of ${e.relativeTarget}(${e.selectorKey}), found "${a}".`}}switch(e.assertion){case"toBeVisible":return this.validateVisibility(r,e.target,!0,e.failureMessage||"",t);case"notToBeVisible":return this.validateVisibility(r,e.target,!1,e.failureMessage||"",t);case"toHaveAttribute":return e.attribute&&e.expectedValue!==void 0?this.validateAttribute(r,e.target,e.attribute,e.expectedValue,e.failureMessage||"",t):{success:!1,failMessage:"Missing attribute or expectedValue for toHaveAttribute assertion"};case"toHaveValue":return e.expectedValue!==void 0?this.validateValue(r,e.target,e.expectedValue,e.failureMessage||"",t):{success:!1,failMessage:"Missing expectedValue for toHaveValue assertion"};case"toHaveFocus":return this.validateFocus(r,e.target,!0,e.failureMessage||"",t);case"notToHaveFocus":return this.validateFocus(r,e.target,!1,e.failureMessage||"",t);case"toHaveRole":return e.expectedValue!==void 0?this.validateRole(r,e.target,e.expectedValue,e.failureMessage||"",t):{success:!1,failMessage:"Missing expectedValue for toHaveRole assertion"};default:return{success:!1,failMessage:`Unknown assertion type: ${e.assertion}`}}}}});var Nt={};X(Nt,{runContractTestsPlaywright:()=>Ts});async function Ts(c,e,t,r,s){let i=r?.test?.components?.find(S=>S.name===c),n=!!i?.contractPath,a=new Le(!0,n),l={actionTimeoutMs:400,assertionTimeoutMs:400,navigationTimeoutMs:3e4,componentReadyTimeoutMs:5e3},u=r?.test?.disableTimeouts===!0,h=i?.disableTimeouts===!0||u,y=(S,ie,oe)=>{if(h)return 0;let ee=S??ie;return typeof ee!="number"||!Number.isFinite(ee)||ee<0?oe:ee},L=y(i?.actionTimeoutMs,r?.test?.actionTimeoutMs,l.actionTimeoutMs),H=y(i?.assertionTimeoutMs,r?.test?.assertionTimeoutMs,l.assertionTimeoutMs),M=y(i?.navigationTimeoutMs,r?.test?.navigationTimeoutMs,l.navigationTimeoutMs),U=y(i?.componentReadyTimeoutMs,r?.test?.componentReadyTimeoutMs,l.componentReadyTimeoutMs),W=$e(t),J=i?.contractPath;if(!J)throw new Error(`Contract path not found for component: ${c}`);let G=(()=>{if(Fe.default.isAbsolute(J))return J;if(s){let ie=Fe.default.resolve(s,J);try{return(0,Ie.readFileSync)(ie,"utf-8"),ie}catch{}}let S=Fe.default.resolve(process.cwd(),J);try{return(0,Ie.readFileSync)(S,"utf-8"),S}catch{return new URL(J,Cs.url).pathname}})(),Y=(0,Ie.readFileSync)(G,"utf-8"),v=JSON.parse(Y),Ce=(v.relationships?.length||0)+(v.static[0]?.assertions.length||0)+v.dynamic.length,Ue=v.meta?.source?.apg,Z=[],ae=[],ce=[],N=[],A=null,q=(S,ie)=>{let oe=fe(ie),ee=At(oe,W);if(ee==="error")return Z.push(S),{status:"fail",level:oe,detail:S};if(ee==="warning")return ae.push(S),{status:"warn",level:oe,detail:S};let ne=`${S} (ignored by strictness=${W}, level=${oe})`;return N.push(ne),{status:"skip",level:oe,detail:ne}};try{if(A=await Ct(),e){try{await A.goto(e,{waitUntil:"domcontentloaded",timeout:M})}catch(o){throw new Error(`Failed to navigate to ${e}. Ensure dev server is running and accessible. Original error: ${o instanceof Error?o.message:String(o)}`)}await A.addStyleTag({content:"* { transition: none !important; animation: none !important; }"})}let S=await Be.detect(c,i,L,H,s);if(!S)throw new Error(`Unsupported component: ${c}`);let ie=S.getMainSelector();if(!ie)throw new Error(`CRITICAL: No selector found in contract for ${c}`);try{await A.locator(ie).first().waitFor({state:"attached",timeout:U})}catch(o){throw new Error(`
|
|
136
136
|
\u274C CRITICAL: Component not found on page!
|
|
137
137
|
This usually means:
|
|
138
138
|
- The component didn't render
|
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import{a as x}from"./chunk-ZNQ5BXVJ.js";import{c as R,d as C}from"./chunk-52I3IN
|
|
|
13
13
|
\u274C Accessibility violations found!`)),console.log(o.yellow(` ${$} violation${$!==1?"s":""} detected across ${r.length} page${r.length!==1?"s":""}.`)),console.log(o.gray(` Review the generated report for details.
|
|
14
14
|
`)),console.log(o.dim(`
|
|
15
15
|
`+"\u2500".repeat(60))),console.log(o.cyan("\u{1F499} Found aria-ease helpful?")),console.log(o.white(" \u2022 Star us on GitHub: ")+o.blue.underline("https://github.com/aria-ease/aria-ease")),console.log(o.white(" \u2022 Share feedback: ")+o.blue.underline("https://github.com/aria-ease/aria-ease/discussions")),console.log(o.dim("\u2500".repeat(60)+`
|
|
16
|
-
`)),process.exit(1)});l.command("test").description("Run core a11y accessibility standard tests on UI components").action(async()=>{let{runTest:n}=await import("./test-
|
|
16
|
+
`)),process.exit(1)});l.command("test").description("Run core a11y accessibility standard tests on UI components").action(async()=>{let{runTest:n}=await import("./test-PCRWMQUO.js");n()});l.command("build").description("Build accessibility artifacts").addCommand(new S("contracts").description("Build DSL contracts to JSON").action(async()=>{let{buildContracts:n}=await import("./buildContracts-T4XQZBDU.js"),{loadConfig:h}=await import("./configLoader-ZXTSCIP6.js"),f=process.cwd(),{config:c,configPath:s,errors:u}=await h(f);s?console.log(o.green(`\u2705 Loaded config from ${w.basename(s)}
|
|
17
17
|
`)):u.length>0&&(console.log(o.red(`\u274C Config file has errors:
|
|
18
18
|
`)),u.forEach(d=>console.log(o.red(` ${d}`))),console.log(""),process.exit(1));let i=await n(f,c);!i.success&&i.errors.length>0&&(console.log(o.red(`\u274C ${i.errors.length} error${i.errors.length!==1?"s":""} occurred during build
|
|
19
19
|
`)),process.exit(1)),i.built.length===0&&(!c.contracts||c.contracts.length===0)&&process.exit(0),i.built.length===0&&(console.log(o.yellow(`\u26A0\uFE0F No contracts were built
|
package/dist/{contractTestRunnerPlaywright-IUUAGMXP.js → contractTestRunnerPlaywright-2CEH3GPM.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as j}from"./chunk-WIWSYIGK.js";import{a as Te,c as Q,d as Se,e as ke}from"./chunk-APUMBDOT.js";import{a as N}from"./chunk-SM6ZKEDR.js";import"./chunk-CNU4N4AY.js";import{readFileSync as de}from"fs";import he from"path";import{readFileSync as fe}from"fs";import ge from"path";import Ce from"path";import{pathToFileURL as Pe}from"url";var oe=class{builtInStrategies=new Map;constructor(){this.registerBuiltInStrategies()}registerBuiltInStrategies(){this.builtInStrategies.set("menu",()=>import("./MenuComponentStrategy-
|
|
1
|
+
import{a as j}from"./chunk-WIWSYIGK.js";import{a as Te,c as Q,d as Se,e as ke}from"./chunk-APUMBDOT.js";import{a as N}from"./chunk-SM6ZKEDR.js";import"./chunk-CNU4N4AY.js";import{readFileSync as de}from"fs";import he from"path";import{readFileSync as fe}from"fs";import ge from"path";import Ce from"path";import{pathToFileURL as Pe}from"url";var oe=class{builtInStrategies=new Map;constructor(){this.registerBuiltInStrategies()}registerBuiltInStrategies(){this.builtInStrategies.set("menu",()=>import("./MenuComponentStrategy-L3QXLC6S.js").then(t=>t.MenuComponentStrategy)),this.builtInStrategies.set("accordion",()=>import("./AccordionComponentStrategy-2SWMNUR6.js").then(t=>t.AccordionComponentStrategy)),this.builtInStrategies.set("combobox",()=>import("./ComboboxComponentStrategy-DHZS4NW6.js").then(t=>t.ComboboxComponentStrategy)),this.builtInStrategies.set("tabs",()=>import("./TabsComponentStrategy-LKV6D2B7.js").then(t=>t.TabsComponentStrategy))}async loadStrategy(t,s,r){try{if(s)try{let n=Ce.isAbsolute(s)?s:Ce.resolve(r||process.cwd(),s),u=await import(Pe(n).href),i=u.default||u;if(!i)throw new Error(`No default export found in ${s}`);return i}catch(n){throw new Error(`Failed to load custom strategy from ${s}: ${n instanceof Error?n.message:String(n)}`)}let o=this.builtInStrategies.get(t);return o?o():null}catch(o){throw new Error(`Strategy loading failed for ${t}: ${o instanceof Error?o.message:String(o)}`)}}has(t,s){return!!s||this.builtInStrategies.has(t)}};var ae=class{static strategyRegistry=new oe;static isComponentConfig(t){return typeof t=="object"&&t!==null}static async detect(t,s,r=400,o=400,n){let u=this.isComponentConfig(s)?s:void 0,i=u?.contractPath;if(!i)throw new Error(`Contract path not found for component: ${t}`);let R=(()=>{if(ge.isAbsolute(i))return i;if(n){let ie=ge.resolve(n,i);try{return fe(ie,"utf-8"),ie}catch{}}let X=ge.resolve(process.cwd(),i);try{return fe(X,"utf-8"),X}catch{return new URL(i,import.meta.url).pathname}})(),C=fe(R,"utf-8"),te=JSON.parse(C).selectors,_=await this.strategyRegistry.loadStrategy(t,u?.strategyPath,n);if(!_)return null;let z=te.main;return t==="tabs"?new _(z,te):new _(z,te,r,o)}};var ce=class{startTime=0;componentName="";staticPasses=0;staticFailures=0;staticWarnings=0;dynamicResults=[];totalTests=0;skipped=0;warnings=0;isPlaywright=!1;isCustomContract=!1;apgUrl="https://www.w3.org/WAI/ARIA/apg/";hasPrintedStaticSection=!1;hasPrintedDynamicSection=!1;constructor(t=!1,s=!1){this.isPlaywright=t,this.isCustomContract=s}log(t){process.stderr.write(t+`
|
|
2
2
|
`)}start(t,s,r){this.startTime=Date.now(),this.componentName=t,this.totalTests=s,this.hasPrintedStaticSection=!1,this.hasPrintedDynamicSection=!1,r&&(this.apgUrl=r);let o="Playwright (Real Browser)";this.log(`
|
|
3
3
|
${"\u2550".repeat(60)}`),this.log(`\u{1F50D} Testing ${t.charAt(0).toUpperCase()+t.slice(1)} Component - ${o}`),this.log(`${"\u2550".repeat(60)}
|
|
4
4
|
`)}reportStatic(t,s,r=0){this.staticPasses=t,this.staticFailures=s,this.staticWarnings=r}reportStaticTest(t,s,r,o){this.hasPrintedStaticSection||(this.log(`${"\u2500".repeat(60)}`),this.log("\u{1F9EA} Static Assertions"),this.log(`${"\u2500".repeat(60)}`),this.hasPrintedStaticSection=!0);let n=s==="pass"?"\u2713":s==="warn"?"\u26A0":s==="skip"?"\u25CB":"\u2717";this.log(` ${n} ${t}`),o&&this.log(` \u21B3 level=${o}`),(s==="fail"||s==="warn"||s==="skip")&&r&&this.log(` \u21B3 ${r}`)}reportTest(t,s,r){this.hasPrintedDynamicSection||(this.log(""),this.log(`${"\u2500".repeat(60)}`),this.log("\u2328\uFE0F Dynamic Interaction Tests"),this.log(`${"\u2500".repeat(60)}`),this.hasPrintedDynamicSection=!0);let o={description:t.description,status:s,failureMessage:r,level:t.level};s==="skip"&&(o.skipReason="Requires real browser (addEventListener events)"),this.dynamicResults.push(o);let n={pass:"\u2713",fail:"\u2717",warn:"\u26A0",skip:"\u25CB"},u=t.level?`[${t.level.toUpperCase()}] `:"";this.log(` ${n[s]} ${u}${t.description}`),s==="skip"&&!this.isPlaywright&&this.log(" \u21B3 Skipped (runs only in Playwright)"),s==="fail"&&r&&this.log(` \u21B3 ${r}`),s==="warn"&&r&&this.log(` \u21B3 ${r}`),s==="skip"&&r&&this.log(` \u21B3 ${r}`)}reportFailures(t){t.length!==0&&(this.log(`
|
|
@@ -19,7 +19,7 @@ ${"\u2550".repeat(60)}`),this.log(`\u{1F4CA} Summary
|
|
|
19
19
|
`),i>0?(this.log("\u{1F527} Next Steps:"),this.log(" 1. Review the failures above"),this.log(" 2. Fix ARIA attributes and keyboard handlers"),this.log(` 3. Re-run tests to verify fixes
|
|
20
20
|
`)):!this.isPlaywright&&this.skipped>0&&this.log(`\u2728 Optional: Run Playwright tests for complete validation
|
|
21
21
|
`),{passes:u,failures:i,skipped:this.skipped,duration:s}}error(t,s){this.log(`
|
|
22
|
-
\u274C Error: ${t}`),s&&this.log(` Context: ${s}`),this.log("")}};var ee=class{constructor(t,s,r=400){this.page=t;this.selectors=s;this.timeoutMs=r}isBrowserClosedError(t){return t instanceof Error&&t.message.includes("Target page, context or browser has been closed")}async focus(t,s,r){try{if(t==="virtual"&&r){let n=this.selectors.main;if(!n)return{success:!1,error:"Main selector not defined for virtual focus."};let u=this.page.locator(n).first();return await u.count()?(await u.evaluate((R,C)=>{R.setAttribute("aria-activedescendant",C)},r),{success:!0}):{success:!1,error:"Main element not found for virtual focus."}}if(t==="relative"&&s){let n=this.selectors.relative;if(!n)return{success:!1,error:"Relative selector not defined for focus action."};let u=await j.resolve(this.page,n,s);return u?(await u.focus({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${s} for focus.`}}let o=this.selectors[t];return o?(await this.page.locator(o).first().focus({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for focus target ${t} not found.`}}catch(o){return this.isBrowserClosedError(o)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to focus ${t}: ${o instanceof Error?o.message:String(o)}`}}}async type(t,s){try{let r=this.selectors[t];return r?(await this.page.locator(r).first().fill(s,{timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for type target ${t} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to type into ${t}: ${r instanceof Error?r.message:String(r)}`}}}async click(t,s){try{if(t==="document")return await this.page.mouse.click(10,10),{success:!0};if(t==="relative"&&s){let o=this.selectors.relative;if(!o)return{success:!1,error:"Relative selector not defined for click action."};let n=await j.resolve(this.page,o,s);return n?(await n.click({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${s} for click.`}}let r=this.selectors[t];return r?(await this.page.locator(r).first().click({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for action target ${t} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to click ${t}: ${r instanceof Error?r.message:String(r)}`}}}async keypress(t,s,r){try{let n={Space:"Space",Enter:"Enter",Escape:"Escape","Arrow Up":"ArrowUp","Arrow Down":"ArrowDown","Arrow Left":"ArrowLeft","Arrow Right":"ArrowRight",Home:"Home",End:"End",Tab:"Tab"}[s]||s;if(n==="Space"?n=" ":n.includes(" ")&&(n=n.replace(/ /g,"")),t==="focusable"&&["ArrowUp","ArrowDown","ArrowLeft","ArrowRight","Escape","Home","End","Tab","Shift+Tab"].includes(n))return await this.page.keyboard.press(n),{success:!0};if(t==="relative"){if(r==null)return{success:!1,error:"relativeTarget must be provided for relative keypress."};let C=this.selectors.relative;if(!C)return{success:!1,error:"Relative selector not defined for keypress action."};let A=await j.resolve(this.page,C,r);return A?(await A.press(n,{timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${r} for keypress.`}}let u=this.selectors[t];if(!u)return{success:!1,error:`Selector for keypress target ${t} not found.`};let i=this.page.locator(u).first();return await i.count()===0?{success:!1,error:`${t} element not found.`,shouldBreak:!0}:(await i.press(n,{timeout:this.timeoutMs}),{success:!0})}catch(o){return this.isBrowserClosedError(o)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to press ${s} on ${t}: ${o instanceof Error?o.message:String(o)}`}}}async hover(t,s){try{if(t==="relative"&&s){let o=this.selectors.relative;if(!o)return{success:!1,error:"Relative selector not defined for hover action."};let n=await j.resolve(this.page,o,s);return n?(await n.hover({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${s} for hover.`}}let r=this.selectors[t];return r?(await this.page.locator(r).first().hover({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for hover target ${t} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to hover ${t}: ${r instanceof Error?r.message:String(r)}`}}}};var re=class{constructor(t,s,r=400){this.page=t;this.selectors=s;this.timeoutMs=r}async resolveTarget(t,s,r){try{if(t==="relative"){let n=r?this.selectors[r]:this.selectors.relative;if(!n)return{target:null,error:"Relative selector is not defined in the contract."};if(!s)return{target:null,error:"Relative target or expected value is not defined."};let u=await j.resolve(this.page,n,s);return u?{target:u}:{target:null,error:`Target ${t} not found.`}}let o=this.selectors[t];return o?{target:this.page.locator(o).first()}:{target:null,error:`Selector for assertion target ${t} not found.`}}catch(o){return{target:null,error:`Failed to resolve target ${t}: ${o instanceof Error?o.message:String(o)}`}}}async validateVisibility(t,s,r,o,n){try{return r?(await(0,N.expect)(t).toBeVisible({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} is visible as expected. Test: "${n}".`}):(await(0,N.expect)(t).toBeHidden({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} is not visible as expected. Test: "${n}".`})}catch{let u=this.selectors[s]||"",i=await this.page.evaluate(R=>{let C=R?document.querySelector(R):null;if(!C)return"element not found";let A=window.getComputedStyle(C);return`display:${A.display}, visibility:${A.visibility}, opacity:${A.opacity}`},u);return r?{success:!1,failMessage:`${o} (actual: ${i})`}:{success:!1,failMessage:`${o} ${s} is still visible (actual: ${i}).`}}}async validateAttribute(t,s,r,o,n,u){if(o==="!empty"){let C=await t.getAttribute(r);return C&&C.trim()!==""?{success:!0,passMessage:`${s} has non-empty "${r}". Test: "${u}".`}:{success:!1,failMessage:`${n} ${s} "${r}" should not be empty, found "${C}".`}}if(typeof o!="string")throw console.error("[AssertionRunner] expectedValue is not a string:",o),new Error(`AssertionRunner: expectedValue for attribute assertion must be a string, but got: ${JSON.stringify(o)}`);let i=o.split(" | ").map(C=>C.trim()),R=await t.getAttribute(r);return R!==null&&i.includes(R)?{success:!0,passMessage:`${s} has expected "${r}". Test: "${u}".`}:{success:!1,failMessage:`${n} ${s} "${r}" should be "${o}", found "${R}".`}}async validateValue(t,s,r,o,n){let u=await t.inputValue().catch(()=>"");return r==="!empty"?u&&u.trim()!==""?{success:!0,passMessage:`${s} has non-empty value. Test: "${n}".`}:{success:!1,failMessage:`${o} ${s} value should not be empty, found "${u}".`}:r===""?u===""?{success:!0,passMessage:`${s} has empty value. Test: "${n}".`}:{success:!1,failMessage:`${o} ${s} value should be empty, found "${u}".`}:u===r?{success:!0,passMessage:`${s} has expected value. Test: "${n}".`}:{success:!1,failMessage:`${o} ${s} value should be "${r}", found "${u}".`}}async validateFocus(t,s,r,o,n){try{return r?(await(0,N.expect)(t).toBeFocused({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} has focus as expected. Test: "${n}".`}):(await(0,N.expect)(t).not.toBeFocused({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} does not have focus as expected. Test: "${n}".`})}catch{let u=await this.page.evaluate(()=>{let i=document.activeElement;return i?`${i.tagName}#${i.id||"no-id"}.${i.className||"no-class"}`:"no element focused"});return{success:!1,failMessage:`${o} (actual focus: ${u})`}}}async validateRole(t,s,r,o,n){let u=await t.getAttribute("role");return u===r?{success:!0,passMessage:`${s} has role "${r}". Test: "${n}".`}:{success:!1,failMessage:`${o} Expected role "${r}", found "${u}".`}}async validate(t,s){if(this.page.isClosed())return{success:!1,failMessage:"CRITICAL: Browser/page closed before completing all tests. Increase test timeout or reduce test complexity."};let r=null,o;if(t.controlledBy){let n=t.controlledBy,u=this.selectors[n.target];if(!u)return{success:!1,failMessage:`Selector for controlledBy.target '${n.target}' not found.`,target:null};let i=null;if(n.relativeTarget?i=await j.resolve(this.page,u,n.relativeTarget):i=this.page.locator(u).first(),!i)return{success:!1,failMessage:"Controlling element for controlledBy not found.",target:null};let R=n.attribute||"aria-controls",C=await i.getAttribute(R);if(!C)return{success:!1,failMessage:`Controlling element does not have attribute '${R}'.`,target:null};if(r=this.page.locator(`#${C}`),!r||await r.count()===0)return{success:!1,failMessage:`Controlled element with id '${C}' not found.`,target:null}}else{let n=await this.resolveTarget(t.target,t.relativeTarget||t.expectedValue,t.selectorKey);if(r=n.target,o=n.error,o||!r)return{success:!1,failMessage:o||`Target ${t.target} not found.`,target:null}}if(t.target==="input"&&t.attribute==="aria-activedescendant"&&t.expectedValue==="!empty"&&t.relativeTarget&&t.selectorKey){let n=await j.resolve(this.page,this.selectors[t.selectorKey],t.relativeTarget),u=n?await n.getAttribute("id"):null,i=await r.getAttribute("aria-activedescendant");return u&&i===u?{success:!0,passMessage:`input[aria-activedescendant] matches id of ${t.relativeTarget}(${t.selectorKey}). Test: "${s}".`}:{success:!1,failMessage:`input[aria-activedescendant] should match id of ${t.relativeTarget}(${t.selectorKey}), found "${i}".`}}switch(t.assertion){case"toBeVisible":return this.validateVisibility(r,t.target,!0,t.failureMessage||"",s);case"notToBeVisible":return this.validateVisibility(r,t.target,!1,t.failureMessage||"",s);case"toHaveAttribute":return t.attribute&&t.expectedValue!==void 0?this.validateAttribute(r,t.target,t.attribute,t.expectedValue,t.failureMessage||"",s):{success:!1,failMessage:"Missing attribute or expectedValue for toHaveAttribute assertion"};case"toHaveValue":return t.expectedValue!==void 0?this.validateValue(r,t.target,t.expectedValue,t.failureMessage||"",s):{success:!1,failMessage:"Missing expectedValue for toHaveValue assertion"};case"toHaveFocus":return this.validateFocus(r,t.target,!0,t.failureMessage||"",s);case"notToHaveFocus":return this.validateFocus(r,t.target,!1,t.failureMessage||"",s);case"toHaveRole":return t.expectedValue!==void 0?this.validateRole(r,t.target,t.expectedValue,t.failureMessage||"",s):{success:!1,failMessage:"Missing expectedValue for toHaveRole assertion"};default:return{success:!1,failMessage:`Unknown assertion type: ${t.assertion}`}}}};async function tt(M,t,s,r,o){let n=r?.test?.components?.find(d=>d.name===M),u=!!n?.contractPath,i=new ce(!0,u),R={actionTimeoutMs:400,assertionTimeoutMs:400,navigationTimeoutMs:3e4,componentReadyTimeoutMs:5e3},C=r?.test?.disableTimeouts===!0,te=n?.disableTimeouts===!0||C,_=(d,H,O)=>{if(te)return 0;let F=d??H;return typeof F!="number"||!Number.isFinite(F)||F<0?O:F},z=_(n?.actionTimeoutMs,r?.test?.actionTimeoutMs,R.actionTimeoutMs),X=_(n?.assertionTimeoutMs,r?.test?.assertionTimeoutMs,R.assertionTimeoutMs),ie=_(n?.navigationTimeoutMs,r?.test?.navigationTimeoutMs,R.navigationTimeoutMs),le=_(n?.componentReadyTimeoutMs,r?.test?.componentReadyTimeoutMs,R.componentReadyTimeoutMs),me=Se(s),Y=n?.contractPath;if(!Y)throw new Error(`Contract path not found for component: ${M}`);let Re=(()=>{if(he.isAbsolute(Y))return Y;if(o){let H=he.resolve(o,Y);try{return de(H,"utf-8"),H}catch{}}let d=he.resolve(process.cwd(),Y);try{return de(d,"utf-8"),d}catch{return new URL(Y,import.meta.url).pathname}})(),Ae=de(Re,"utf-8"),b=JSON.parse(Ae),Me=(b.relationships?.length||0)+(b.static[0]?.assertions.length||0)+b.dynamic.length,Ee=b.meta?.source?.apg,V=[],K=[],q=[],x=[],y=null,E=(d,H)=>{let O=Q(H),F=ke(O,me);if(F==="error")return V.push(d),{status:"fail",level:O,detail:d};if(F==="warning")return K.push(d),{status:"warn",level:O,detail:d};let D=`${d} (ignored by strictness=${me}, level=${O})`;return x.push(D),{status:"skip",level:O,detail:D}};try{if(y=await Te(),t){try{await y.goto(t,{waitUntil:"domcontentloaded",timeout:ie})}catch(e){throw new Error(`Failed to navigate to ${t}. Ensure dev server is running and accessible. Original error: ${e instanceof Error?e.message:String(e)}`)}await y.addStyleTag({content:"* { transition: none !important; animation: none !important; }"})}let d=await ae.detect(M,n,z,X,o);if(!d)throw new Error(`Unsupported component: ${M}`);let H=d.getMainSelector();if(!H)throw new Error(`CRITICAL: No selector found in contract for ${M}`);try{await y.locator(H).first().waitFor({state:"attached",timeout:le})}catch(e){throw new Error(`
|
|
22
|
+
\u274C Error: ${t}`),s&&this.log(` Context: ${s}`),this.log("")}};var ee=class{constructor(t,s,r=400){this.page=t;this.selectors=s;this.timeoutMs=r}isBrowserClosedError(t){return t instanceof Error&&t.message.includes("Target page, context or browser has been closed")}async focus(t,s,r){try{if(t==="virtual"&&r){let n=this.selectors.main;if(!n)return{success:!1,error:"Main selector not defined for virtual focus."};let u=this.page.locator(n).first();return await u.count()?(await u.evaluate((R,C)=>{R.setAttribute("aria-activedescendant",C)},r),{success:!0}):{success:!1,error:"Main element not found for virtual focus."}}if(t==="relative"&&s){let n=this.selectors.relative;if(!n)return{success:!1,error:"Relative selector not defined for focus action."};let u=await j.resolve(this.page,n,s);return u?(await u.focus({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${s} for focus.`}}let o=this.selectors[t];return o?(await this.page.locator(o).first().focus({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for focus target ${t} not found.`}}catch(o){return this.isBrowserClosedError(o)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to focus ${t}: ${o instanceof Error?o.message:String(o)}`}}}async type(t,s){try{let r=this.selectors[t];return r?(await this.page.locator(r).first().fill(s,{timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for type target ${t} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to type into ${t}: ${r instanceof Error?r.message:String(r)}`}}}async click(t,s){try{if(t==="document")return await this.page.mouse.click(10,10),{success:!0};if(t==="relative"&&s){let o=this.selectors.relative;if(!o)return{success:!1,error:"Relative selector not defined for click action."};let n=await j.resolve(this.page,o,s);return n?(await n.click({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${s} for click.`}}let r=this.selectors[t];return r?(await this.page.locator(r).first().click({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for action target ${t} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to click ${t}: ${r instanceof Error?r.message:String(r)}`}}}async keypress(t,s,r){try{let n={Space:"Space",Enter:"Enter",Escape:"Escape","Arrow Up":"ArrowUp","Arrow Down":"ArrowDown","Arrow Left":"ArrowLeft","Arrow Right":"ArrowRight",Home:"Home",End:"End",Tab:"Tab"}[s]||s;if(n==="Space"?n=" ":n.includes(" ")&&(n=n.replace(/ /g,"")),t==="relative"){if(r==null)return{success:!1,error:"relativeTarget must be provided for relative keypress."};let C=this.selectors.relative;if(!C)return{success:!1,error:"Relative selector not defined for keypress action."};let A=await j.resolve(this.page,C,r);return A?(await A.press(n,{timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${r} for keypress.`}}let u=this.selectors[t];if(!u)return{success:!1,error:`Selector for keypress target ${t} not found.`};let i=this.page.locator(u).first();return await i.count()===0?{success:!1,error:`${t} element not found.`,shouldBreak:!0}:(await i.press(n,{timeout:this.timeoutMs}),{success:!0})}catch(o){return this.isBrowserClosedError(o)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to press ${s} on ${t}: ${o instanceof Error?o.message:String(o)}`}}}async hover(t,s){try{if(t==="relative"&&s){let o=this.selectors.relative;if(!o)return{success:!1,error:"Relative selector not defined for hover action."};let n=await j.resolve(this.page,o,s);return n?(await n.hover({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${s} for hover.`}}let r=this.selectors[t];return r?(await this.page.locator(r).first().hover({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for hover target ${t} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to hover ${t}: ${r instanceof Error?r.message:String(r)}`}}}};var re=class{constructor(t,s,r=400){this.page=t;this.selectors=s;this.timeoutMs=r}async resolveTarget(t,s,r){try{if(t==="relative"){let n=r?this.selectors[r]:this.selectors.relative;if(!n)return{target:null,error:"Relative selector is not defined in the contract."};if(!s)return{target:null,error:"Relative target or expected value is not defined."};let u=await j.resolve(this.page,n,s);return u?{target:u}:{target:null,error:`Target ${t} not found.`}}let o=this.selectors[t];return o?{target:this.page.locator(o).first()}:{target:null,error:`Selector for assertion target ${t} not found.`}}catch(o){return{target:null,error:`Failed to resolve target ${t}: ${o instanceof Error?o.message:String(o)}`}}}async validateVisibility(t,s,r,o,n){try{return r?(await(0,N.expect)(t).toBeVisible({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} is visible as expected. Test: "${n}".`}):(await(0,N.expect)(t).toBeHidden({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} is not visible as expected. Test: "${n}".`})}catch{let u=this.selectors[s]||"",i=await this.page.evaluate(R=>{let C=R?document.querySelector(R):null;if(!C)return"element not found";let A=window.getComputedStyle(C);return`display:${A.display}, visibility:${A.visibility}, opacity:${A.opacity}`},u);return r?{success:!1,failMessage:`${o} (actual: ${i})`}:{success:!1,failMessage:`${o} ${s} is still visible (actual: ${i}).`}}}async validateAttribute(t,s,r,o,n,u){if(o==="!empty"){let C=await t.getAttribute(r);return C&&C.trim()!==""?{success:!0,passMessage:`${s} has non-empty "${r}". Test: "${u}".`}:{success:!1,failMessage:`${n} ${s} "${r}" should not be empty, found "${C}".`}}if(typeof o!="string")throw console.error("[AssertionRunner] expectedValue is not a string:",o),new Error(`AssertionRunner: expectedValue for attribute assertion must be a string, but got: ${JSON.stringify(o)}`);let i=o.split(" | ").map(C=>C.trim()),R=await t.getAttribute(r);return R!==null&&i.includes(R)?{success:!0,passMessage:`${s} has expected "${r}". Test: "${u}".`}:{success:!1,failMessage:`${n} ${s} "${r}" should be "${o}", found "${R}".`}}async validateValue(t,s,r,o,n){let u=await t.inputValue().catch(()=>"");return r==="!empty"?u&&u.trim()!==""?{success:!0,passMessage:`${s} has non-empty value. Test: "${n}".`}:{success:!1,failMessage:`${o} ${s} value should not be empty, found "${u}".`}:r===""?u===""?{success:!0,passMessage:`${s} has empty value. Test: "${n}".`}:{success:!1,failMessage:`${o} ${s} value should be empty, found "${u}".`}:u===r?{success:!0,passMessage:`${s} has expected value. Test: "${n}".`}:{success:!1,failMessage:`${o} ${s} value should be "${r}", found "${u}".`}}async validateFocus(t,s,r,o,n){try{return r?(await(0,N.expect)(t).toBeFocused({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} has focus as expected. Test: "${n}".`}):(await(0,N.expect)(t).not.toBeFocused({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} does not have focus as expected. Test: "${n}".`})}catch{let u=await this.page.evaluate(()=>{let i=document.activeElement;return i?`${i.tagName}#${i.id||"no-id"}.${i.className||"no-class"}`:"no element focused"});return{success:!1,failMessage:`${o} (actual focus: ${u})`}}}async validateRole(t,s,r,o,n){let u=await t.getAttribute("role");return u===r?{success:!0,passMessage:`${s} has role "${r}". Test: "${n}".`}:{success:!1,failMessage:`${o} Expected role "${r}", found "${u}".`}}async validate(t,s){if(this.page.isClosed())return{success:!1,failMessage:"CRITICAL: Browser/page closed before completing all tests. Increase test timeout or reduce test complexity."};let r=null,o;if(t.controlledBy){let n=t.controlledBy,u=this.selectors[n.target];if(!u)return{success:!1,failMessage:`Selector for controlledBy.target '${n.target}' not found.`,target:null};let i=null;if(n.relativeTarget?i=await j.resolve(this.page,u,n.relativeTarget):i=this.page.locator(u).first(),!i)return{success:!1,failMessage:"Controlling element for controlledBy not found.",target:null};let R=n.attribute||"aria-controls",C=await i.getAttribute(R);if(!C)return{success:!1,failMessage:`Controlling element does not have attribute '${R}'.`,target:null};if(r=this.page.locator(`#${C}`),!r||await r.count()===0)return{success:!1,failMessage:`Controlled element with id '${C}' not found.`,target:null}}else{let n=await this.resolveTarget(t.target,t.relativeTarget||t.expectedValue,t.selectorKey);if(r=n.target,o=n.error,o||!r)return{success:!1,failMessage:o||`Target ${t.target} not found.`,target:null}}if(t.target==="input"&&t.attribute==="aria-activedescendant"&&t.expectedValue==="!empty"&&t.relativeTarget&&t.selectorKey){let n=await j.resolve(this.page,this.selectors[t.selectorKey],t.relativeTarget),u=n?await n.getAttribute("id"):null,i=await r.getAttribute("aria-activedescendant");return u&&i===u?{success:!0,passMessage:`input[aria-activedescendant] matches id of ${t.relativeTarget}(${t.selectorKey}). Test: "${s}".`}:{success:!1,failMessage:`input[aria-activedescendant] should match id of ${t.relativeTarget}(${t.selectorKey}), found "${i}".`}}switch(t.assertion){case"toBeVisible":return this.validateVisibility(r,t.target,!0,t.failureMessage||"",s);case"notToBeVisible":return this.validateVisibility(r,t.target,!1,t.failureMessage||"",s);case"toHaveAttribute":return t.attribute&&t.expectedValue!==void 0?this.validateAttribute(r,t.target,t.attribute,t.expectedValue,t.failureMessage||"",s):{success:!1,failMessage:"Missing attribute or expectedValue for toHaveAttribute assertion"};case"toHaveValue":return t.expectedValue!==void 0?this.validateValue(r,t.target,t.expectedValue,t.failureMessage||"",s):{success:!1,failMessage:"Missing expectedValue for toHaveValue assertion"};case"toHaveFocus":return this.validateFocus(r,t.target,!0,t.failureMessage||"",s);case"notToHaveFocus":return this.validateFocus(r,t.target,!1,t.failureMessage||"",s);case"toHaveRole":return t.expectedValue!==void 0?this.validateRole(r,t.target,t.expectedValue,t.failureMessage||"",s):{success:!1,failMessage:"Missing expectedValue for toHaveRole assertion"};default:return{success:!1,failMessage:`Unknown assertion type: ${t.assertion}`}}}};async function tt(M,t,s,r,o){let n=r?.test?.components?.find(d=>d.name===M),u=!!n?.contractPath,i=new ce(!0,u),R={actionTimeoutMs:400,assertionTimeoutMs:400,navigationTimeoutMs:3e4,componentReadyTimeoutMs:5e3},C=r?.test?.disableTimeouts===!0,te=n?.disableTimeouts===!0||C,_=(d,H,O)=>{if(te)return 0;let F=d??H;return typeof F!="number"||!Number.isFinite(F)||F<0?O:F},z=_(n?.actionTimeoutMs,r?.test?.actionTimeoutMs,R.actionTimeoutMs),X=_(n?.assertionTimeoutMs,r?.test?.assertionTimeoutMs,R.assertionTimeoutMs),ie=_(n?.navigationTimeoutMs,r?.test?.navigationTimeoutMs,R.navigationTimeoutMs),le=_(n?.componentReadyTimeoutMs,r?.test?.componentReadyTimeoutMs,R.componentReadyTimeoutMs),me=Se(s),Y=n?.contractPath;if(!Y)throw new Error(`Contract path not found for component: ${M}`);let Re=(()=>{if(he.isAbsolute(Y))return Y;if(o){let H=he.resolve(o,Y);try{return de(H,"utf-8"),H}catch{}}let d=he.resolve(process.cwd(),Y);try{return de(d,"utf-8"),d}catch{return new URL(Y,import.meta.url).pathname}})(),Ae=de(Re,"utf-8"),b=JSON.parse(Ae),Me=(b.relationships?.length||0)+(b.static[0]?.assertions.length||0)+b.dynamic.length,Ee=b.meta?.source?.apg,V=[],K=[],q=[],x=[],y=null,E=(d,H)=>{let O=Q(H),F=ke(O,me);if(F==="error")return V.push(d),{status:"fail",level:O,detail:d};if(F==="warning")return K.push(d),{status:"warn",level:O,detail:d};let D=`${d} (ignored by strictness=${me}, level=${O})`;return x.push(D),{status:"skip",level:O,detail:D}};try{if(y=await Te(),t){try{await y.goto(t,{waitUntil:"domcontentloaded",timeout:ie})}catch(e){throw new Error(`Failed to navigate to ${t}. Ensure dev server is running and accessible. Original error: ${e instanceof Error?e.message:String(e)}`)}await y.addStyleTag({content:"* { transition: none !important; animation: none !important; }"})}let d=await ae.detect(M,n,z,X,o);if(!d)throw new Error(`Unsupported component: ${M}`);let H=d.getMainSelector();if(!H)throw new Error(`CRITICAL: No selector found in contract for ${M}`);try{await y.locator(H).first().waitFor({state:"attached",timeout:le})}catch(e){throw new Error(`
|
|
23
23
|
\u274C CRITICAL: Component not found on page!
|
|
24
24
|
This usually means:
|
|
25
25
|
- The component didn't render
|
package/dist/{contractTestRunnerPlaywright-44QPA5JG.js → contractTestRunnerPlaywright-RUKMUY5P.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as Te,c as Q,d as Se,e as ke}from"./chunk-APUMBDOT.js";import{a as N}from"./chunk-SM6ZKEDR.js";import{a as j}from"./chunk-WIWSYIGK.js";import"./chunk-CNU4N4AY.js";import{readFileSync as de}from"fs";import he from"path";import{readFileSync as fe}from"fs";import ge from"path";import Ce from"path";import{pathToFileURL as Pe}from"url";var oe=class{builtInStrategies=new Map;constructor(){this.registerBuiltInStrategies()}registerBuiltInStrategies(){this.builtInStrategies.set("menu",()=>import("./MenuComponentStrategy-
|
|
1
|
+
import{a as Te,c as Q,d as Se,e as ke}from"./chunk-APUMBDOT.js";import{a as N}from"./chunk-SM6ZKEDR.js";import{a as j}from"./chunk-WIWSYIGK.js";import"./chunk-CNU4N4AY.js";import{readFileSync as de}from"fs";import he from"path";import{readFileSync as fe}from"fs";import ge from"path";import Ce from"path";import{pathToFileURL as Pe}from"url";var oe=class{builtInStrategies=new Map;constructor(){this.registerBuiltInStrategies()}registerBuiltInStrategies(){this.builtInStrategies.set("menu",()=>import("./MenuComponentStrategy-L3QXLC6S.js").then(t=>t.MenuComponentStrategy)),this.builtInStrategies.set("accordion",()=>import("./AccordionComponentStrategy-2SWMNUR6.js").then(t=>t.AccordionComponentStrategy)),this.builtInStrategies.set("combobox",()=>import("./ComboboxComponentStrategy-DHZS4NW6.js").then(t=>t.ComboboxComponentStrategy)),this.builtInStrategies.set("tabs",()=>import("./TabsComponentStrategy-LKV6D2B7.js").then(t=>t.TabsComponentStrategy))}async loadStrategy(t,s,r){try{if(s)try{let n=Ce.isAbsolute(s)?s:Ce.resolve(r||process.cwd(),s),u=await import(Pe(n).href),i=u.default||u;if(!i)throw new Error(`No default export found in ${s}`);return i}catch(n){throw new Error(`Failed to load custom strategy from ${s}: ${n instanceof Error?n.message:String(n)}`)}let o=this.builtInStrategies.get(t);return o?o():null}catch(o){throw new Error(`Strategy loading failed for ${t}: ${o instanceof Error?o.message:String(o)}`)}}has(t,s){return!!s||this.builtInStrategies.has(t)}};var ae=class{static strategyRegistry=new oe;static isComponentConfig(t){return typeof t=="object"&&t!==null}static async detect(t,s,r=400,o=400,n){let u=this.isComponentConfig(s)?s:void 0,i=u?.contractPath;if(!i)throw new Error(`Contract path not found for component: ${t}`);let R=(()=>{if(ge.isAbsolute(i))return i;if(n){let ie=ge.resolve(n,i);try{return fe(ie,"utf-8"),ie}catch{}}let X=ge.resolve(process.cwd(),i);try{return fe(X,"utf-8"),X}catch{return new URL(i,import.meta.url).pathname}})(),C=fe(R,"utf-8"),te=JSON.parse(C).selectors,_=await this.strategyRegistry.loadStrategy(t,u?.strategyPath,n);if(!_)return null;let z=te.main;return t==="tabs"?new _(z,te):new _(z,te,r,o)}};var ce=class{startTime=0;componentName="";staticPasses=0;staticFailures=0;staticWarnings=0;dynamicResults=[];totalTests=0;skipped=0;warnings=0;isPlaywright=!1;isCustomContract=!1;apgUrl="https://www.w3.org/WAI/ARIA/apg/";hasPrintedStaticSection=!1;hasPrintedDynamicSection=!1;constructor(t=!1,s=!1){this.isPlaywright=t,this.isCustomContract=s}log(t){process.stderr.write(t+`
|
|
2
2
|
`)}start(t,s,r){this.startTime=Date.now(),this.componentName=t,this.totalTests=s,this.hasPrintedStaticSection=!1,this.hasPrintedDynamicSection=!1,r&&(this.apgUrl=r);let o="Playwright (Real Browser)";this.log(`
|
|
3
3
|
${"\u2550".repeat(60)}`),this.log(`\u{1F50D} Testing ${t.charAt(0).toUpperCase()+t.slice(1)} Component - ${o}`),this.log(`${"\u2550".repeat(60)}
|
|
4
4
|
`)}reportStatic(t,s,r=0){this.staticPasses=t,this.staticFailures=s,this.staticWarnings=r}reportStaticTest(t,s,r,o){this.hasPrintedStaticSection||(this.log(`${"\u2500".repeat(60)}`),this.log("\u{1F9EA} Static Assertions"),this.log(`${"\u2500".repeat(60)}`),this.hasPrintedStaticSection=!0);let n=s==="pass"?"\u2713":s==="warn"?"\u26A0":s==="skip"?"\u25CB":"\u2717";this.log(` ${n} ${t}`),o&&this.log(` \u21B3 level=${o}`),(s==="fail"||s==="warn"||s==="skip")&&r&&this.log(` \u21B3 ${r}`)}reportTest(t,s,r){this.hasPrintedDynamicSection||(this.log(""),this.log(`${"\u2500".repeat(60)}`),this.log("\u2328\uFE0F Dynamic Interaction Tests"),this.log(`${"\u2500".repeat(60)}`),this.hasPrintedDynamicSection=!0);let o={description:t.description,status:s,failureMessage:r,level:t.level};s==="skip"&&(o.skipReason="Requires real browser (addEventListener events)"),this.dynamicResults.push(o);let n={pass:"\u2713",fail:"\u2717",warn:"\u26A0",skip:"\u25CB"},u=t.level?`[${t.level.toUpperCase()}] `:"";this.log(` ${n[s]} ${u}${t.description}`),s==="skip"&&!this.isPlaywright&&this.log(" \u21B3 Skipped (runs only in Playwright)"),s==="fail"&&r&&this.log(` \u21B3 ${r}`),s==="warn"&&r&&this.log(` \u21B3 ${r}`),s==="skip"&&r&&this.log(` \u21B3 ${r}`)}reportFailures(t){t.length!==0&&(this.log(`
|
|
@@ -19,7 +19,7 @@ ${"\u2550".repeat(60)}`),this.log(`\u{1F4CA} Summary
|
|
|
19
19
|
`),i>0?(this.log("\u{1F527} Next Steps:"),this.log(" 1. Review the failures above"),this.log(" 2. Fix ARIA attributes and keyboard handlers"),this.log(` 3. Re-run tests to verify fixes
|
|
20
20
|
`)):!this.isPlaywright&&this.skipped>0&&this.log(`\u2728 Optional: Run Playwright tests for complete validation
|
|
21
21
|
`),{passes:u,failures:i,skipped:this.skipped,duration:s}}error(t,s){this.log(`
|
|
22
|
-
\u274C Error: ${t}`),s&&this.log(` Context: ${s}`),this.log("")}};var ee=class{constructor(t,s,r=400){this.page=t;this.selectors=s;this.timeoutMs=r}isBrowserClosedError(t){return t instanceof Error&&t.message.includes("Target page, context or browser has been closed")}async focus(t,s,r){try{if(t==="virtual"&&r){let n=this.selectors.main;if(!n)return{success:!1,error:"Main selector not defined for virtual focus."};let u=this.page.locator(n).first();return await u.count()?(await u.evaluate((R,C)=>{R.setAttribute("aria-activedescendant",C)},r),{success:!0}):{success:!1,error:"Main element not found for virtual focus."}}if(t==="relative"&&s){let n=this.selectors.relative;if(!n)return{success:!1,error:"Relative selector not defined for focus action."};let u=await j.resolve(this.page,n,s);return u?(await u.focus({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${s} for focus.`}}let o=this.selectors[t];return o?(await this.page.locator(o).first().focus({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for focus target ${t} not found.`}}catch(o){return this.isBrowserClosedError(o)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to focus ${t}: ${o instanceof Error?o.message:String(o)}`}}}async type(t,s){try{let r=this.selectors[t];return r?(await this.page.locator(r).first().fill(s,{timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for type target ${t} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to type into ${t}: ${r instanceof Error?r.message:String(r)}`}}}async click(t,s){try{if(t==="document")return await this.page.mouse.click(10,10),{success:!0};if(t==="relative"&&s){let o=this.selectors.relative;if(!o)return{success:!1,error:"Relative selector not defined for click action."};let n=await j.resolve(this.page,o,s);return n?(await n.click({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${s} for click.`}}let r=this.selectors[t];return r?(await this.page.locator(r).first().click({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for action target ${t} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to click ${t}: ${r instanceof Error?r.message:String(r)}`}}}async keypress(t,s,r){try{let n={Space:"Space",Enter:"Enter",Escape:"Escape","Arrow Up":"ArrowUp","Arrow Down":"ArrowDown","Arrow Left":"ArrowLeft","Arrow Right":"ArrowRight",Home:"Home",End:"End",Tab:"Tab"}[s]||s;if(n==="Space"?n=" ":n.includes(" ")&&(n=n.replace(/ /g,"")),t==="focusable"&&["ArrowUp","ArrowDown","ArrowLeft","ArrowRight","Escape","Home","End","Tab","Shift+Tab"].includes(n))return await this.page.keyboard.press(n),{success:!0};if(t==="relative"){if(r==null)return{success:!1,error:"relativeTarget must be provided for relative keypress."};let C=this.selectors.relative;if(!C)return{success:!1,error:"Relative selector not defined for keypress action."};let A=await j.resolve(this.page,C,r);return A?(await A.press(n,{timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${r} for keypress.`}}let u=this.selectors[t];if(!u)return{success:!1,error:`Selector for keypress target ${t} not found.`};let i=this.page.locator(u).first();return await i.count()===0?{success:!1,error:`${t} element not found.`,shouldBreak:!0}:(await i.press(n,{timeout:this.timeoutMs}),{success:!0})}catch(o){return this.isBrowserClosedError(o)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to press ${s} on ${t}: ${o instanceof Error?o.message:String(o)}`}}}async hover(t,s){try{if(t==="relative"&&s){let o=this.selectors.relative;if(!o)return{success:!1,error:"Relative selector not defined for hover action."};let n=await j.resolve(this.page,o,s);return n?(await n.hover({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${s} for hover.`}}let r=this.selectors[t];return r?(await this.page.locator(r).first().hover({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for hover target ${t} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to hover ${t}: ${r instanceof Error?r.message:String(r)}`}}}};var re=class{constructor(t,s,r=400){this.page=t;this.selectors=s;this.timeoutMs=r}async resolveTarget(t,s,r){try{if(t==="relative"){let n=r?this.selectors[r]:this.selectors.relative;if(!n)return{target:null,error:"Relative selector is not defined in the contract."};if(!s)return{target:null,error:"Relative target or expected value is not defined."};let u=await j.resolve(this.page,n,s);return u?{target:u}:{target:null,error:`Target ${t} not found.`}}let o=this.selectors[t];return o?{target:this.page.locator(o).first()}:{target:null,error:`Selector for assertion target ${t} not found.`}}catch(o){return{target:null,error:`Failed to resolve target ${t}: ${o instanceof Error?o.message:String(o)}`}}}async validateVisibility(t,s,r,o,n){try{return r?(await(0,N.expect)(t).toBeVisible({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} is visible as expected. Test: "${n}".`}):(await(0,N.expect)(t).toBeHidden({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} is not visible as expected. Test: "${n}".`})}catch{let u=this.selectors[s]||"",i=await this.page.evaluate(R=>{let C=R?document.querySelector(R):null;if(!C)return"element not found";let A=window.getComputedStyle(C);return`display:${A.display}, visibility:${A.visibility}, opacity:${A.opacity}`},u);return r?{success:!1,failMessage:`${o} (actual: ${i})`}:{success:!1,failMessage:`${o} ${s} is still visible (actual: ${i}).`}}}async validateAttribute(t,s,r,o,n,u){if(o==="!empty"){let C=await t.getAttribute(r);return C&&C.trim()!==""?{success:!0,passMessage:`${s} has non-empty "${r}". Test: "${u}".`}:{success:!1,failMessage:`${n} ${s} "${r}" should not be empty, found "${C}".`}}if(typeof o!="string")throw console.error("[AssertionRunner] expectedValue is not a string:",o),new Error(`AssertionRunner: expectedValue for attribute assertion must be a string, but got: ${JSON.stringify(o)}`);let i=o.split(" | ").map(C=>C.trim()),R=await t.getAttribute(r);return R!==null&&i.includes(R)?{success:!0,passMessage:`${s} has expected "${r}". Test: "${u}".`}:{success:!1,failMessage:`${n} ${s} "${r}" should be "${o}", found "${R}".`}}async validateValue(t,s,r,o,n){let u=await t.inputValue().catch(()=>"");return r==="!empty"?u&&u.trim()!==""?{success:!0,passMessage:`${s} has non-empty value. Test: "${n}".`}:{success:!1,failMessage:`${o} ${s} value should not be empty, found "${u}".`}:r===""?u===""?{success:!0,passMessage:`${s} has empty value. Test: "${n}".`}:{success:!1,failMessage:`${o} ${s} value should be empty, found "${u}".`}:u===r?{success:!0,passMessage:`${s} has expected value. Test: "${n}".`}:{success:!1,failMessage:`${o} ${s} value should be "${r}", found "${u}".`}}async validateFocus(t,s,r,o,n){try{return r?(await(0,N.expect)(t).toBeFocused({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} has focus as expected. Test: "${n}".`}):(await(0,N.expect)(t).not.toBeFocused({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} does not have focus as expected. Test: "${n}".`})}catch{let u=await this.page.evaluate(()=>{let i=document.activeElement;return i?`${i.tagName}#${i.id||"no-id"}.${i.className||"no-class"}`:"no element focused"});return{success:!1,failMessage:`${o} (actual focus: ${u})`}}}async validateRole(t,s,r,o,n){let u=await t.getAttribute("role");return u===r?{success:!0,passMessage:`${s} has role "${r}". Test: "${n}".`}:{success:!1,failMessage:`${o} Expected role "${r}", found "${u}".`}}async validate(t,s){if(this.page.isClosed())return{success:!1,failMessage:"CRITICAL: Browser/page closed before completing all tests. Increase test timeout or reduce test complexity."};let r=null,o;if(t.controlledBy){let n=t.controlledBy,u=this.selectors[n.target];if(!u)return{success:!1,failMessage:`Selector for controlledBy.target '${n.target}' not found.`,target:null};let i=null;if(n.relativeTarget?i=await j.resolve(this.page,u,n.relativeTarget):i=this.page.locator(u).first(),!i)return{success:!1,failMessage:"Controlling element for controlledBy not found.",target:null};let R=n.attribute||"aria-controls",C=await i.getAttribute(R);if(!C)return{success:!1,failMessage:`Controlling element does not have attribute '${R}'.`,target:null};if(r=this.page.locator(`#${C}`),!r||await r.count()===0)return{success:!1,failMessage:`Controlled element with id '${C}' not found.`,target:null}}else{let n=await this.resolveTarget(t.target,t.relativeTarget||t.expectedValue,t.selectorKey);if(r=n.target,o=n.error,o||!r)return{success:!1,failMessage:o||`Target ${t.target} not found.`,target:null}}if(t.target==="input"&&t.attribute==="aria-activedescendant"&&t.expectedValue==="!empty"&&t.relativeTarget&&t.selectorKey){let n=await j.resolve(this.page,this.selectors[t.selectorKey],t.relativeTarget),u=n?await n.getAttribute("id"):null,i=await r.getAttribute("aria-activedescendant");return u&&i===u?{success:!0,passMessage:`input[aria-activedescendant] matches id of ${t.relativeTarget}(${t.selectorKey}). Test: "${s}".`}:{success:!1,failMessage:`input[aria-activedescendant] should match id of ${t.relativeTarget}(${t.selectorKey}), found "${i}".`}}switch(t.assertion){case"toBeVisible":return this.validateVisibility(r,t.target,!0,t.failureMessage||"",s);case"notToBeVisible":return this.validateVisibility(r,t.target,!1,t.failureMessage||"",s);case"toHaveAttribute":return t.attribute&&t.expectedValue!==void 0?this.validateAttribute(r,t.target,t.attribute,t.expectedValue,t.failureMessage||"",s):{success:!1,failMessage:"Missing attribute or expectedValue for toHaveAttribute assertion"};case"toHaveValue":return t.expectedValue!==void 0?this.validateValue(r,t.target,t.expectedValue,t.failureMessage||"",s):{success:!1,failMessage:"Missing expectedValue for toHaveValue assertion"};case"toHaveFocus":return this.validateFocus(r,t.target,!0,t.failureMessage||"",s);case"notToHaveFocus":return this.validateFocus(r,t.target,!1,t.failureMessage||"",s);case"toHaveRole":return t.expectedValue!==void 0?this.validateRole(r,t.target,t.expectedValue,t.failureMessage||"",s):{success:!1,failMessage:"Missing expectedValue for toHaveRole assertion"};default:return{success:!1,failMessage:`Unknown assertion type: ${t.assertion}`}}}};async function tt(M,t,s,r,o){let n=r?.test?.components?.find(d=>d.name===M),u=!!n?.contractPath,i=new ce(!0,u),R={actionTimeoutMs:400,assertionTimeoutMs:400,navigationTimeoutMs:3e4,componentReadyTimeoutMs:5e3},C=r?.test?.disableTimeouts===!0,te=n?.disableTimeouts===!0||C,_=(d,H,O)=>{if(te)return 0;let F=d??H;return typeof F!="number"||!Number.isFinite(F)||F<0?O:F},z=_(n?.actionTimeoutMs,r?.test?.actionTimeoutMs,R.actionTimeoutMs),X=_(n?.assertionTimeoutMs,r?.test?.assertionTimeoutMs,R.assertionTimeoutMs),ie=_(n?.navigationTimeoutMs,r?.test?.navigationTimeoutMs,R.navigationTimeoutMs),le=_(n?.componentReadyTimeoutMs,r?.test?.componentReadyTimeoutMs,R.componentReadyTimeoutMs),me=Se(s),Y=n?.contractPath;if(!Y)throw new Error(`Contract path not found for component: ${M}`);let Re=(()=>{if(he.isAbsolute(Y))return Y;if(o){let H=he.resolve(o,Y);try{return de(H,"utf-8"),H}catch{}}let d=he.resolve(process.cwd(),Y);try{return de(d,"utf-8"),d}catch{return new URL(Y,import.meta.url).pathname}})(),Ae=de(Re,"utf-8"),b=JSON.parse(Ae),Me=(b.relationships?.length||0)+(b.static[0]?.assertions.length||0)+b.dynamic.length,Ee=b.meta?.source?.apg,V=[],K=[],q=[],x=[],y=null,E=(d,H)=>{let O=Q(H),F=ke(O,me);if(F==="error")return V.push(d),{status:"fail",level:O,detail:d};if(F==="warning")return K.push(d),{status:"warn",level:O,detail:d};let D=`${d} (ignored by strictness=${me}, level=${O})`;return x.push(D),{status:"skip",level:O,detail:D}};try{if(y=await Te(),t){try{await y.goto(t,{waitUntil:"domcontentloaded",timeout:ie})}catch(e){throw new Error(`Failed to navigate to ${t}. Ensure dev server is running and accessible. Original error: ${e instanceof Error?e.message:String(e)}`)}await y.addStyleTag({content:"* { transition: none !important; animation: none !important; }"})}let d=await ae.detect(M,n,z,X,o);if(!d)throw new Error(`Unsupported component: ${M}`);let H=d.getMainSelector();if(!H)throw new Error(`CRITICAL: No selector found in contract for ${M}`);try{await y.locator(H).first().waitFor({state:"attached",timeout:le})}catch(e){throw new Error(`
|
|
22
|
+
\u274C Error: ${t}`),s&&this.log(` Context: ${s}`),this.log("")}};var ee=class{constructor(t,s,r=400){this.page=t;this.selectors=s;this.timeoutMs=r}isBrowserClosedError(t){return t instanceof Error&&t.message.includes("Target page, context or browser has been closed")}async focus(t,s,r){try{if(t==="virtual"&&r){let n=this.selectors.main;if(!n)return{success:!1,error:"Main selector not defined for virtual focus."};let u=this.page.locator(n).first();return await u.count()?(await u.evaluate((R,C)=>{R.setAttribute("aria-activedescendant",C)},r),{success:!0}):{success:!1,error:"Main element not found for virtual focus."}}if(t==="relative"&&s){let n=this.selectors.relative;if(!n)return{success:!1,error:"Relative selector not defined for focus action."};let u=await j.resolve(this.page,n,s);return u?(await u.focus({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${s} for focus.`}}let o=this.selectors[t];return o?(await this.page.locator(o).first().focus({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for focus target ${t} not found.`}}catch(o){return this.isBrowserClosedError(o)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to focus ${t}: ${o instanceof Error?o.message:String(o)}`}}}async type(t,s){try{let r=this.selectors[t];return r?(await this.page.locator(r).first().fill(s,{timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for type target ${t} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to type into ${t}: ${r instanceof Error?r.message:String(r)}`}}}async click(t,s){try{if(t==="document")return await this.page.mouse.click(10,10),{success:!0};if(t==="relative"&&s){let o=this.selectors.relative;if(!o)return{success:!1,error:"Relative selector not defined for click action."};let n=await j.resolve(this.page,o,s);return n?(await n.click({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${s} for click.`}}let r=this.selectors[t];return r?(await this.page.locator(r).first().click({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for action target ${t} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to click ${t}: ${r instanceof Error?r.message:String(r)}`}}}async keypress(t,s,r){try{let n={Space:"Space",Enter:"Enter",Escape:"Escape","Arrow Up":"ArrowUp","Arrow Down":"ArrowDown","Arrow Left":"ArrowLeft","Arrow Right":"ArrowRight",Home:"Home",End:"End",Tab:"Tab"}[s]||s;if(n==="Space"?n=" ":n.includes(" ")&&(n=n.replace(/ /g,"")),t==="relative"){if(r==null)return{success:!1,error:"relativeTarget must be provided for relative keypress."};let C=this.selectors.relative;if(!C)return{success:!1,error:"Relative selector not defined for keypress action."};let A=await j.resolve(this.page,C,r);return A?(await A.press(n,{timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${r} for keypress.`}}let u=this.selectors[t];if(!u)return{success:!1,error:`Selector for keypress target ${t} not found.`};let i=this.page.locator(u).first();return await i.count()===0?{success:!1,error:`${t} element not found.`,shouldBreak:!0}:(await i.press(n,{timeout:this.timeoutMs}),{success:!0})}catch(o){return this.isBrowserClosedError(o)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to press ${s} on ${t}: ${o instanceof Error?o.message:String(o)}`}}}async hover(t,s){try{if(t==="relative"&&s){let o=this.selectors.relative;if(!o)return{success:!1,error:"Relative selector not defined for hover action."};let n=await j.resolve(this.page,o,s);return n?(await n.hover({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Could not resolve relative target ${s} for hover.`}}let r=this.selectors[t];return r?(await this.page.locator(r).first().hover({timeout:this.timeoutMs}),{success:!0}):{success:!1,error:`Selector for hover target ${t} not found.`}}catch(r){return this.isBrowserClosedError(r)?{success:!1,error:"CRITICAL: Browser/page closed during test execution. Remaining actions skipped.",shouldBreak:!0}:{success:!1,error:`Failed to hover ${t}: ${r instanceof Error?r.message:String(r)}`}}}};var re=class{constructor(t,s,r=400){this.page=t;this.selectors=s;this.timeoutMs=r}async resolveTarget(t,s,r){try{if(t==="relative"){let n=r?this.selectors[r]:this.selectors.relative;if(!n)return{target:null,error:"Relative selector is not defined in the contract."};if(!s)return{target:null,error:"Relative target or expected value is not defined."};let u=await j.resolve(this.page,n,s);return u?{target:u}:{target:null,error:`Target ${t} not found.`}}let o=this.selectors[t];return o?{target:this.page.locator(o).first()}:{target:null,error:`Selector for assertion target ${t} not found.`}}catch(o){return{target:null,error:`Failed to resolve target ${t}: ${o instanceof Error?o.message:String(o)}`}}}async validateVisibility(t,s,r,o,n){try{return r?(await(0,N.expect)(t).toBeVisible({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} is visible as expected. Test: "${n}".`}):(await(0,N.expect)(t).toBeHidden({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} is not visible as expected. Test: "${n}".`})}catch{let u=this.selectors[s]||"",i=await this.page.evaluate(R=>{let C=R?document.querySelector(R):null;if(!C)return"element not found";let A=window.getComputedStyle(C);return`display:${A.display}, visibility:${A.visibility}, opacity:${A.opacity}`},u);return r?{success:!1,failMessage:`${o} (actual: ${i})`}:{success:!1,failMessage:`${o} ${s} is still visible (actual: ${i}).`}}}async validateAttribute(t,s,r,o,n,u){if(o==="!empty"){let C=await t.getAttribute(r);return C&&C.trim()!==""?{success:!0,passMessage:`${s} has non-empty "${r}". Test: "${u}".`}:{success:!1,failMessage:`${n} ${s} "${r}" should not be empty, found "${C}".`}}if(typeof o!="string")throw console.error("[AssertionRunner] expectedValue is not a string:",o),new Error(`AssertionRunner: expectedValue for attribute assertion must be a string, but got: ${JSON.stringify(o)}`);let i=o.split(" | ").map(C=>C.trim()),R=await t.getAttribute(r);return R!==null&&i.includes(R)?{success:!0,passMessage:`${s} has expected "${r}". Test: "${u}".`}:{success:!1,failMessage:`${n} ${s} "${r}" should be "${o}", found "${R}".`}}async validateValue(t,s,r,o,n){let u=await t.inputValue().catch(()=>"");return r==="!empty"?u&&u.trim()!==""?{success:!0,passMessage:`${s} has non-empty value. Test: "${n}".`}:{success:!1,failMessage:`${o} ${s} value should not be empty, found "${u}".`}:r===""?u===""?{success:!0,passMessage:`${s} has empty value. Test: "${n}".`}:{success:!1,failMessage:`${o} ${s} value should be empty, found "${u}".`}:u===r?{success:!0,passMessage:`${s} has expected value. Test: "${n}".`}:{success:!1,failMessage:`${o} ${s} value should be "${r}", found "${u}".`}}async validateFocus(t,s,r,o,n){try{return r?(await(0,N.expect)(t).toBeFocused({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} has focus as expected. Test: "${n}".`}):(await(0,N.expect)(t).not.toBeFocused({timeout:this.timeoutMs}),{success:!0,passMessage:`${s} does not have focus as expected. Test: "${n}".`})}catch{let u=await this.page.evaluate(()=>{let i=document.activeElement;return i?`${i.tagName}#${i.id||"no-id"}.${i.className||"no-class"}`:"no element focused"});return{success:!1,failMessage:`${o} (actual focus: ${u})`}}}async validateRole(t,s,r,o,n){let u=await t.getAttribute("role");return u===r?{success:!0,passMessage:`${s} has role "${r}". Test: "${n}".`}:{success:!1,failMessage:`${o} Expected role "${r}", found "${u}".`}}async validate(t,s){if(this.page.isClosed())return{success:!1,failMessage:"CRITICAL: Browser/page closed before completing all tests. Increase test timeout or reduce test complexity."};let r=null,o;if(t.controlledBy){let n=t.controlledBy,u=this.selectors[n.target];if(!u)return{success:!1,failMessage:`Selector for controlledBy.target '${n.target}' not found.`,target:null};let i=null;if(n.relativeTarget?i=await j.resolve(this.page,u,n.relativeTarget):i=this.page.locator(u).first(),!i)return{success:!1,failMessage:"Controlling element for controlledBy not found.",target:null};let R=n.attribute||"aria-controls",C=await i.getAttribute(R);if(!C)return{success:!1,failMessage:`Controlling element does not have attribute '${R}'.`,target:null};if(r=this.page.locator(`#${C}`),!r||await r.count()===0)return{success:!1,failMessage:`Controlled element with id '${C}' not found.`,target:null}}else{let n=await this.resolveTarget(t.target,t.relativeTarget||t.expectedValue,t.selectorKey);if(r=n.target,o=n.error,o||!r)return{success:!1,failMessage:o||`Target ${t.target} not found.`,target:null}}if(t.target==="input"&&t.attribute==="aria-activedescendant"&&t.expectedValue==="!empty"&&t.relativeTarget&&t.selectorKey){let n=await j.resolve(this.page,this.selectors[t.selectorKey],t.relativeTarget),u=n?await n.getAttribute("id"):null,i=await r.getAttribute("aria-activedescendant");return u&&i===u?{success:!0,passMessage:`input[aria-activedescendant] matches id of ${t.relativeTarget}(${t.selectorKey}). Test: "${s}".`}:{success:!1,failMessage:`input[aria-activedescendant] should match id of ${t.relativeTarget}(${t.selectorKey}), found "${i}".`}}switch(t.assertion){case"toBeVisible":return this.validateVisibility(r,t.target,!0,t.failureMessage||"",s);case"notToBeVisible":return this.validateVisibility(r,t.target,!1,t.failureMessage||"",s);case"toHaveAttribute":return t.attribute&&t.expectedValue!==void 0?this.validateAttribute(r,t.target,t.attribute,t.expectedValue,t.failureMessage||"",s):{success:!1,failMessage:"Missing attribute or expectedValue for toHaveAttribute assertion"};case"toHaveValue":return t.expectedValue!==void 0?this.validateValue(r,t.target,t.expectedValue,t.failureMessage||"",s):{success:!1,failMessage:"Missing expectedValue for toHaveValue assertion"};case"toHaveFocus":return this.validateFocus(r,t.target,!0,t.failureMessage||"",s);case"notToHaveFocus":return this.validateFocus(r,t.target,!1,t.failureMessage||"",s);case"toHaveRole":return t.expectedValue!==void 0?this.validateRole(r,t.target,t.expectedValue,t.failureMessage||"",s):{success:!1,failMessage:"Missing expectedValue for toHaveRole assertion"};default:return{success:!1,failMessage:`Unknown assertion type: ${t.assertion}`}}}};async function tt(M,t,s,r,o){let n=r?.test?.components?.find(d=>d.name===M),u=!!n?.contractPath,i=new ce(!0,u),R={actionTimeoutMs:400,assertionTimeoutMs:400,navigationTimeoutMs:3e4,componentReadyTimeoutMs:5e3},C=r?.test?.disableTimeouts===!0,te=n?.disableTimeouts===!0||C,_=(d,H,O)=>{if(te)return 0;let F=d??H;return typeof F!="number"||!Number.isFinite(F)||F<0?O:F},z=_(n?.actionTimeoutMs,r?.test?.actionTimeoutMs,R.actionTimeoutMs),X=_(n?.assertionTimeoutMs,r?.test?.assertionTimeoutMs,R.assertionTimeoutMs),ie=_(n?.navigationTimeoutMs,r?.test?.navigationTimeoutMs,R.navigationTimeoutMs),le=_(n?.componentReadyTimeoutMs,r?.test?.componentReadyTimeoutMs,R.componentReadyTimeoutMs),me=Se(s),Y=n?.contractPath;if(!Y)throw new Error(`Contract path not found for component: ${M}`);let Re=(()=>{if(he.isAbsolute(Y))return Y;if(o){let H=he.resolve(o,Y);try{return de(H,"utf-8"),H}catch{}}let d=he.resolve(process.cwd(),Y);try{return de(d,"utf-8"),d}catch{return new URL(Y,import.meta.url).pathname}})(),Ae=de(Re,"utf-8"),b=JSON.parse(Ae),Me=(b.relationships?.length||0)+(b.static[0]?.assertions.length||0)+b.dynamic.length,Ee=b.meta?.source?.apg,V=[],K=[],q=[],x=[],y=null,E=(d,H)=>{let O=Q(H),F=ke(O,me);if(F==="error")return V.push(d),{status:"fail",level:O,detail:d};if(F==="warning")return K.push(d),{status:"warn",level:O,detail:d};let D=`${d} (ignored by strictness=${me}, level=${O})`;return x.push(D),{status:"skip",level:O,detail:D}};try{if(y=await Te(),t){try{await y.goto(t,{waitUntil:"domcontentloaded",timeout:ie})}catch(e){throw new Error(`Failed to navigate to ${t}. Ensure dev server is running and accessible. Original error: ${e instanceof Error?e.message:String(e)}`)}await y.addStyleTag({content:"* { transition: none !important; animation: none !important; }"})}let d=await ae.detect(M,n,z,X,o);if(!d)throw new Error(`Unsupported component: ${M}`);let H=d.getMainSelector();if(!H)throw new Error(`CRITICAL: No selector found in contract for ${M}`);try{await y.locator(H).first().waitFor({state:"attached",timeout:le})}catch(e){throw new Error(`
|
|
23
23
|
\u274C CRITICAL: Component not found on page!
|
|
24
24
|
This usually means:
|
|
25
25
|
- The component didn't render
|