@pushwoosh/dumb-components 2.9.12 → 2.9.13
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/package.json +4 -6
- package/Banner/__tests__/Banner.test.d.ts +0 -1
- package/Banner/__tests__/Banner.test.js +0 -57
- package/Button/__tests__/Button.test.d.ts +0 -1
- package/Button/__tests__/Button.test.js +0 -27
- package/Calendar/__tests__/CalendarMonthSlider.test.d.ts +0 -1
- package/Calendar/__tests__/CalendarMonthSlider.test.js +0 -85
- package/Calendar/__tests__/CellBox.test.d.ts +0 -1
- package/Calendar/__tests__/CellBox.test.js +0 -34
- package/Calendar/__tests__/helpers.test.d.ts +0 -1
- package/Calendar/__tests__/helpers.test.js +0 -143
- package/CardMetric/__tests__/CardMetric.test.d.ts +0 -1
- package/CardMetric/__tests__/CardMetric.test.js +0 -31
- package/Chip/__tests__/Chip.test.d.ts +0 -1
- package/Chip/__tests__/Chip.test.js +0 -101
- package/DateTimePicker/__tests__/YearView.test.d.ts +0 -1
- package/DateTimePicker/__tests__/YearView.test.js +0 -15
- package/DropdownMenu/__tests__/DropdownMenuItem.test.d.ts +0 -1
- package/DropdownMenu/__tests__/DropdownMenuItem.test.js +0 -109
- package/EditableField/__tests__/EditableField.test.d.ts +0 -1
- package/EditableField/__tests__/EditableField.test.js +0 -19
- package/EmailTemplatePreview/__tests__/clickMap.test.d.ts +0 -1
- package/EmailTemplatePreview/__tests__/clickMap.test.js +0 -168
- package/ExternalImagePreview/__tests__/ExternalImagePreview.test.d.ts +0 -1
- package/ExternalImagePreview/__tests__/ExternalImagePreview.test.js +0 -18
- package/InboxPreview/__tests__/helpers.test.d.ts +0 -1
- package/InboxPreview/__tests__/helpers.test.js +0 -201
- package/NativeRichMediaPreview/__tests__/NativeRichMediaPreview.test.d.ts +0 -1
- package/NativeRichMediaPreview/__tests__/NativeRichMediaPreview.test.js +0 -81
- package/PageHeader/__tests__/PageHeader.test.d.ts +0 -1
- package/PageHeader/__tests__/PageHeader.test.js +0 -37
- package/PushPreview/__tests__/PushPreview.test.d.ts +0 -1
- package/PushPreview/__tests__/PushPreview.test.js +0 -26
- package/PushStoriesPreview/__tests__/PushStoriesPreview.test.d.ts +0 -1
- package/PushStoriesPreview/__tests__/PushStoriesPreview.test.js +0 -234
- package/RadioCard/__tests__/RadioCard.test.d.ts +0 -1
- package/RadioCard/__tests__/RadioCard.test.js +0 -23
- package/RichmediaPreview/__tests__/RichmediaPreview.test.d.ts +0 -1
- package/RichmediaPreview/__tests__/RichmediaPreview.test.js +0 -21
- package/SandboxedHtmlFrame/__tests__/SandboxedHtmlFrame.test.d.ts +0 -1
- package/SandboxedHtmlFrame/__tests__/SandboxedHtmlFrame.test.js +0 -57
- package/Skeleton/__tests__/Skeleton.test.d.ts +0 -1
- package/Skeleton/__tests__/Skeleton.test.js +0 -101
- package/Spinner/__tests__/Spinner.test.d.ts +0 -1
- package/Spinner/__tests__/Spinner.test.js +0 -15
- package/Switch/__tests__/Switch.test.d.ts +0 -1
- package/Switch/__tests__/Switch.test.js +0 -44
- package/Tabs/__tests__/TabBar.test.d.ts +0 -1
- package/Tabs/__tests__/TabBar.test.js +0 -36
- package/Toast/__tests__/Toast.test.d.ts +0 -1
- package/Toast/__tests__/Toast.test.js +0 -20
- package/WhatsAppPreview/__tests__/WhatsAppAttachment.test.d.ts +0 -1
- package/WhatsAppPreview/__tests__/WhatsAppAttachment.test.js +0 -53
- package/WhatsAppPreview/__tests__/WhatsAppPreview.test.d.ts +0 -1
- package/WhatsAppPreview/__tests__/WhatsAppPreview.test.js +0 -55
- package/WhatsAppPreview/__tests__/attachment.test.d.ts +0 -1
- package/WhatsAppPreview/__tests__/attachment.test.js +0 -103
- package/WhatsAppPreview/__tests__/parseWhatsAppMarkup.test.d.ts +0 -1
- package/WhatsAppPreview/__tests__/parseWhatsAppMarkup.test.js +0 -59
- package/helpers/__tests__/barcodeUrl.test.d.ts +0 -1
- package/helpers/__tests__/barcodeUrl.test.js +0 -43
- package/helpers/__tests__/timezones.test.d.ts +0 -1
- package/helpers/__tests__/timezones.test.js +0 -188
- package/hooks/__tests__/useLayer.test.d.ts +0 -1
- package/hooks/__tests__/useLayer.test.js +0 -71
- package/polyglot/__tests__/filters.test.d.ts +0 -1
- package/polyglot/__tests__/filters.test.js +0 -152
- package/polyglot/__tests__/helpers.test.d.ts +0 -1
- package/polyglot/__tests__/helpers.test.js +0 -176
- package/polyglot/__tests__/parser.test.d.ts +0 -1
- package/polyglot/__tests__/parser.test.js +0 -108
- package/polyglot/__tests__/render.test.d.ts +0 -1
- package/polyglot/__tests__/render.test.js +0 -285
- package/shared/dropdownField/__tests__/useDropdownPosition.test.d.ts +0 -1
- package/shared/dropdownField/__tests__/useDropdownPosition.test.js +0 -60
- package/shared/dynamicContent/__tests__/token.test.d.ts +0 -1
- package/shared/dynamicContent/__tests__/token.test.js +0 -32
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pushwoosh/dumb-components",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.13",
|
|
4
4
|
"description": "React components to build Pushwoosh products",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.js",
|
|
@@ -18,19 +18,17 @@
|
|
|
18
18
|
"@testing-library/dom": "^10.4.2",
|
|
19
19
|
"@testing-library/jest-dom": "^6.9.1",
|
|
20
20
|
"@testing-library/react": "^16.3.0",
|
|
21
|
-
"@types/jest": "^30.0.0",
|
|
22
21
|
"@types/lodash": "^4.17.13",
|
|
23
22
|
"@types/react": "^18.3.31",
|
|
24
23
|
"@types/react-dom": "^18.3.7",
|
|
25
24
|
"@types/react-transition-group": "^4.4.12",
|
|
26
25
|
"@types/styled-components": "^5.1.34",
|
|
27
26
|
"glob": "^11.0.3",
|
|
28
|
-
"
|
|
29
|
-
"jest-environment-jsdom": "^30.2.0",
|
|
27
|
+
"jsdom": "^26.1.0",
|
|
30
28
|
"react": "^18.3.1",
|
|
31
29
|
"react-dom": "^18.3.1",
|
|
32
30
|
"styled-components": "^5.3.11",
|
|
33
|
-
"
|
|
31
|
+
"vitest": "^4.1.10"
|
|
34
32
|
},
|
|
35
33
|
"dependencies": {
|
|
36
34
|
"@codemirror/lang-html": "^6.4.9",
|
|
@@ -70,6 +68,6 @@
|
|
|
70
68
|
"check:lint": "echo \"Run check:lint\" && eslint src",
|
|
71
69
|
"check:lint-fix": "echo \"Run check:lint\" && eslint src --fix",
|
|
72
70
|
"check:types": "echo \"Run check:types\" && pushwoosh-engine lib:check-types",
|
|
73
|
-
"test": "
|
|
71
|
+
"test": "vitest run"
|
|
74
72
|
}
|
|
75
73
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import { Banner } from '../Banner';
|
|
4
|
-
describe('Banner', () => {
|
|
5
|
-
let consoleError;
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
8
|
-
});
|
|
9
|
-
afterEach(() => {
|
|
10
|
-
consoleError.mockRestore();
|
|
11
|
-
});
|
|
12
|
-
it('renders a title without children', () => {
|
|
13
|
-
render(_jsx(Banner, {
|
|
14
|
-
type: "info",
|
|
15
|
-
title: "Heading"
|
|
16
|
-
}));
|
|
17
|
-
expect(screen.getByText('Heading')).toBeInTheDocument();
|
|
18
|
-
});
|
|
19
|
-
it('renders children without a title', () => {
|
|
20
|
-
const {
|
|
21
|
-
container
|
|
22
|
-
} = render(_jsx(Banner, {
|
|
23
|
-
type: "info",
|
|
24
|
-
children: "Description"
|
|
25
|
-
}));
|
|
26
|
-
expect(screen.getByText('Description')).toBeInTheDocument();
|
|
27
|
-
expect(container.querySelector('h4')).toBeNull();
|
|
28
|
-
});
|
|
29
|
-
it('renders numeric zero children', () => {
|
|
30
|
-
render(_jsx(Banner, {
|
|
31
|
-
type: "info",
|
|
32
|
-
children: 0
|
|
33
|
-
}));
|
|
34
|
-
expect(screen.getByText('0')).toBeInTheDocument();
|
|
35
|
-
});
|
|
36
|
-
it('skips an empty title but keeps the children', () => {
|
|
37
|
-
const {
|
|
38
|
-
container
|
|
39
|
-
} = render(_jsx(Banner, {
|
|
40
|
-
type: "info",
|
|
41
|
-
title: "",
|
|
42
|
-
children: "Description"
|
|
43
|
-
}));
|
|
44
|
-
expect(screen.getByText('Description')).toBeInTheDocument();
|
|
45
|
-
expect(container.querySelector('h4')).toBeNull();
|
|
46
|
-
});
|
|
47
|
-
it('renders nothing and reports when there is neither title nor children', () => {
|
|
48
|
-
const {
|
|
49
|
-
container
|
|
50
|
-
} = render(_jsx(Banner, {
|
|
51
|
-
type: "info",
|
|
52
|
-
title: ""
|
|
53
|
-
}));
|
|
54
|
-
expect(container).toBeEmptyDOMElement();
|
|
55
|
-
expect(consoleError).toHaveBeenCalledWith('[Banner]: neither title nor children is set');
|
|
56
|
-
});
|
|
57
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import { Button } from '../Button';
|
|
4
|
-
describe('Button disabled colors', () => {
|
|
5
|
-
it('keeps white text on the red background for a disabled danger button', () => {
|
|
6
|
-
render(_jsx(Button, {
|
|
7
|
-
color: "danger",
|
|
8
|
-
isDisabled: true,
|
|
9
|
-
children: "Delete"
|
|
10
|
-
}));
|
|
11
|
-
const style = getComputedStyle(screen.getByRole('button'));
|
|
12
|
-
expect(style.color).toContain('--danger-shape-base-color');
|
|
13
|
-
expect(style.backgroundColor).toContain('--danger-shape-base-bg-color');
|
|
14
|
-
});
|
|
15
|
-
it('paints background, not text color, behind a disabled link-button', () => {
|
|
16
|
-
render(_jsx(Button, {
|
|
17
|
-
as: "a",
|
|
18
|
-
color: "primary",
|
|
19
|
-
isDisabled: true,
|
|
20
|
-
children: "Open"
|
|
21
|
-
}));
|
|
22
|
-
const style = getComputedStyle(screen.getByText('Open').closest('a'));
|
|
23
|
-
expect(style.color).toContain('--primary-shape-base-color');
|
|
24
|
-
expect(style.backgroundColor).toContain('--primary-shape-disabled-bg-color');
|
|
25
|
-
expect(style.borderColor).toBe('transparent');
|
|
26
|
-
});
|
|
27
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { act, fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
-
import { CalendarMonthSlider } from '../CalendarMonthSlider/CalendarMonthSlider';
|
|
4
|
-
const LAST_DAY_START = {
|
|
5
|
-
year: 2026,
|
|
6
|
-
month: 1,
|
|
7
|
-
day: 31
|
|
8
|
-
};
|
|
9
|
-
function renderSlider(startMonth = LAST_DAY_START) {
|
|
10
|
-
return render(_jsx(CalendarMonthSlider, {
|
|
11
|
-
startMonth: startMonth,
|
|
12
|
-
onDaySelect: jest.fn()
|
|
13
|
-
}));
|
|
14
|
-
}
|
|
15
|
-
function selectsOf(kind) {
|
|
16
|
-
const selects = screen.getAllByRole('combobox');
|
|
17
|
-
const isYear = select => /^\d+$/.test(select.options[0].text);
|
|
18
|
-
return selects.filter(select => kind === 'year' ? isYear(select) : !isYear(select));
|
|
19
|
-
}
|
|
20
|
-
function visibleMonths() {
|
|
21
|
-
const years = selectsOf('year');
|
|
22
|
-
return selectsOf('month').map((month, i) => `${years[i].value}-${month.value.padStart(2, '0')}`);
|
|
23
|
-
}
|
|
24
|
-
function step(direction) {
|
|
25
|
-
const [prev, next] = screen.getAllByRole('button');
|
|
26
|
-
fireEvent.click(direction === 'prev' ? prev : next);
|
|
27
|
-
act(() => {
|
|
28
|
-
jest.runAllTimers();
|
|
29
|
-
});
|
|
30
|
-
fireEvent.transitionEnd(selectsOf('month')[0]);
|
|
31
|
-
}
|
|
32
|
-
describe('CalendarMonthSlider', () => {
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
jest.useFakeTimers();
|
|
35
|
-
jest.setSystemTime(new Date(2026, 5, 15));
|
|
36
|
-
});
|
|
37
|
-
afterEach(() => {
|
|
38
|
-
jest.useRealTimers();
|
|
39
|
-
});
|
|
40
|
-
it('renders the start month regardless of the day it was opened on', () => {
|
|
41
|
-
renderSlider();
|
|
42
|
-
expect(visibleMonths()).toEqual(['2026-01']);
|
|
43
|
-
});
|
|
44
|
-
it('steps to the adjacent month in both directions without skipping one', () => {
|
|
45
|
-
renderSlider();
|
|
46
|
-
step('next');
|
|
47
|
-
expect(visibleMonths()).toEqual(['2026-02']);
|
|
48
|
-
step('next');
|
|
49
|
-
expect(visibleMonths()).toEqual(['2026-03']);
|
|
50
|
-
step('prev');
|
|
51
|
-
expect(visibleMonths()).toEqual(['2026-02']);
|
|
52
|
-
});
|
|
53
|
-
it('crosses the year boundary in both directions', () => {
|
|
54
|
-
renderSlider({
|
|
55
|
-
year: 2026,
|
|
56
|
-
month: 12,
|
|
57
|
-
day: 31
|
|
58
|
-
});
|
|
59
|
-
step('next');
|
|
60
|
-
expect(visibleMonths()).toEqual(['2027-01']);
|
|
61
|
-
step('prev');
|
|
62
|
-
step('prev');
|
|
63
|
-
expect(visibleMonths()).toEqual(['2026-11']);
|
|
64
|
-
});
|
|
65
|
-
it('shows the adjacent month, not the one after, while the step animates', () => {
|
|
66
|
-
renderSlider();
|
|
67
|
-
fireEvent.click(screen.getAllByRole('button')[1]);
|
|
68
|
-
expect(visibleMonths()).toEqual(['2026-01', '2026-02']);
|
|
69
|
-
});
|
|
70
|
-
it('jumps to the month and year picked in the selects', () => {
|
|
71
|
-
renderSlider();
|
|
72
|
-
fireEvent.change(selectsOf('month')[0], {
|
|
73
|
-
target: {
|
|
74
|
-
value: '2'
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
expect(visibleMonths()).toEqual(['2026-02']);
|
|
78
|
-
fireEvent.change(selectsOf('year')[0], {
|
|
79
|
-
target: {
|
|
80
|
-
value: '2027'
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
expect(visibleMonths()).toEqual(['2027-02']);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import { CellBox } from '../CalendarMonth/styles';
|
|
4
|
-
const PERIOD_VARIANTS = ['period', 'periodOutdated'];
|
|
5
|
-
function variantCss(variant) {
|
|
6
|
-
const {
|
|
7
|
-
rules
|
|
8
|
-
} = CellBox.componentStyle;
|
|
9
|
-
const flatten = part => {
|
|
10
|
-
if (Array.isArray(part)) return part.map(flatten).join('');
|
|
11
|
-
return typeof part === 'string' ? part : '';
|
|
12
|
-
};
|
|
13
|
-
return rules.filter(rule => typeof rule === 'function').map(rule => flatten(rule({
|
|
14
|
-
$variant: variant
|
|
15
|
-
}))).join('');
|
|
16
|
-
}
|
|
17
|
-
describe('CellBox period variants', () => {
|
|
18
|
-
it.each(PERIOD_VARIANTS)('anchors :before of %s to the cell with &, so stylis 4 does not turn it into a descendant selector', variant => {
|
|
19
|
-
const css = variantCss(variant);
|
|
20
|
-
expect(css).toContain('&:before');
|
|
21
|
-
expect(css).not.toMatch(/(^|[\s;{}])::?before/);
|
|
22
|
-
});
|
|
23
|
-
it.each(PERIOD_VARIANTS)('paints the %s background on the cell pseudo-element', variant => {
|
|
24
|
-
render(_jsx(CellBox, {
|
|
25
|
-
"data-testid": "cell",
|
|
26
|
-
"$variant": variant,
|
|
27
|
-
children: "1"
|
|
28
|
-
}));
|
|
29
|
-
const [className] = [...screen.getByTestId('cell').classList].slice(-1);
|
|
30
|
-
const styles = [...document.querySelectorAll('style')].map(node => node.textContent).join('');
|
|
31
|
-
expect(styles).toMatch(new RegExp(`\\.${className}:before\\{[^}]*background:`));
|
|
32
|
-
expect(styles).not.toContain(`.${className} :before`);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { addPeriod, getTimezoneOffset, setPeriodStruct } from '../helpers';
|
|
2
|
-
describe('addPeriod', () => {
|
|
3
|
-
it('clamps the day when the target month is shorter', () => {
|
|
4
|
-
expect(addPeriod({
|
|
5
|
-
year: 2026,
|
|
6
|
-
month: 8,
|
|
7
|
-
day: 31
|
|
8
|
-
}, 'month', 1)).toEqual({
|
|
9
|
-
year: 2026,
|
|
10
|
-
month: 9,
|
|
11
|
-
day: 30,
|
|
12
|
-
hour: 0,
|
|
13
|
-
minute: 0,
|
|
14
|
-
second: 0,
|
|
15
|
-
millisecond: 0
|
|
16
|
-
});
|
|
17
|
-
expect(addPeriod({
|
|
18
|
-
year: 2026,
|
|
19
|
-
month: 3,
|
|
20
|
-
day: 31
|
|
21
|
-
}, 'month', -1)).toEqual({
|
|
22
|
-
year: 2026,
|
|
23
|
-
month: 2,
|
|
24
|
-
day: 28,
|
|
25
|
-
hour: 0,
|
|
26
|
-
minute: 0,
|
|
27
|
-
second: 0,
|
|
28
|
-
millisecond: 0
|
|
29
|
-
});
|
|
30
|
-
expect(addPeriod({
|
|
31
|
-
year: 2024,
|
|
32
|
-
month: 2,
|
|
33
|
-
day: 29
|
|
34
|
-
}, 'year', 1)).toEqual({
|
|
35
|
-
year: 2025,
|
|
36
|
-
month: 2,
|
|
37
|
-
day: 28,
|
|
38
|
-
hour: 0,
|
|
39
|
-
minute: 0,
|
|
40
|
-
second: 0,
|
|
41
|
-
millisecond: 0
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
it('crosses year boundaries in both directions', () => {
|
|
45
|
-
expect(addPeriod({
|
|
46
|
-
year: 2026,
|
|
47
|
-
month: 12,
|
|
48
|
-
day: 15
|
|
49
|
-
}, 'month', 1)).toMatchObject({
|
|
50
|
-
year: 2027,
|
|
51
|
-
month: 1,
|
|
52
|
-
day: 15
|
|
53
|
-
});
|
|
54
|
-
expect(addPeriod({
|
|
55
|
-
year: 2026,
|
|
56
|
-
month: 1,
|
|
57
|
-
day: 15
|
|
58
|
-
}, 'month', -1)).toMatchObject({
|
|
59
|
-
year: 2025,
|
|
60
|
-
month: 12,
|
|
61
|
-
day: 15
|
|
62
|
-
});
|
|
63
|
-
expect(addPeriod({
|
|
64
|
-
year: 2026,
|
|
65
|
-
month: 5,
|
|
66
|
-
day: 10
|
|
67
|
-
}, 'month', -17)).toMatchObject({
|
|
68
|
-
year: 2024,
|
|
69
|
-
month: 12,
|
|
70
|
-
day: 10
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
it('keeps the time of day on month steps', () => {
|
|
74
|
-
expect(addPeriod({
|
|
75
|
-
year: 2026,
|
|
76
|
-
month: 1,
|
|
77
|
-
day: 31,
|
|
78
|
-
hour: 13,
|
|
79
|
-
minute: 45,
|
|
80
|
-
second: 7,
|
|
81
|
-
millisecond: 0
|
|
82
|
-
}, 'month', 1)).toMatchObject({
|
|
83
|
-
year: 2026,
|
|
84
|
-
month: 2,
|
|
85
|
-
day: 28,
|
|
86
|
-
hour: 13,
|
|
87
|
-
minute: 45,
|
|
88
|
-
second: 7
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
it('still rolls over on day steps', () => {
|
|
92
|
-
expect(addPeriod({
|
|
93
|
-
year: 2026,
|
|
94
|
-
month: 8,
|
|
95
|
-
day: 31
|
|
96
|
-
}, 'day', 1)).toMatchObject({
|
|
97
|
-
year: 2026,
|
|
98
|
-
month: 9,
|
|
99
|
-
day: 1
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
describe('setPeriodStruct', () => {
|
|
104
|
-
it('clamps the day when setting a shorter month', () => {
|
|
105
|
-
expect(setPeriodStruct({
|
|
106
|
-
year: 2026,
|
|
107
|
-
month: 1,
|
|
108
|
-
day: 31
|
|
109
|
-
}, 'month', 2)).toMatchObject({
|
|
110
|
-
year: 2026,
|
|
111
|
-
month: 2,
|
|
112
|
-
day: 28
|
|
113
|
-
});
|
|
114
|
-
expect(setPeriodStruct({
|
|
115
|
-
year: 2024,
|
|
116
|
-
month: 2,
|
|
117
|
-
day: 29
|
|
118
|
-
}, 'year', 2025)).toMatchObject({
|
|
119
|
-
year: 2025,
|
|
120
|
-
month: 2,
|
|
121
|
-
day: 28
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
describe('getTimezoneOffset', () => {
|
|
126
|
-
it('follows DST at the given instant', () => {
|
|
127
|
-
expect(getTimezoneOffset('Australia/Melbourne', new Date('2026-06-15T12:00:00Z'))).toBe(600);
|
|
128
|
-
expect(getTimezoneOffset('Australia/Melbourne', new Date('2026-10-10T12:00:00Z'))).toBe(660);
|
|
129
|
-
expect(getTimezoneOffset('Asia/Kolkata', new Date('2026-01-15T12:00:00Z'))).toBe(330);
|
|
130
|
-
});
|
|
131
|
-
it('builds one Intl.DateTimeFormat per zone, however many instants it is asked about', () => {
|
|
132
|
-
const construct = jest.spyOn(Intl, 'DateTimeFormat');
|
|
133
|
-
try {
|
|
134
|
-
getTimezoneOffset('Pacific/Chatham', new Date('2026-01-15T12:00:00Z'));
|
|
135
|
-
const afterFirst = construct.mock.calls.length;
|
|
136
|
-
getTimezoneOffset('Pacific/Chatham', new Date('2026-06-15T12:00:00Z'));
|
|
137
|
-
getTimezoneOffset('Pacific/Chatham', new Date('2026-10-10T12:00:00Z'));
|
|
138
|
-
expect(construct.mock.calls.length).toBe(afterFirst);
|
|
139
|
-
} finally {
|
|
140
|
-
construct.mockRestore();
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import { CardMetric } from '../CardMetric';
|
|
4
|
-
describe('CardMetric', () => {
|
|
5
|
-
it('styles a focused stacking card without leaking view/focus to the DOM', () => {
|
|
6
|
-
const {
|
|
7
|
-
container
|
|
8
|
-
} = render(_jsx(CardMetric, {
|
|
9
|
-
view: "stacking",
|
|
10
|
-
focus: true,
|
|
11
|
-
title: "Sent",
|
|
12
|
-
metric: 1
|
|
13
|
-
}));
|
|
14
|
-
const card = container.firstElementChild;
|
|
15
|
-
expect(card).not.toHaveAttribute('view');
|
|
16
|
-
expect(card).not.toHaveAttribute('focus');
|
|
17
|
-
expect(getComputedStyle(card).padding).toBe('24px');
|
|
18
|
-
expect(getComputedStyle(card).outlineWidth).toBe('4px');
|
|
19
|
-
});
|
|
20
|
-
it('collapses the body and marks the title clickable', () => {
|
|
21
|
-
render(_jsx(CardMetric, {
|
|
22
|
-
title: "Sent",
|
|
23
|
-
collapse: {
|
|
24
|
-
isCollapsed: true
|
|
25
|
-
},
|
|
26
|
-
children: "Body"
|
|
27
|
-
}));
|
|
28
|
-
expect(getComputedStyle(screen.getByText('Sent')).cursor).toBe('pointer');
|
|
29
|
-
expect(getComputedStyle(screen.getByText('Body').parentElement).gridTemplateRows).toBe('0fr');
|
|
30
|
-
});
|
|
31
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
-
import { Chip } from '../Chip';
|
|
4
|
-
describe('Chip', () => {
|
|
5
|
-
it('renders a passive chip as a div without a button role', () => {
|
|
6
|
-
const {
|
|
7
|
-
container
|
|
8
|
-
} = render(_jsx(Chip, {
|
|
9
|
-
children: "Tag"
|
|
10
|
-
}));
|
|
11
|
-
expect(container.firstChild?.nodeName).toBe('DIV');
|
|
12
|
-
expect(screen.queryByRole('button')).toBeNull();
|
|
13
|
-
});
|
|
14
|
-
it('renders a chip with onClick as a toggle button reflecting $selected', () => {
|
|
15
|
-
const onClick = jest.fn();
|
|
16
|
-
const {
|
|
17
|
-
rerender
|
|
18
|
-
} = render(_jsx(Chip, {
|
|
19
|
-
onClick: onClick,
|
|
20
|
-
children: "All"
|
|
21
|
-
}));
|
|
22
|
-
const chip = screen.getByRole('button', {
|
|
23
|
-
name: 'All'
|
|
24
|
-
});
|
|
25
|
-
expect(chip).toHaveAttribute('type', 'button');
|
|
26
|
-
expect(chip).toHaveAttribute('aria-pressed', 'false');
|
|
27
|
-
fireEvent.click(chip);
|
|
28
|
-
expect(onClick).toHaveBeenCalledTimes(1);
|
|
29
|
-
rerender(_jsx(Chip, {
|
|
30
|
-
onClick: onClick,
|
|
31
|
-
"$selected": true,
|
|
32
|
-
children: "All"
|
|
33
|
-
}));
|
|
34
|
-
expect(screen.getByRole('button', {
|
|
35
|
-
name: 'All'
|
|
36
|
-
})).toHaveAttribute('aria-pressed', 'true');
|
|
37
|
-
});
|
|
38
|
-
it('passes disabled to the button and blocks clicks', () => {
|
|
39
|
-
const onClick = jest.fn();
|
|
40
|
-
render(_jsx(Chip, {
|
|
41
|
-
onClick: onClick,
|
|
42
|
-
disabled: true,
|
|
43
|
-
children: "All"
|
|
44
|
-
}));
|
|
45
|
-
const chip = screen.getByRole('button', {
|
|
46
|
-
name: 'All'
|
|
47
|
-
});
|
|
48
|
-
expect(chip).toBeDisabled();
|
|
49
|
-
fireEvent.click(chip);
|
|
50
|
-
expect(onClick).not.toHaveBeenCalled();
|
|
51
|
-
});
|
|
52
|
-
it('keeps a closeable chip a div and exposes only the close button', () => {
|
|
53
|
-
const onClose = jest.fn();
|
|
54
|
-
const {
|
|
55
|
-
container
|
|
56
|
-
} = render(_jsx(Chip, {
|
|
57
|
-
onClick: () => {},
|
|
58
|
-
"$onClose": onClose,
|
|
59
|
-
children: "Tag"
|
|
60
|
-
}));
|
|
61
|
-
expect(container.firstChild?.nodeName).toBe('DIV');
|
|
62
|
-
const buttons = screen.getAllByRole('button');
|
|
63
|
-
expect(buttons).toHaveLength(1);
|
|
64
|
-
expect(buttons[0]).toHaveAccessibleName('Remove');
|
|
65
|
-
fireEvent.click(buttons[0]);
|
|
66
|
-
expect(onClose).toHaveBeenCalledTimes(1);
|
|
67
|
-
});
|
|
68
|
-
it('does not bubble a close click to the chip onClick', () => {
|
|
69
|
-
const onClick = jest.fn();
|
|
70
|
-
const onClose = jest.fn();
|
|
71
|
-
render(_jsx(Chip, {
|
|
72
|
-
onClick: onClick,
|
|
73
|
-
"$onClose": onClose,
|
|
74
|
-
children: "Tag"
|
|
75
|
-
}));
|
|
76
|
-
fireEvent.click(screen.getByRole('button', {
|
|
77
|
-
name: 'Remove'
|
|
78
|
-
}));
|
|
79
|
-
expect(onClose).toHaveBeenCalledTimes(1);
|
|
80
|
-
expect(onClick).not.toHaveBeenCalled();
|
|
81
|
-
});
|
|
82
|
-
it('treats explicit as="button" like the automatic interactive mode', () => {
|
|
83
|
-
render(_jsx(Chip, {
|
|
84
|
-
as: "button",
|
|
85
|
-
children: "Tag"
|
|
86
|
-
}));
|
|
87
|
-
const chip = screen.getByRole('button', {
|
|
88
|
-
name: 'Tag'
|
|
89
|
-
});
|
|
90
|
-
expect(chip).toHaveAttribute('type', 'button');
|
|
91
|
-
expect(chip).toHaveAttribute('aria-pressed', 'false');
|
|
92
|
-
});
|
|
93
|
-
it('does not become a button when read-only', () => {
|
|
94
|
-
render(_jsx(Chip, {
|
|
95
|
-
onClick: () => {},
|
|
96
|
-
"$readOnly": true,
|
|
97
|
-
children: "Tag"
|
|
98
|
-
}));
|
|
99
|
-
expect(screen.queryByRole('button')).toBeNull();
|
|
100
|
-
});
|
|
101
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
3
|
-
import { YearView } from '../components/YearView/YearView';
|
|
4
|
-
describe('YearView', () => {
|
|
5
|
-
it('makes month cells 59px tall without a height attribute', () => {
|
|
6
|
-
render(_jsx(YearView, {
|
|
7
|
-
year: "2026",
|
|
8
|
-
onChange: jest.fn(),
|
|
9
|
-
onSelect: jest.fn()
|
|
10
|
-
}));
|
|
11
|
-
const cell = screen.getAllByText(/^[A-Z][a-z]{2}$/)[0].closest('div[class]');
|
|
12
|
-
expect(cell).not.toHaveAttribute('height');
|
|
13
|
-
expect(getComputedStyle(cell).height).toBe('59px');
|
|
14
|
-
});
|
|
15
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
-
import { createRef } from 'react';
|
|
4
|
-
import { DropdownMenuItem } from '../components/DropdownMenuItem';
|
|
5
|
-
import { DropdownContext } from '../context';
|
|
6
|
-
const renderInMenu = (ui, close = jest.fn()) => render(_jsx(DropdownContext.Provider, {
|
|
7
|
-
value: close,
|
|
8
|
-
children: ui
|
|
9
|
-
}));
|
|
10
|
-
describe('DropdownMenuItem', () => {
|
|
11
|
-
it('calls onClick and closes the menu', () => {
|
|
12
|
-
const onClick = jest.fn();
|
|
13
|
-
const close = jest.fn();
|
|
14
|
-
renderInMenu(_jsx(DropdownMenuItem, {
|
|
15
|
-
onClick: onClick,
|
|
16
|
-
children: "Preview"
|
|
17
|
-
}), close);
|
|
18
|
-
const item = screen.getByRole('button', {
|
|
19
|
-
name: 'Preview'
|
|
20
|
-
});
|
|
21
|
-
expect(item).toHaveAttribute('type', 'button');
|
|
22
|
-
fireEvent.click(item);
|
|
23
|
-
expect(onClick).toHaveBeenCalledTimes(1);
|
|
24
|
-
expect(close).toHaveBeenCalledWith(false);
|
|
25
|
-
});
|
|
26
|
-
it('keeps a disabled item without hint natively disabled', () => {
|
|
27
|
-
renderInMenu(_jsx(DropdownMenuItem, {
|
|
28
|
-
onClick: jest.fn(),
|
|
29
|
-
disabled: true,
|
|
30
|
-
children: "Preview"
|
|
31
|
-
}));
|
|
32
|
-
expect(screen.getByRole('button', {
|
|
33
|
-
name: 'Preview'
|
|
34
|
-
})).toBeDisabled();
|
|
35
|
-
});
|
|
36
|
-
it('makes a disabled item with hint focusable, described and inert', () => {
|
|
37
|
-
const onClick = jest.fn();
|
|
38
|
-
const close = jest.fn();
|
|
39
|
-
renderInMenu(_jsx(DropdownMenuItem, {
|
|
40
|
-
onClick: onClick,
|
|
41
|
-
disabled: true,
|
|
42
|
-
hint: "Save the template first",
|
|
43
|
-
children: "Test email"
|
|
44
|
-
}), close);
|
|
45
|
-
const item = screen.getByRole('button', {
|
|
46
|
-
name: 'Test email'
|
|
47
|
-
});
|
|
48
|
-
expect(item).not.toBeDisabled();
|
|
49
|
-
expect(item).toHaveAttribute('aria-disabled', 'true');
|
|
50
|
-
expect(item).toHaveAccessibleDescription('Save the template first');
|
|
51
|
-
fireEvent.click(item);
|
|
52
|
-
expect(onClick).not.toHaveBeenCalled();
|
|
53
|
-
expect(close).not.toHaveBeenCalled();
|
|
54
|
-
});
|
|
55
|
-
it('shows the hint tooltip on hover and focus', () => {
|
|
56
|
-
renderInMenu(_jsx(DropdownMenuItem, {
|
|
57
|
-
onClick: jest.fn(),
|
|
58
|
-
disabled: true,
|
|
59
|
-
hint: "Save first",
|
|
60
|
-
children: "Test email"
|
|
61
|
-
}));
|
|
62
|
-
const item = screen.getByRole('button', {
|
|
63
|
-
name: 'Test email'
|
|
64
|
-
});
|
|
65
|
-
fireEvent.mouseEnter(item);
|
|
66
|
-
expect(screen.getAllByText('Save first')).toHaveLength(2);
|
|
67
|
-
fireEvent.mouseLeave(item);
|
|
68
|
-
expect(screen.getAllByText('Save first')).toHaveLength(1);
|
|
69
|
-
fireEvent.focusIn(item);
|
|
70
|
-
expect(screen.getAllByText('Save first')).toHaveLength(2);
|
|
71
|
-
});
|
|
72
|
-
it('ignores hint while enabled', () => {
|
|
73
|
-
renderInMenu(_jsx(DropdownMenuItem, {
|
|
74
|
-
onClick: jest.fn(),
|
|
75
|
-
hint: "Save first",
|
|
76
|
-
children: "Test email"
|
|
77
|
-
}));
|
|
78
|
-
expect(screen.queryByText('Save first')).toBeNull();
|
|
79
|
-
expect(screen.getByRole('button', {
|
|
80
|
-
name: 'Test email'
|
|
81
|
-
})).not.toHaveAttribute('aria-describedby');
|
|
82
|
-
});
|
|
83
|
-
it('forwards ref to the item button, with and without hint', () => {
|
|
84
|
-
const ref = createRef();
|
|
85
|
-
const {
|
|
86
|
-
rerender
|
|
87
|
-
} = renderInMenu(_jsx(DropdownMenuItem, {
|
|
88
|
-
ref: ref,
|
|
89
|
-
onClick: jest.fn(),
|
|
90
|
-
children: "Preview"
|
|
91
|
-
}));
|
|
92
|
-
expect(ref.current).toBe(screen.getByRole('button', {
|
|
93
|
-
name: 'Preview'
|
|
94
|
-
}));
|
|
95
|
-
rerender(_jsx(DropdownContext.Provider, {
|
|
96
|
-
value: jest.fn(),
|
|
97
|
-
children: _jsx(DropdownMenuItem, {
|
|
98
|
-
ref: ref,
|
|
99
|
-
onClick: jest.fn(),
|
|
100
|
-
disabled: true,
|
|
101
|
-
hint: "Add content",
|
|
102
|
-
children: "Preview"
|
|
103
|
-
})
|
|
104
|
-
}));
|
|
105
|
-
expect(ref.current).toBe(screen.getByRole('button', {
|
|
106
|
-
name: 'Preview'
|
|
107
|
-
}));
|
|
108
|
-
});
|
|
109
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|