@baseline-ui/test-utils 0.63.0 → 1.0.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/index.d.mts +39 -1
- package/dist/index.d.ts +39 -1
- package/dist/index.js +10 -10
- package/dist/index.mjs +10 -10
- package/package.json +2 -2
- package/sbom.json +8 -8
package/dist/index.d.mts
CHANGED
|
@@ -225,6 +225,42 @@ interface EditorTester {
|
|
|
225
225
|
startMention: () => Promise<void>;
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Options for {@link fileUploaderTester}. The root is always resolved from the
|
|
230
|
+
* stable `data-testid="file-uploader"`; `trigger` overrides the upload
|
|
231
|
+
* button (the focusable element that opens the native file picker) for the
|
|
232
|
+
* rare case a consumer renders a custom one.
|
|
233
|
+
*
|
|
234
|
+
* `variant` mirrors the component's `variant` prop and only affects how the
|
|
235
|
+
* upload `button` is resolved: in the `dropzone` variant the whole drop area is
|
|
236
|
+
* the focusable trigger (`data-testid="file-uploader-dropzone"`, `role="button"`),
|
|
237
|
+
* while the `button` variant renders a single `role="button"` inside the root.
|
|
238
|
+
*/
|
|
239
|
+
interface FileUploaderTesterOptions extends BaseTesterOptions {
|
|
240
|
+
variant?: "dropzone" | "button";
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Driver for a `<FileUploader>` in Playwright component tests. Construct with
|
|
244
|
+
* {@link fileUploaderTester} (or `testers(frame).fileUploader()`).
|
|
245
|
+
*/
|
|
246
|
+
interface FileUploaderTester {
|
|
247
|
+
/** The uploader root element — scopes every other locator. */
|
|
248
|
+
readonly root: Locator;
|
|
249
|
+
/** The upload trigger button that opens the native file picker. */
|
|
250
|
+
readonly button: Locator;
|
|
251
|
+
/** The hidden native file input. Prefer {@link upload} to set files on it. */
|
|
252
|
+
readonly input: Locator;
|
|
253
|
+
/**
|
|
254
|
+
* The drop area (dropzone variant only). Use with `locator.drop({ files })`
|
|
255
|
+
* to simulate a drag-and-drop. Not attached in the `button` variant.
|
|
256
|
+
*/
|
|
257
|
+
readonly dropzone: Locator;
|
|
258
|
+
/** The error alert. Only attached while `errorMessage` is set. */
|
|
259
|
+
readonly errorMessage: Locator;
|
|
260
|
+
/** Sets files on the hidden input — the way a user picks files. */
|
|
261
|
+
upload: (files: Parameters<Locator["setInputFiles"]>[0]) => Promise<void>;
|
|
262
|
+
}
|
|
263
|
+
|
|
228
264
|
/**
|
|
229
265
|
* Options for {@link selectTester}. Defaults the trigger to
|
|
230
266
|
* `frame.getByTestId("select-button")` (the convention for both single- and
|
|
@@ -359,6 +395,7 @@ interface SelectTesterFactoryFor<O extends {
|
|
|
359
395
|
|
|
360
396
|
type BoundSelectOptions = Omit<SelectTesterOptions, "frame">;
|
|
361
397
|
type BoundEditorOptions = Omit<EditorTesterOptions, "frame">;
|
|
398
|
+
type BoundFileUploaderOptions = Omit<FileUploaderTesterOptions, "frame">;
|
|
362
399
|
/**
|
|
363
400
|
* The frame-bound tester factory. Methods are flat — one per component — so
|
|
364
401
|
* IDE autocomplete on `t.` lists the full surface in one place. Variants of a
|
|
@@ -371,6 +408,7 @@ type BoundEditorOptions = Omit<EditorTesterOptions, "frame">;
|
|
|
371
408
|
interface Testers {
|
|
372
409
|
select: SelectTesterFactoryFor<BoundSelectOptions>;
|
|
373
410
|
editor: (options?: BoundEditorOptions) => EditorTester;
|
|
411
|
+
fileUploader: (options?: BoundFileUploaderOptions) => FileUploaderTester;
|
|
374
412
|
}
|
|
375
413
|
/**
|
|
376
414
|
* Build a frame-bound tester factory. Construct once per test and pick the
|
|
@@ -388,4 +426,4 @@ interface Testers {
|
|
|
388
426
|
*/
|
|
389
427
|
declare function testers(frame: Frame): Testers;
|
|
390
428
|
|
|
391
|
-
export { type AutocompleteTester, DEFAULT_CRITICAL_INCOMPLETE_RULES, DEFAULT_DISABLED_RULES, DEFAULT_WCAG_TAGS, type EditorTester, type Frame, type MultiSelectTester, type SelectTester, type Testers, type ToBeAccessibleOptions, expect, testers };
|
|
429
|
+
export { type AutocompleteTester, DEFAULT_CRITICAL_INCOMPLETE_RULES, DEFAULT_DISABLED_RULES, DEFAULT_WCAG_TAGS, type EditorTester, type FileUploaderTester, type Frame, type MultiSelectTester, type SelectTester, type Testers, type ToBeAccessibleOptions, expect, testers };
|
package/dist/index.d.ts
CHANGED
|
@@ -225,6 +225,42 @@ interface EditorTester {
|
|
|
225
225
|
startMention: () => Promise<void>;
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Options for {@link fileUploaderTester}. The root is always resolved from the
|
|
230
|
+
* stable `data-testid="file-uploader"`; `trigger` overrides the upload
|
|
231
|
+
* button (the focusable element that opens the native file picker) for the
|
|
232
|
+
* rare case a consumer renders a custom one.
|
|
233
|
+
*
|
|
234
|
+
* `variant` mirrors the component's `variant` prop and only affects how the
|
|
235
|
+
* upload `button` is resolved: in the `dropzone` variant the whole drop area is
|
|
236
|
+
* the focusable trigger (`data-testid="file-uploader-dropzone"`, `role="button"`),
|
|
237
|
+
* while the `button` variant renders a single `role="button"` inside the root.
|
|
238
|
+
*/
|
|
239
|
+
interface FileUploaderTesterOptions extends BaseTesterOptions {
|
|
240
|
+
variant?: "dropzone" | "button";
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Driver for a `<FileUploader>` in Playwright component tests. Construct with
|
|
244
|
+
* {@link fileUploaderTester} (or `testers(frame).fileUploader()`).
|
|
245
|
+
*/
|
|
246
|
+
interface FileUploaderTester {
|
|
247
|
+
/** The uploader root element — scopes every other locator. */
|
|
248
|
+
readonly root: Locator;
|
|
249
|
+
/** The upload trigger button that opens the native file picker. */
|
|
250
|
+
readonly button: Locator;
|
|
251
|
+
/** The hidden native file input. Prefer {@link upload} to set files on it. */
|
|
252
|
+
readonly input: Locator;
|
|
253
|
+
/**
|
|
254
|
+
* The drop area (dropzone variant only). Use with `locator.drop({ files })`
|
|
255
|
+
* to simulate a drag-and-drop. Not attached in the `button` variant.
|
|
256
|
+
*/
|
|
257
|
+
readonly dropzone: Locator;
|
|
258
|
+
/** The error alert. Only attached while `errorMessage` is set. */
|
|
259
|
+
readonly errorMessage: Locator;
|
|
260
|
+
/** Sets files on the hidden input — the way a user picks files. */
|
|
261
|
+
upload: (files: Parameters<Locator["setInputFiles"]>[0]) => Promise<void>;
|
|
262
|
+
}
|
|
263
|
+
|
|
228
264
|
/**
|
|
229
265
|
* Options for {@link selectTester}. Defaults the trigger to
|
|
230
266
|
* `frame.getByTestId("select-button")` (the convention for both single- and
|
|
@@ -359,6 +395,7 @@ interface SelectTesterFactoryFor<O extends {
|
|
|
359
395
|
|
|
360
396
|
type BoundSelectOptions = Omit<SelectTesterOptions, "frame">;
|
|
361
397
|
type BoundEditorOptions = Omit<EditorTesterOptions, "frame">;
|
|
398
|
+
type BoundFileUploaderOptions = Omit<FileUploaderTesterOptions, "frame">;
|
|
362
399
|
/**
|
|
363
400
|
* The frame-bound tester factory. Methods are flat — one per component — so
|
|
364
401
|
* IDE autocomplete on `t.` lists the full surface in one place. Variants of a
|
|
@@ -371,6 +408,7 @@ type BoundEditorOptions = Omit<EditorTesterOptions, "frame">;
|
|
|
371
408
|
interface Testers {
|
|
372
409
|
select: SelectTesterFactoryFor<BoundSelectOptions>;
|
|
373
410
|
editor: (options?: BoundEditorOptions) => EditorTester;
|
|
411
|
+
fileUploader: (options?: BoundFileUploaderOptions) => FileUploaderTester;
|
|
374
412
|
}
|
|
375
413
|
/**
|
|
376
414
|
* Build a frame-bound tester factory. Construct once per test and pick the
|
|
@@ -388,4 +426,4 @@ interface Testers {
|
|
|
388
426
|
*/
|
|
389
427
|
declare function testers(frame: Frame): Testers;
|
|
390
428
|
|
|
391
|
-
export { type AutocompleteTester, DEFAULT_CRITICAL_INCOMPLETE_RULES, DEFAULT_DISABLED_RULES, DEFAULT_WCAG_TAGS, type EditorTester, type Frame, type MultiSelectTester, type SelectTester, type Testers, type ToBeAccessibleOptions, expect, testers };
|
|
429
|
+
export { type AutocompleteTester, DEFAULT_CRITICAL_INCOMPLETE_RULES, DEFAULT_DISABLED_RULES, DEFAULT_WCAG_TAGS, type EditorTester, type FileUploaderTester, type Frame, type MultiSelectTester, type SelectTester, type Testers, type ToBeAccessibleOptions, expect, testers };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
'use strict';var test=require('@playwright/test'),_=require('axe-core'),promises=require('fs/promises'),
|
|
1
|
+
'use strict';var test=require('@playwright/test'),_=require('axe-core'),promises=require('fs/promises'),C=require('path');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var ___default=/*#__PURE__*/_interopDefault(_);var C__default=/*#__PURE__*/_interopDefault(C);/**
|
|
2
2
|
* Copyright (c) 2023-2024 PSPDFKit GmbH. All rights reserved.
|
|
3
3
|
*
|
|
4
4
|
* THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
|
|
@@ -7,15 +7,15 @@
|
|
|
7
7
|
* This notice may not be removed from this file.
|
|
8
8
|
*
|
|
9
9
|
*/
|
|
10
|
-
var w=["wcag2a","wcag2aa","wcag21a","wcag21aa","best-practice"],L=["landmark-one-main","page-has-heading-one","region","aria-allowed-role","duplicate-id","scrollable-region-focusable"],E=["aria-valid-attr-value","aria-valid-attr","aria-required-attr"];function
|
|
11
|
-
`):
|
|
12
|
-
`)}var y=e=>{if(e instanceof Error)return e.message;if(typeof e=="string")return e;if(e==null)return "unknown error";try{return JSON.stringify(e)}catch{return "unstringifiable error"}},
|
|
13
|
-
${y(u)}`);if(
|
|
10
|
+
var w=["wcag2a","wcag2aa","wcag21a","wcag21aa","best-practice"],L=["landmark-one-main","page-has-heading-one","region","aria-allowed-role","duplicate-id","scrollable-region-focusable"],E=["aria-valid-attr-value","aria-valid-attr","aria-required-attr"];function A(e,o={}){let{prefix:t="BaselineUI-",ignoreHashed:n=false}=o,r=Array.isArray(t)?t:[t];function s(c){return c.split(/[-_]/).some(i=>i.length>=5&&/^[a-z\d]+$/.test(i)&&/[a-z]/.test(i)&&/\d/.test(i))}function l(c){return [...c.classList].filter(i=>r.some(g=>i.startsWith(g))&&(!n||!s(i)))}function u(c,i=false){let g=[],b=c.shadowRoot?c.shadowRoot.children:c.children;for(let f of b){let h=i||f.getAttribute("aria-hidden")==="true",B=l(f),x=u(f,h);B.length>0?g.push({classes:B,children:x,hidden:h}):g.push(...x);}return g}function d(c,i="",g=false){let b=[];for(let f=0;f<c.length;f++){let h=c[f],B=f===c.length-1,x=g?"":B?"\u2514\u2500\u2500 ":"\u251C\u2500\u2500 ",P=g?"":i+(B?" ":"\u2502 "),U=h.classes.join(", ");b.push(i+x+U+(h.hidden?" [aria-hidden]":""),...d(h.children,P));}return b}let p=l(e),a=u(e);return p.length===0&&a.length===0?"":p.length>0?d([{classes:p,children:a,hidden:false}],"",true).join(`
|
|
11
|
+
`):d(a,"",true).join(`
|
|
12
|
+
`)}var y=e=>{if(e instanceof Error)return e.message;if(typeof e=="string")return e;if(e==null)return "unknown error";try{return JSON.stringify(e)}catch{return "unstringifiable error"}},j=async e=>{let o=typeof e.goto=="function",t=!o&&typeof e.owner=="function";if(o||t)return e.locator("body");let n=e;return await n.first().evaluate(s=>s.tagName?.toLowerCase()==="iframe").catch(()=>false)?n.contentFrame().locator("body"):n},M=async e=>{await e.first().evaluate((o,t)=>{if(window.axe)return;let r=document.createElement("script");r.textContent=t,document.head.append(r);},___default.default.source);},W=["document-title","html-has-lang","html-lang-valid","html-xml-lang-mismatch"],z=(e,o=[])=>{let t=new Set([...L,...o,...e.disableRules??[]]);return {runOnly:{type:"tag",values:[...e.tags??w]},rules:Object.fromEntries([...t].map(n=>[n,{enabled:false}]))}},F=e=>{if(e!==void 0)return typeof e=="string"?[e]:[...e]},H=async(e,o,t)=>{let n=await e.count();if(n===0)throw new Error("toBeAccessible: locator resolved to zero elements; nothing to scan.");await M(e);let r=F(o.include),s=F(o.exclude);return n===1?await e.evaluate(async(l,u)=>{let d=window,p={include:[l,...u.userInclude??[]],exclude:u.userExclude??[]};return await d.axe.run(p,u.runOptions)},{userInclude:r,userExclude:s,runOptions:t}):await e.evaluateAll(async(l,u)=>{let d=window,p={include:[...l,...u.userInclude??[]],exclude:u.userExclude??[]};return await d.axe.run(p,u.runOptions)},{userInclude:r,userExclude:s,runOptions:t})},O="BaselineUI-";function S(e){return e.replaceAll(/\W+/g,"-").replaceAll(/^-|-$/g,"")}function V(e){return Array.isArray(e)?e.length===1&&e[0]===O:e===O}function G(e){return (Array.isArray(e)?e:[e]).join("+")}function q(e,o,t,n,r){let s=o.slice(1).map(l=>S(l));return t&&s.push(S(t)),n!==void 0&&!V(n)&&s.push(S(G(n))),r&&s.push("ignoreHashed"),C__default.default.join(e,`${s.join("--")}.txt`)}var J=test.expect.extend({toBeWithinDelta(e,o,t){return Math.abs(e-o)<=t?{message:()=>`expected ${e} not to be within ${t} of ${o}`,pass:true}:{message:()=>`expected ${e} to be within ${t} of ${o}`,pass:false}},async toBeCalledOnce(e){try{return await test.expect.poll(()=>e.callCount).toBe(1),{message:()=>"Expected function to be called once.",pass:!0}}catch(o){return {message:()=>y(o),pass:false}}},async toBeCalledTwice(e){try{return await test.expect.poll(()=>e.callCount).toBe(2),{message:()=>"Expected function to be called twice.",pass:!0}}catch(o){return {message:()=>y(o),pass:false}}},async toBeCalledThrice(e){try{return await test.expect.poll(()=>e.callCount).toBe(3),{message:()=>"Expected function to be called thrice.",pass:!0}}catch(o){return {message:()=>y(o),pass:false}}},async toBeCalledWith(e,...o){try{return await test.expect(()=>{for(let[t,n]of o.entries())test.expect(e.lastCall?.args?.[t]).toStrictEqual(n);}).toPass(),{message:()=>`Expected function to be called with ${o.join(", ")}.`,pass:!0}}catch(t){return {message:()=>y(t),pass:false}}},async toBeCalledWithExactly(e,...o){try{return await test.expect.poll(()=>e.lastCall?.args).toStrictEqual(o),{message:()=>`Expected function to be called with exactly ${o.join(", ")}.`,pass:!0}}catch(t){return {message:()=>y(t),pass:false}}},toBeCalled(e){try{return test.expect(e.called).toBeTruthy(),{message:()=>"Expected function to be called.",pass:!0}}catch(o){return {message:()=>y(o),pass:false}}},async toBeCalledTimes(e,o){try{return await test.expect.poll(()=>e.callCount).toBe(o),{message:()=>`Expected function to be called ${o} times.`,pass:!0}}catch(t){return {message:()=>y(t),pass:false}}},async toBeAccessible(e,o={}){let t=await j(e),n=await t.first().evaluate(a=>{let c=a.ownerDocument?.defaultView;return c!==null&&c!==window.top}).catch(()=>false),r=z(o,n?W:[]),s,l=async()=>{let a=await H(t,o,r),c=o.treatIncompleteAsViolationIds??E,i=[...a.violations,...a.incomplete.filter(g=>c.includes(g.id))];return s={result:a,violations:i},i},u;try{if(o.timeout&&o.timeout>0){let a=test.expect.poll(l,{timeout:o.timeout});await(this.isNot?a.not.toHaveLength(0):a.toHaveLength(0));}else await l();}catch(a){u=a;}if(!s)throw new Error(`toBeAccessible: axe scan never completed.
|
|
13
|
+
${y(u)}`);if(s.violations.length===0)return {message:()=>"Expected accessibility violations but found none.",pass:true};this.isNot||await test.test.info().attach(o.attachmentName??"accessibility-scan-results",{body:JSON.stringify(s.result,null,2),contentType:"application/json"});let d=s.violations.map(a=>{let c=a.nodes.map(i=>Array.isArray(i.target)?i.target.join(" "):String(i.target)).join(`
|
|
14
14
|
`);return ` \u2022 [${a.id}] ${a.help}
|
|
15
|
-
${
|
|
15
|
+
${c}
|
|
16
16
|
${a.helpUrl??""}`}).join(`
|
|
17
|
-
`),
|
|
18
|
-
${
|
|
19
|
-
`,u=test.test.info();if(u.config.ignoreSnapshots)return {message:()=>"Class tree snapshot check skipped.",pass:!0};let
|
|
17
|
+
`),p=s.violations.length;return {message:()=>`Found ${p} accessibility violation${p===1?"":"s"}:
|
|
18
|
+
${d}`,pass:false}},async toMatchClassTree(e,o,t={}){let{prefix:n=O,ignoreHashed:r=false}=t,s=await e.evaluate(A,{prefix:n,ignoreHashed:r});if(!s){let l=Array.isArray(n)?n.map(u=>`${u}*`).join(" / "):`${n}*`;return {message:()=>`No ${l} classes found in the DOM tree.`,pass:false}}try{let l=`${s}
|
|
19
|
+
`,u=test.test.info();if(u.config.ignoreSnapshots)return {message:()=>"Class tree snapshot check skipped.",pass:!0};let p=q(u.project.snapshotDir,u.titlePath,o,n,r),a=u.config.updateSnapshots;await promises.mkdir(C__default.default.dirname(p),{recursive:!0});let c;try{c=await promises.readFile(p,"utf8");}catch(i){if(i.code==="ENOENT"&&a!=="none")return await promises.writeFile(p,l),{message:()=>"Class tree snapshot created.",pass:!0};throw i}if(c!==l){if(a==="all"||a==="changed")return await promises.writeFile(p,l),{message:()=>"Class tree snapshot updated.",pass:!0};try{test.expect(l).toBe(c);}catch(i){return {message:()=>`Class tree snapshot mismatch at ${p}
|
|
20
20
|
|
|
21
|
-
${i.message}`,pass:!1}}}return {message:()=>"Class tree matched snapshot.",pass:!0}}catch(
|
|
21
|
+
${i.message}`,pass:!1}}}return {message:()=>"Class tree matched snapshot.",pass:!0}}catch(l){return {message:()=>y(l),pass:false}}}});function T(e){let o=async()=>{if(await e.getAttribute("aria-expanded")!==null)return e;let r=e.locator("[aria-expanded]").first();return await r.count()>0?r:e},t=async()=>await(await o()).getAttribute("aria-expanded")==="true";return {isOpen:t,open:async(r="click")=>{if(await t())return;if(r==="click"){await e.click();return}await(await o()).press(r);}}}function R({frame:e,root:o}){let t=o??e.locator(".BaselineUI-Editor"),n=t.getByTestId("editor-font-color-button"),r=t.getByTestId("editor-background-color-button"),s=t.getByTestId("editor-add-link-button"),l=t.getByTestId("editor-help-button"),u=t.getByTestId("editor-mention-button"),d=t.getByRole("combobox"),p=e.getByTestId("editor-mention-listbox"),a=e.getByTestId("editor-help-dialog-close-button"),c=e.getByRole("dialog").filter({has:a}),i=e.getByRole("dialog").filter({has:e.getByTestId(/^editor-link-/)});return {root:t,textbox:t.getByRole("textbox"),placeholder:t.getByTestId("editor-placeholder"),toolbar:t.getByRole("toolbar"),boldButton:t.getByTestId("editor-bold-button"),italicButton:t.getByTestId("editor-italic-button"),underlineButton:t.getByTestId("editor-underline-button"),fontColorButton:n,backgroundColorButton:r,openFontColorPicker:T(n).open,openBackgroundColorPicker:T(r).open,addLinkButton:s,linkDialog:i,linkInput:e.getByTestId("editor-link-input"),linkAddButton:e.getByTestId("editor-link-add-button"),linkEditButton:e.getByTestId("editor-link-edit-button"),linkRemoveButton:e.getByTestId("editor-link-remove-button"),linkCancelButton:e.getByTestId("editor-link-cancel-button"),linkSaveButton:e.getByTestId("editor-link-save-button"),openLinkDialog:T(s).open,saveButton:t.getByTestId("editor-save-button"),cancelButton:t.getByTestId("editor-cancel-button"),mentionButton:u,helpButton:l,helpDialog:c,helpDialogCloseButton:a,async openHelpDialog(){await c.isVisible()||await l.click();},mentionInput:d,mentionListbox:p,mentionOption:g=>p.getByRole("option",{name:g}),async startMention(){await d.isVisible()||await u.click();}}}function D({frame:e,trigger:o,variant:t="dropzone"}){let n=e.getByTestId("file-uploader"),r=n.locator('input[type="file"]'),s=o??(t==="button"?n.getByRole("button"):e.getByTestId("file-uploader-dropzone"));return {root:n,button:s,input:r,dropzone:e.getByTestId("file-uploader-dropzone"),errorMessage:n.getByRole("alert"),async upload(l){await r.setInputFiles(l);}}}var v=(e=>{let t=K(e);return e.multiple&&(t=X(t,e.frame)),e.autocomplete&&(t=Q(t,e.frame)),t});function K({frame:e,trigger:o}){let t=o??e.getByTestId("select-button"),n=s=>e.getByRole("option",{name:s}),{open:r}=T(t);return {trigger:t,listbox:e.getByRole("listbox"),option:n,open:r,async selectOption(s){await r(),await n(s).click();}}}function X(e,o){return {...e,selectAllButton:o.getByTestId("select-all-button"),clearButton:o.getByTestId("select-clear-button"),tag:t=>e.trigger.getByRole("row",{name:t}),removeTagButton:t=>e.trigger.getByRole("row",{name:t}).getByRole("button")}}function Q(e,o){let t=o.getByRole("searchbox");return {...e,searchbox:t,async filter(n){await t.fill(n);}}}function Y(e){return {select:((o={})=>v({frame:e,...o})),editor:(o={})=>R({frame:e,...o}),fileUploader:(o={})=>D({frame:e,...o})}}exports.DEFAULT_CRITICAL_INCOMPLETE_RULES=E;exports.DEFAULT_DISABLED_RULES=L;exports.DEFAULT_WCAG_TAGS=w;exports.expect=J;exports.testers=Y;
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {expect,test}from'@playwright/test';import _ from'axe-core';import {mkdir,readFile,writeFile}from'fs/promises';import
|
|
1
|
+
import {expect,test}from'@playwright/test';import _ from'axe-core';import {mkdir,readFile,writeFile}from'fs/promises';import C from'path';/**
|
|
2
2
|
* Copyright (c) 2023-2024 PSPDFKit GmbH. All rights reserved.
|
|
3
3
|
*
|
|
4
4
|
* THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
|
|
@@ -7,15 +7,15 @@ import {expect,test}from'@playwright/test';import _ from'axe-core';import {mkdir
|
|
|
7
7
|
* This notice may not be removed from this file.
|
|
8
8
|
*
|
|
9
9
|
*/
|
|
10
|
-
var w=["wcag2a","wcag2aa","wcag21a","wcag21aa","best-practice"],L=["landmark-one-main","page-has-heading-one","region","aria-allowed-role","duplicate-id","scrollable-region-focusable"],E=["aria-valid-attr-value","aria-valid-attr","aria-required-attr"];function
|
|
11
|
-
`):
|
|
12
|
-
`)}var y=e=>{if(e instanceof Error)return e.message;if(typeof e=="string")return e;if(e==null)return "unknown error";try{return JSON.stringify(e)}catch{return "unstringifiable error"}},
|
|
13
|
-
${y(u)}`);if(
|
|
10
|
+
var w=["wcag2a","wcag2aa","wcag21a","wcag21aa","best-practice"],L=["landmark-one-main","page-has-heading-one","region","aria-allowed-role","duplicate-id","scrollable-region-focusable"],E=["aria-valid-attr-value","aria-valid-attr","aria-required-attr"];function A(e,o={}){let{prefix:t="BaselineUI-",ignoreHashed:n=false}=o,r=Array.isArray(t)?t:[t];function s(c){return c.split(/[-_]/).some(i=>i.length>=5&&/^[a-z\d]+$/.test(i)&&/[a-z]/.test(i)&&/\d/.test(i))}function l(c){return [...c.classList].filter(i=>r.some(g=>i.startsWith(g))&&(!n||!s(i)))}function u(c,i=false){let g=[],b=c.shadowRoot?c.shadowRoot.children:c.children;for(let f of b){let h=i||f.getAttribute("aria-hidden")==="true",B=l(f),x=u(f,h);B.length>0?g.push({classes:B,children:x,hidden:h}):g.push(...x);}return g}function d(c,i="",g=false){let b=[];for(let f=0;f<c.length;f++){let h=c[f],B=f===c.length-1,x=g?"":B?"\u2514\u2500\u2500 ":"\u251C\u2500\u2500 ",P=g?"":i+(B?" ":"\u2502 "),U=h.classes.join(", ");b.push(i+x+U+(h.hidden?" [aria-hidden]":""),...d(h.children,P));}return b}let p=l(e),a=u(e);return p.length===0&&a.length===0?"":p.length>0?d([{classes:p,children:a,hidden:false}],"",true).join(`
|
|
11
|
+
`):d(a,"",true).join(`
|
|
12
|
+
`)}var y=e=>{if(e instanceof Error)return e.message;if(typeof e=="string")return e;if(e==null)return "unknown error";try{return JSON.stringify(e)}catch{return "unstringifiable error"}},j=async e=>{let o=typeof e.goto=="function",t=!o&&typeof e.owner=="function";if(o||t)return e.locator("body");let n=e;return await n.first().evaluate(s=>s.tagName?.toLowerCase()==="iframe").catch(()=>false)?n.contentFrame().locator("body"):n},M=async e=>{await e.first().evaluate((o,t)=>{if(window.axe)return;let r=document.createElement("script");r.textContent=t,document.head.append(r);},_.source);},W=["document-title","html-has-lang","html-lang-valid","html-xml-lang-mismatch"],z=(e,o=[])=>{let t=new Set([...L,...o,...e.disableRules??[]]);return {runOnly:{type:"tag",values:[...e.tags??w]},rules:Object.fromEntries([...t].map(n=>[n,{enabled:false}]))}},F=e=>{if(e!==void 0)return typeof e=="string"?[e]:[...e]},H=async(e,o,t)=>{let n=await e.count();if(n===0)throw new Error("toBeAccessible: locator resolved to zero elements; nothing to scan.");await M(e);let r=F(o.include),s=F(o.exclude);return n===1?await e.evaluate(async(l,u)=>{let d=window,p={include:[l,...u.userInclude??[]],exclude:u.userExclude??[]};return await d.axe.run(p,u.runOptions)},{userInclude:r,userExclude:s,runOptions:t}):await e.evaluateAll(async(l,u)=>{let d=window,p={include:[...l,...u.userInclude??[]],exclude:u.userExclude??[]};return await d.axe.run(p,u.runOptions)},{userInclude:r,userExclude:s,runOptions:t})},O="BaselineUI-";function S(e){return e.replaceAll(/\W+/g,"-").replaceAll(/^-|-$/g,"")}function V(e){return Array.isArray(e)?e.length===1&&e[0]===O:e===O}function G(e){return (Array.isArray(e)?e:[e]).join("+")}function q(e,o,t,n,r){let s=o.slice(1).map(l=>S(l));return t&&s.push(S(t)),n!==void 0&&!V(n)&&s.push(S(G(n))),r&&s.push("ignoreHashed"),C.join(e,`${s.join("--")}.txt`)}var J=expect.extend({toBeWithinDelta(e,o,t){return Math.abs(e-o)<=t?{message:()=>`expected ${e} not to be within ${t} of ${o}`,pass:true}:{message:()=>`expected ${e} to be within ${t} of ${o}`,pass:false}},async toBeCalledOnce(e){try{return await expect.poll(()=>e.callCount).toBe(1),{message:()=>"Expected function to be called once.",pass:!0}}catch(o){return {message:()=>y(o),pass:false}}},async toBeCalledTwice(e){try{return await expect.poll(()=>e.callCount).toBe(2),{message:()=>"Expected function to be called twice.",pass:!0}}catch(o){return {message:()=>y(o),pass:false}}},async toBeCalledThrice(e){try{return await expect.poll(()=>e.callCount).toBe(3),{message:()=>"Expected function to be called thrice.",pass:!0}}catch(o){return {message:()=>y(o),pass:false}}},async toBeCalledWith(e,...o){try{return await expect(()=>{for(let[t,n]of o.entries())expect(e.lastCall?.args?.[t]).toStrictEqual(n);}).toPass(),{message:()=>`Expected function to be called with ${o.join(", ")}.`,pass:!0}}catch(t){return {message:()=>y(t),pass:false}}},async toBeCalledWithExactly(e,...o){try{return await expect.poll(()=>e.lastCall?.args).toStrictEqual(o),{message:()=>`Expected function to be called with exactly ${o.join(", ")}.`,pass:!0}}catch(t){return {message:()=>y(t),pass:false}}},toBeCalled(e){try{return expect(e.called).toBeTruthy(),{message:()=>"Expected function to be called.",pass:!0}}catch(o){return {message:()=>y(o),pass:false}}},async toBeCalledTimes(e,o){try{return await expect.poll(()=>e.callCount).toBe(o),{message:()=>`Expected function to be called ${o} times.`,pass:!0}}catch(t){return {message:()=>y(t),pass:false}}},async toBeAccessible(e,o={}){let t=await j(e),n=await t.first().evaluate(a=>{let c=a.ownerDocument?.defaultView;return c!==null&&c!==window.top}).catch(()=>false),r=z(o,n?W:[]),s,l=async()=>{let a=await H(t,o,r),c=o.treatIncompleteAsViolationIds??E,i=[...a.violations,...a.incomplete.filter(g=>c.includes(g.id))];return s={result:a,violations:i},i},u;try{if(o.timeout&&o.timeout>0){let a=expect.poll(l,{timeout:o.timeout});await(this.isNot?a.not.toHaveLength(0):a.toHaveLength(0));}else await l();}catch(a){u=a;}if(!s)throw new Error(`toBeAccessible: axe scan never completed.
|
|
13
|
+
${y(u)}`);if(s.violations.length===0)return {message:()=>"Expected accessibility violations but found none.",pass:true};this.isNot||await test.info().attach(o.attachmentName??"accessibility-scan-results",{body:JSON.stringify(s.result,null,2),contentType:"application/json"});let d=s.violations.map(a=>{let c=a.nodes.map(i=>Array.isArray(i.target)?i.target.join(" "):String(i.target)).join(`
|
|
14
14
|
`);return ` \u2022 [${a.id}] ${a.help}
|
|
15
|
-
${
|
|
15
|
+
${c}
|
|
16
16
|
${a.helpUrl??""}`}).join(`
|
|
17
|
-
`),
|
|
18
|
-
${
|
|
19
|
-
`,u=test.info();if(u.config.ignoreSnapshots)return {message:()=>"Class tree snapshot check skipped.",pass:!0};let
|
|
17
|
+
`),p=s.violations.length;return {message:()=>`Found ${p} accessibility violation${p===1?"":"s"}:
|
|
18
|
+
${d}`,pass:false}},async toMatchClassTree(e,o,t={}){let{prefix:n=O,ignoreHashed:r=false}=t,s=await e.evaluate(A,{prefix:n,ignoreHashed:r});if(!s){let l=Array.isArray(n)?n.map(u=>`${u}*`).join(" / "):`${n}*`;return {message:()=>`No ${l} classes found in the DOM tree.`,pass:false}}try{let l=`${s}
|
|
19
|
+
`,u=test.info();if(u.config.ignoreSnapshots)return {message:()=>"Class tree snapshot check skipped.",pass:!0};let p=q(u.project.snapshotDir,u.titlePath,o,n,r),a=u.config.updateSnapshots;await mkdir(C.dirname(p),{recursive:!0});let c;try{c=await readFile(p,"utf8");}catch(i){if(i.code==="ENOENT"&&a!=="none")return await writeFile(p,l),{message:()=>"Class tree snapshot created.",pass:!0};throw i}if(c!==l){if(a==="all"||a==="changed")return await writeFile(p,l),{message:()=>"Class tree snapshot updated.",pass:!0};try{expect(l).toBe(c);}catch(i){return {message:()=>`Class tree snapshot mismatch at ${p}
|
|
20
20
|
|
|
21
|
-
${i.message}`,pass:!1}}}return {message:()=>"Class tree matched snapshot.",pass:!0}}catch(
|
|
21
|
+
${i.message}`,pass:!1}}}return {message:()=>"Class tree matched snapshot.",pass:!0}}catch(l){return {message:()=>y(l),pass:false}}}});function T(e){let o=async()=>{if(await e.getAttribute("aria-expanded")!==null)return e;let r=e.locator("[aria-expanded]").first();return await r.count()>0?r:e},t=async()=>await(await o()).getAttribute("aria-expanded")==="true";return {isOpen:t,open:async(r="click")=>{if(await t())return;if(r==="click"){await e.click();return}await(await o()).press(r);}}}function R({frame:e,root:o}){let t=o??e.locator(".BaselineUI-Editor"),n=t.getByTestId("editor-font-color-button"),r=t.getByTestId("editor-background-color-button"),s=t.getByTestId("editor-add-link-button"),l=t.getByTestId("editor-help-button"),u=t.getByTestId("editor-mention-button"),d=t.getByRole("combobox"),p=e.getByTestId("editor-mention-listbox"),a=e.getByTestId("editor-help-dialog-close-button"),c=e.getByRole("dialog").filter({has:a}),i=e.getByRole("dialog").filter({has:e.getByTestId(/^editor-link-/)});return {root:t,textbox:t.getByRole("textbox"),placeholder:t.getByTestId("editor-placeholder"),toolbar:t.getByRole("toolbar"),boldButton:t.getByTestId("editor-bold-button"),italicButton:t.getByTestId("editor-italic-button"),underlineButton:t.getByTestId("editor-underline-button"),fontColorButton:n,backgroundColorButton:r,openFontColorPicker:T(n).open,openBackgroundColorPicker:T(r).open,addLinkButton:s,linkDialog:i,linkInput:e.getByTestId("editor-link-input"),linkAddButton:e.getByTestId("editor-link-add-button"),linkEditButton:e.getByTestId("editor-link-edit-button"),linkRemoveButton:e.getByTestId("editor-link-remove-button"),linkCancelButton:e.getByTestId("editor-link-cancel-button"),linkSaveButton:e.getByTestId("editor-link-save-button"),openLinkDialog:T(s).open,saveButton:t.getByTestId("editor-save-button"),cancelButton:t.getByTestId("editor-cancel-button"),mentionButton:u,helpButton:l,helpDialog:c,helpDialogCloseButton:a,async openHelpDialog(){await c.isVisible()||await l.click();},mentionInput:d,mentionListbox:p,mentionOption:g=>p.getByRole("option",{name:g}),async startMention(){await d.isVisible()||await u.click();}}}function D({frame:e,trigger:o,variant:t="dropzone"}){let n=e.getByTestId("file-uploader"),r=n.locator('input[type="file"]'),s=o??(t==="button"?n.getByRole("button"):e.getByTestId("file-uploader-dropzone"));return {root:n,button:s,input:r,dropzone:e.getByTestId("file-uploader-dropzone"),errorMessage:n.getByRole("alert"),async upload(l){await r.setInputFiles(l);}}}var v=(e=>{let t=K(e);return e.multiple&&(t=X(t,e.frame)),e.autocomplete&&(t=Q(t,e.frame)),t});function K({frame:e,trigger:o}){let t=o??e.getByTestId("select-button"),n=s=>e.getByRole("option",{name:s}),{open:r}=T(t);return {trigger:t,listbox:e.getByRole("listbox"),option:n,open:r,async selectOption(s){await r(),await n(s).click();}}}function X(e,o){return {...e,selectAllButton:o.getByTestId("select-all-button"),clearButton:o.getByTestId("select-clear-button"),tag:t=>e.trigger.getByRole("row",{name:t}),removeTagButton:t=>e.trigger.getByRole("row",{name:t}).getByRole("button")}}function Q(e,o){let t=o.getByRole("searchbox");return {...e,searchbox:t,async filter(n){await t.fill(n);}}}function Y(e){return {select:((o={})=>v({frame:e,...o})),editor:(o={})=>R({frame:e,...o}),fileUploader:(o={})=>D({frame:e,...o})}}export{E as DEFAULT_CRITICAL_INCOMPLETE_RULES,L as DEFAULT_DISABLED_RULES,w as DEFAULT_WCAG_TAGS,J as expect,Y as testers};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@baseline-ui/test-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "A collection of test utilities for Baseline UI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"axe-core": "^4.11.4",
|
|
54
54
|
"react-frame-component": "^5.3.2",
|
|
55
|
-
"@baseline-ui/core": "0.
|
|
55
|
+
"@baseline-ui/core": "1.0.0"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "tsup",
|
package/sbom.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "http://cyclonedx.org/schema/bom-1.
|
|
2
|
+
"$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
|
-
"specVersion": "1.
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
4
|
+
"specVersion": "1.6",
|
|
5
|
+
"serialNumber": "urn:uuid:193ab07f-43e4-401f-9435-a89aed60486f",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-
|
|
8
|
+
"timestamp": "2026-07-02T14:17:00.419Z",
|
|
9
9
|
"lifecycles": [
|
|
10
10
|
{
|
|
11
11
|
"phase": "pre-build"
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"component": {
|
|
24
24
|
"type": "library",
|
|
25
25
|
"name": "@baseline-ui/test-utils",
|
|
26
|
-
"version": "0.
|
|
27
|
-
"purl": "pkg:npm/@baseline-ui/test-utils@0.
|
|
28
|
-
"bom-ref": "pkg:npm/@baseline-ui/test-utils@0.
|
|
26
|
+
"version": "1.0.0",
|
|
27
|
+
"purl": "pkg:npm/@baseline-ui/test-utils@1.0.0",
|
|
28
|
+
"bom-ref": "pkg:npm/@baseline-ui/test-utils@1.0.0",
|
|
29
29
|
"licenses": [
|
|
30
30
|
{
|
|
31
31
|
"license": {
|
|
@@ -500,7 +500,7 @@
|
|
|
500
500
|
],
|
|
501
501
|
"dependencies": [
|
|
502
502
|
{
|
|
503
|
-
"ref": "pkg:npm
|
|
503
|
+
"ref": "pkg:npm/@baseline-ui/test-utils@1.0.0",
|
|
504
504
|
"dependsOn": [
|
|
505
505
|
"pkg:npm/%40neondatabase/serverless@1.1.0",
|
|
506
506
|
"pkg:npm/%40playwright/test@1.60.0",
|