Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 30 additions & 28 deletions playwright/a11y-matrix-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ function flattenSuites(suites) {
test: spec.title,
status: result?.status ?? 'unknown',
error: result?.error?.message ?? '',
axeResults: parseAxeAttachment(result)
axeResults: parseAxeAttachments(result)
});
}
for (const sub of suite.suites || []) {
Expand All @@ -91,26 +91,27 @@ function flattenSuites(suites) {
test: `${sub.title} - ${spec.title}`,
status: result?.status ?? 'unknown',
error: result?.error?.message ?? '',
axeResults: parseAxeAttachment(result)
axeResults: parseAxeAttachments(result)
});
}
}
}
return out;
}

/** Extract the axe-core results object from the test attachment */
function parseAxeAttachment(result) {
if (!result?.attachments) return null;
const att = result.attachments.find(
(a) => a.name === 'accessibility-scan-results' && a.body
);
if (!att) return null;
try {
return JSON.parse(Buffer.from(att.body, 'base64').toString());
} catch {
return null;
}
/** Extract all axe-core results objects from the test attachments (one per state) */
function parseAxeAttachments(result) {
if (!result?.attachments) return [];
return result.attachments
.filter((a) => a.name.endsWith('-accessibility-scan') && a.body)
.map((a) => {
try {
return JSON.parse(Buffer.from(a.body, 'base64').toString());
} catch {
return null;
}
})
.filter(Boolean);
}

const tests = flattenSuites(data.suites?.[0]?.suites ?? []);
Expand All @@ -132,23 +133,24 @@ function extractViolationIds(errorMsg) {
];
}

