@sebgroup/green-core 2.28.0 → 2.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/popover/popover.component.js +0 -3
- package/custom-elements.json +7847 -7638
- package/gds-element.js +1 -1
- package/generated/mcp/components.json +1 -1
- package/generated/mcp/icons.json +1 -1
- package/generated/mcp/index.json +1 -1
- package/generated/react/index.d.ts +1 -1
- package/generated/react/index.js +1 -1
- package/package.json +480 -480
- package/shared-styles/rbcb-toggle.style.js +2 -3
- package/test-setup.d.ts +14 -0
- package/test-setup.js +35 -0
- package/utils/helpers/custom-element-scoping.js +1 -1
- package/utils/testing/index.d.ts +47 -15
- package/utils/testing/index.js +145 -53
package/test-setup.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface AccessibleOptions {
|
|
2
|
+
rules?: Record<string, {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
}>;
|
|
5
|
+
}
|
|
6
|
+
declare module 'vitest' {
|
|
7
|
+
interface Assertion {
|
|
8
|
+
toBeAccessible(options?: AccessibleOptions): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
interface AsymmetricMatchersContaining {
|
|
11
|
+
toBeAccessible(options?: AccessibleOptions): void;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export {};
|
package/test-setup.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as axe from "axe-core";
|
|
2
|
+
import { afterEach, expect } from "vitest";
|
|
3
|
+
expect.extend({
|
|
4
|
+
async toBeAccessible(received, options = {}) {
|
|
5
|
+
const { rules = {} } = options;
|
|
6
|
+
const results = await axe.run(received, {
|
|
7
|
+
rules: {
|
|
8
|
+
// Disable color-contrast by default as it's often problematic in test environments
|
|
9
|
+
"color-contrast": { enabled: false },
|
|
10
|
+
...rules
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
const violations = results.violations;
|
|
14
|
+
if (violations.length === 0) {
|
|
15
|
+
return {
|
|
16
|
+
pass: true,
|
|
17
|
+
message: () => "Expected element to have accessibility violations"
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const formattedViolations = violations.map((violation) => {
|
|
21
|
+
const nodes = violation.nodes.map((node) => ` - ${node.html}`).join("\n");
|
|
22
|
+
return ` ${violation.id}: ${violation.description}
|
|
23
|
+
${nodes}`;
|
|
24
|
+
}).join("\n\n");
|
|
25
|
+
return {
|
|
26
|
+
pass: false,
|
|
27
|
+
message: () => `Expected element to be accessible, but found the following violations:
|
|
28
|
+
|
|
29
|
+
${formattedViolations}`
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
document.body.innerHTML = "";
|
|
35
|
+
});
|
package/utils/testing/index.d.ts
CHANGED
|
@@ -1,32 +1,64 @@
|
|
|
1
|
-
|
|
1
|
+
import { html, TemplateResult } from 'lit';
|
|
2
|
+
export { html };
|
|
3
|
+
/**
|
|
4
|
+
* Renders a lit template into a container and returns the first element child.
|
|
5
|
+
* Replacement for @open-wc/testing fixture function.
|
|
6
|
+
*/
|
|
7
|
+
export declare function fixture<T extends Element>(template: TemplateResult): Promise<T>;
|
|
8
|
+
/**
|
|
9
|
+
* Wait for a specified number of milliseconds.
|
|
10
|
+
* Replacement for @open-wc/testing aTimeout function.
|
|
11
|
+
*/
|
|
12
|
+
export declare function aTimeout(ms: number): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Wait until a condition becomes true or timeout.
|
|
15
|
+
* Replacement for @open-wc/testing waitUntil function.
|
|
16
|
+
*/
|
|
17
|
+
export declare function waitUntil(condition: () => boolean | Promise<boolean>, message?: string, options?: {
|
|
18
|
+
interval?: number;
|
|
19
|
+
timeout?: number;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
/** A testing utility that clicks on an element. */
|
|
2
22
|
export declare function clickOnElement(
|
|
3
23
|
/** The element to click */
|
|
4
24
|
el: Element,
|
|
5
|
-
/** The location of the element to click */
|
|
6
|
-
|
|
7
|
-
/** The horizontal offset to apply to the position when clicking */
|
|
8
|
-
|
|
9
|
-
/** The vertical offset to apply to the position when clicking */
|
|
10
|
-
|
|
25
|
+
/** The location of the element to click (ignored for now, clicks center) */
|
|
26
|
+
_position?: 'top' | 'right' | 'bottom' | 'left' | 'center',
|
|
27
|
+
/** The horizontal offset to apply to the position when clicking (ignored) */
|
|
28
|
+
_offsetX?: number,
|
|
29
|
+
/** The vertical offset to apply to the position when clicking (ignored) */
|
|
30
|
+
_offsetY?: number): Promise<void>;
|
|
11
31
|
/** A testing utility that moves the mouse onto an element. */
|
|
12
32
|
export declare function moveMouseOnElement(
|
|
13
|
-
/** The element to
|
|
33
|
+
/** The element to hover */
|
|
14
34
|
el: Element,
|
|
15
|
-
/** The location of the element
|
|
16
|
-
|
|
17
|
-
/** The horizontal offset to apply
|
|
18
|
-
|
|
19
|
-
/** The vertical offset to apply
|
|
20
|
-
|
|
35
|
+
/** The location of the element (ignored for now, hovers center) */
|
|
36
|
+
_position?: 'top' | 'right' | 'bottom' | 'left' | 'center',
|
|
37
|
+
/** The horizontal offset to apply (ignored) */
|
|
38
|
+
_offsetX?: number,
|
|
39
|
+
/** The vertical offset to apply (ignored) */
|
|
40
|
+
_offsetY?: number): Promise<void>;
|
|
21
41
|
/** A testing utility that drags an element with the mouse. */
|
|
22
42
|
export declare function dragElement(
|
|
23
43
|
/** The element to drag */
|
|
24
|
-
|
|
44
|
+
source: Element,
|
|
25
45
|
/** The horizontal distance to drag in pixels */
|
|
26
46
|
deltaX?: number,
|
|
27
47
|
/** The vertical distance to drag in pixels */
|
|
28
48
|
deltaY?: number): Promise<void>;
|
|
29
49
|
export declare function isWebKit(): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* WebKit-aware Tab helper.
|
|
52
|
+
* On WebKit, use Alt+Tab to move focus
|
|
53
|
+
*/
|
|
54
|
+
export declare function tabNext(options?: {
|
|
55
|
+
shift?: boolean;
|
|
56
|
+
}): Promise<void>;
|
|
30
57
|
export declare function isChromium(): boolean;
|
|
31
58
|
export declare function isFirefox(): boolean;
|
|
32
59
|
export declare function onlyDate(date: Date | undefined): string | undefined;
|
|
60
|
+
/** A helper to wait for a specific amount of time */
|
|
61
|
+
export declare function timeout(ms: number): Promise<void>;
|
|
62
|
+
/** A helper to wait for a condition to become true */
|
|
63
|
+
export declare function conditionToBeTrue(condition: () => boolean, timeoutMs?: number): Promise<void>;
|
|
64
|
+
export declare function setViewportSize(width: number, height: number): Promise<() => Promise<void>>;
|
package/utils/testing/index.js
CHANGED
|
@@ -1,69 +1,121 @@
|
|
|
1
1
|
import "../../chunks/chunk.QU3DSPNU.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
import { html, render } from "lit";
|
|
3
|
+
import { page, userEvent } from "@vitest/browser/context";
|
|
4
|
+
async function fixture(template) {
|
|
5
|
+
const container = document.createElement("div");
|
|
6
|
+
document.body.appendChild(container);
|
|
7
|
+
render(template, container);
|
|
8
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
9
|
+
await Promise.resolve();
|
|
10
|
+
const element = container.firstElementChild;
|
|
11
|
+
return element;
|
|
12
|
+
}
|
|
13
|
+
function aTimeout(ms) {
|
|
14
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
15
|
+
}
|
|
16
|
+
async function waitUntil(condition, message, options = {}) {
|
|
17
|
+
const { interval = 50, timeout: timeout2 = 1e3 } = options;
|
|
18
|
+
const startTime = Date.now();
|
|
19
|
+
while (Date.now() - startTime <= timeout2) {
|
|
20
|
+
const result = await condition();
|
|
21
|
+
if (result) return;
|
|
22
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
23
|
+
}
|
|
24
|
+
throw new Error(message || `waitUntil timed out after ${timeout2}ms`);
|
|
25
|
+
}
|
|
26
|
+
async function clickOnElement(el, _position = "center", _offsetX = 0, _offsetY = 0) {
|
|
27
|
+
const rect = el.getBoundingClientRect();
|
|
28
|
+
const position = getClickPosition(rect, _position, _offsetX, _offsetY);
|
|
29
|
+
try {
|
|
30
|
+
await withTimeout(userEvent.click(el, { position }), 1e3);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
await withTimeout(userEvent.click(el, { position, force: true }), 1e3);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function withTimeout(promise, ms) {
|
|
36
|
+
let timeoutId;
|
|
37
|
+
const timeout2 = new Promise((_, reject) => {
|
|
38
|
+
timeoutId = setTimeout(() => {
|
|
39
|
+
reject(new Error(`click timed out after ${ms}ms`));
|
|
40
|
+
}, ms);
|
|
41
|
+
});
|
|
42
|
+
try {
|
|
43
|
+
return await Promise.race([promise, timeout2]);
|
|
44
|
+
} finally {
|
|
45
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function getClickPosition(rect, position, offsetX, offsetY) {
|
|
49
|
+
const centerX = rect.width / 2;
|
|
50
|
+
const centerY = rect.height / 2;
|
|
51
|
+
let x = centerX;
|
|
52
|
+
let y = centerY;
|
|
9
53
|
switch (position) {
|
|
10
54
|
case "top":
|
|
11
|
-
|
|
12
|
-
clickY = y;
|
|
13
|
-
break;
|
|
14
|
-
case "right":
|
|
15
|
-
clickX = x + width - 1;
|
|
16
|
-
clickY = centerY;
|
|
55
|
+
y = 1;
|
|
17
56
|
break;
|
|
18
57
|
case "bottom":
|
|
19
|
-
|
|
20
|
-
clickY = y + height - 1;
|
|
58
|
+
y = Math.max(1, rect.height - 1);
|
|
21
59
|
break;
|
|
22
60
|
case "left":
|
|
23
|
-
|
|
24
|
-
clickY = centerY;
|
|
61
|
+
x = 1;
|
|
25
62
|
break;
|
|
63
|
+
case "right":
|
|
64
|
+
x = Math.max(1, rect.width - 1);
|
|
65
|
+
break;
|
|
66
|
+
case "center":
|
|
26
67
|
default:
|
|
27
|
-
|
|
28
|
-
clickY = centerY;
|
|
68
|
+
break;
|
|
29
69
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
return {
|
|
71
|
+
x: Math.max(1, x + offsetX),
|
|
72
|
+
y: Math.max(1, y + offsetY)
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async function moveMouseOnElement(el, _position = "center", _offsetX = 0, _offsetY = 0) {
|
|
76
|
+
await userEvent.hover(el);
|
|
77
|
+
}
|
|
78
|
+
async function dragElement(source, deltaX = 0, deltaY = 0) {
|
|
79
|
+
const rect = source.getBoundingClientRect();
|
|
80
|
+
const targetX = rect.left + rect.width / 2 + deltaX;
|
|
81
|
+
const targetY = rect.top + rect.height / 2 + deltaY;
|
|
82
|
+
await userEvent.hover(source);
|
|
83
|
+
const event = new MouseEvent("mousedown", {
|
|
84
|
+
bubbles: true,
|
|
85
|
+
cancelable: true,
|
|
86
|
+
clientX: rect.left + rect.width / 2,
|
|
87
|
+
clientY: rect.top + rect.height / 2
|
|
88
|
+
});
|
|
89
|
+
source.dispatchEvent(event);
|
|
90
|
+
const moveEvent = new MouseEvent("mousemove", {
|
|
91
|
+
bubbles: true,
|
|
92
|
+
cancelable: true,
|
|
93
|
+
clientX: targetX,
|
|
94
|
+
clientY: targetY
|
|
95
|
+
});
|
|
96
|
+
source.dispatchEvent(moveEvent);
|
|
97
|
+
const upEvent = new MouseEvent("mouseup", {
|
|
98
|
+
bubbles: true,
|
|
99
|
+
cancelable: true,
|
|
100
|
+
clientX: targetX,
|
|
101
|
+
clientY: targetY
|
|
102
|
+
});
|
|
103
|
+
source.dispatchEvent(upEvent);
|
|
63
104
|
}
|
|
64
105
|
function isWebKit() {
|
|
65
106
|
return navigator.userAgent.toLowerCase().indexOf("safari") > -1 && navigator.userAgent.toLowerCase().indexOf("chrome") < 0;
|
|
66
107
|
}
|
|
108
|
+
async function tabNext(options) {
|
|
109
|
+
if (isWebKit()) {
|
|
110
|
+
if (options?.shift) {
|
|
111
|
+
await userEvent.keyboard("{Alt>}{Shift>}{Tab}{/Shift}{/Alt}");
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
await userEvent.keyboard("{Alt>}{Tab}{/Alt}");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
await userEvent.tab(options);
|
|
118
|
+
}
|
|
67
119
|
function isChromium() {
|
|
68
120
|
return navigator.userAgent.toLowerCase().indexOf("chrome") > -1;
|
|
69
121
|
}
|
|
@@ -74,12 +126,52 @@ function onlyDate(date) {
|
|
|
74
126
|
if (!date) return void 0;
|
|
75
127
|
return date.toISOString().split("T")[0];
|
|
76
128
|
}
|
|
129
|
+
function timeout(ms) {
|
|
130
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
131
|
+
}
|
|
132
|
+
function conditionToBeTrue(condition, timeoutMs = 1e3) {
|
|
133
|
+
return new Promise((resolve, reject) => {
|
|
134
|
+
const startTime = Date.now();
|
|
135
|
+
const check = () => {
|
|
136
|
+
if (condition()) {
|
|
137
|
+
resolve();
|
|
138
|
+
} else if (Date.now() - startTime > timeoutMs) {
|
|
139
|
+
reject(new Error("Condition was not met within timeout"));
|
|
140
|
+
} else {
|
|
141
|
+
requestAnimationFrame(check);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
check();
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
async function setViewportSize(width, height) {
|
|
148
|
+
const originalSize = {
|
|
149
|
+
width: window.innerWidth,
|
|
150
|
+
height: window.innerHeight
|
|
151
|
+
};
|
|
152
|
+
if (page) {
|
|
153
|
+
await page.viewport(width, height);
|
|
154
|
+
}
|
|
155
|
+
return async () => {
|
|
156
|
+
if (page) {
|
|
157
|
+
await page.viewport(originalSize.width, originalSize.height);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
77
161
|
export {
|
|
162
|
+
aTimeout,
|
|
78
163
|
clickOnElement,
|
|
164
|
+
conditionToBeTrue,
|
|
79
165
|
dragElement,
|
|
166
|
+
fixture,
|
|
167
|
+
html,
|
|
80
168
|
isChromium,
|
|
81
169
|
isFirefox,
|
|
82
170
|
isWebKit,
|
|
83
171
|
moveMouseOnElement,
|
|
84
|
-
onlyDate
|
|
172
|
+
onlyDate,
|
|
173
|
+
setViewportSize,
|
|
174
|
+
tabNext,
|
|
175
|
+
timeout,
|
|
176
|
+
waitUntil
|
|
85
177
|
};
|