function addResults(comp, status, errorMsg, axeResults) {
function addResults(comp, status, errorMsg, axeResultsArr) {
allComponents.add(comp);

// Use axe attachment for accurate applicability data
if (axeResults) {
for (const v of axeResults.violations || []) {
failedRules[`${comp}|||${v.id}`] = true;
applicableRules[`${comp}|||${v.id}`] = true;
allRules.add(v.id);
}
for (const p of axeResults.passes || []) {
applicableRules[`${comp}|||${p.id}`] = true;
}
for (const inc of axeResults.incomplete || []) {
applicableRules[`${comp}|||${inc.id}`] = true;
// Use axe attachments for accurate applicability data (one per state scan)
if (axeResultsArr.length > 0) {
for (const axeResults of axeResultsArr) {
for (const v of axeResults.violations || []) {
failedRules[`${comp}|||${v.id}`] = true;
applicableRules[`${comp}|||${v.id}`] = true;
allRules.add(v.id);
}
for (const p of axeResults.passes || []) {
applicableRules[`${comp}|||${p.id}`] = true;
}
for (const inc of axeResults.incomplete || []) {
applicableRules[`${comp}|||${inc.id}`] = true;
}
}
// inapplicable rules are NOT added to applicableRules
return;
}

Expand Down
21 changes: 12 additions & 9 deletions playwright/cps-accessibility.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,18 @@ const components: ComponentEntry[] = [
},
{ route: '/checkbox', name: 'Checkbox', selector: 'cps-checkbox' },
{ route: '/chip', name: 'Chip', selector: 'cps-chip' },
// {
// route: '/datepicker',
// name: 'Datepicker',
// selector: ['cps-datepicker', '.cps-datepicker-calendar-menu'],
// setup: async (page) => {
// await page.waitForSelector('cps-datepicker');
// await page.locator('cps-datepicker .cps-icon').first().click();
// }
// },
{
route: '/datepicker',
name: 'Datepicker',
selector: ['cps-datepicker', '.cps-datepicker-calendar-menu'],
setup: async (page) => {
await page.waitForSelector('cps-datepicker');
await page
.locator('cps-datepicker .cps-input-prefix-icon')
.first()
.click();
}
},
{
route: '/dialog',
name: 'Confirmation dialog',
Expand Down
21 changes: 17 additions & 4 deletions projects/composition/src/app/api-data/cps-datepicker.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,21 @@
"default": "100%",
"description": "Width of the datepicker of type number denoting pixels or string."
},
{
"name": "dateFormat",
"optional": false,
"readonly": false,
"type": "CpsDatepickerDateFormat",
"default": "DD/MM/YYYY",
"description": "Date format for displaying and parsing the date string."
},
{
"name": "placeholder",
"optional": false,
"readonly": false,
"type": "string",
"default": "MM/DD/YYYY",
"description": "Placeholder text."
"default": "",
"description": "Placeholder text. Defaults to the configured dateFormat."
},
{
"name": "hint",
Expand Down Expand Up @@ -145,14 +153,14 @@
"name": "minDate",
"optional": false,
"readonly": false,
"type": "Date",
"type": "Date | undefined",
"description": "Minimal date availalbe for selection."
},
{
"name": "maxDate",
"optional": false,
"readonly": false,
"type": "Date",
"type": "Date | undefined",
"description": "Maximal date availalbe for selection."
},
{
Expand Down Expand Up @@ -189,6 +197,11 @@
"name": "CpsDatepickerAppearanceType",
"value": "\"outlined\" | \"underlined\" | \"borderless\"",
"description": "CpsDatepickerAppearanceType is used to define the border of the datepicker input."
},
{
"name": "CpsDatepickerDateFormat",
"value": "\"DD/MM/YYYY\" | \"MM/DD/YYYY\" | \"YYYY/MM/DD\"",
"description": "CpsDatepickerDateFormat defines the display and input format of the date string."
}
]
}
Expand Down
32 changes: 32 additions & 0 deletions projects/composition/src/app/api-data/cps-input.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,38 @@
"default": "",
"description": "Aria label for the input component, used for accessibility, it takes precedence over label."
},
{
"name": "inputRole",
"optional": false,
"readonly": false,
"type": "string | null",
"default": "null",
"description": "WAI-ARIA role for the native input element."
},
{
"name": "ariaExpanded",
"optional": false,
"readonly": false,
"type": "boolean | null",
"default": "null",
"description": "Whether the element controlled by this input is expanded."
},
{
"name": "ariaHasPopup",
"optional": false,
"readonly": false,
"type": "string | null",
"default": "null",
"description": "Type of popup element the input controls."
},
{
"name": "ariaControls",
"optional": false,
"readonly": false,
"type": "string | null",
"default": "null",
"description": "ID of the element controlled by this input."
},
{
"name": "hint",
"optional": false,
Expand Down
1 change: 1 addition & 0 deletions projects/composition/src/app/api-data/types_map.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"CpsAutocompleteAppearanceType": "autocomplete",
"CpsButtonToggleOption": "button-toggle",
"CpsDatepickerAppearanceType": "datepicker",
"CpsDatepickerDateFormat": "datepicker",
"CpsDividerType": "divider",
"IconType": "icon",
"iconSizeType": "icon",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
[clearable]="true"
label="Datepicker with two-way binding, select a date"
[(ngModel)]="syncVal"
width="350"
hint="This datepicker has a fixed width of 350px"
width="25rem"
hint="This datepicker has a fixed width of 25rem"
placeholder="Select a date"
[ngModelOptions]="{ standalone: true }">
</cps-datepicker>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
.datepickers-group {
gap: 24px;
gap: 1.5rem;
display: flex;
flex-direction: column;
}

.sync-val-example {
.sync-val {
margin-top: 8px;
margin-top: 0.5rem;
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
<div
class="cps-datepicker"
[ngStyle]="{ width: cvtWidth }"
[class.focused]="isOpened">
<div class="cps-datepicker" [style.width]="cvtWidth" [class.focused]="isOpened">
<cps-input
#datepickerInput
[disabled]="disabled"
[value]="stringDate"
[label]="label"
[ariaLabel]="ariaLabel"
inputRole="combobox"
ariaHasPopup="dialog"
[ariaExpanded]="isOpened"
[ariaControls]="calendarId"
prefixIcon="datepicker"
prefixIconAriaLabel="Open calendar"
[placeholder]="placeholder"
[placeholder]="placeholder || dateFormat"
(prefixIconClicked)="onClickCalendarIcon()"
[prefixIconClickable]="true"
(focused)="onInputFocus()"
(keydown)="onInputKeydown($event)"
(valueChanged)="onInputValueChanged($event)"
[clearable]="clearable"
(blurred)="onInputBlur()"
Expand All @@ -32,20 +34,27 @@
<cps-menu
#calendarMenu
[withArrow]="false"
(beforeMenuHidden)="onBeforeCalendarHidden()"
(menuShown)="onCalendarMenuShown()"
(beforeMenuHidden)="onBeforeCalendarHidden($event)"
(contentClicked)="onCalendarContentClick()"
[focusOnShow]="false"
hideTransitionOptions="0s linear"
containerClass="cps-datepicker-calendar-menu">
<div class="cps-datepicker-calendar">
<div
class="cps-datepicker-calendar"
role="dialog"
aria-label="Date picker"
[attr.id]="calendarId"
(click)="onCalendarClick($event)">
<p-datepicker
[(ngModel)]="value"
[inline]="true"
[showIcon]="true"
[showButtonBar]="showTodayButton"
(onSelect)="onSelectCalendarDate($event)"
(onClearClick)="onClearCalendarDate()"
[showOtherMonths]="false"
(onClearClick)="onSelectCalendarDate(null)"
(onMonthChange)="onDatepickerMonthChange()"
(onYearChange)="onYearSelected()"
[minDate]="minDate"
[maxDate]="maxDate" />
</div>
Expand Down
Loading
Loading