newspack-components 4.7.0 → 4.8.0-alpha.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/CHANGELOG.md +20 -0
- package/DEVELOPMENT.md +42 -21
- package/dist/cjs/_mixins.scss +13 -0
- package/dist/cjs/_variables.scss +12 -0
- package/dist/cjs/action-card/index.js +18 -10
- package/dist/cjs/action-card/index.test.js +91 -0
- package/dist/cjs/action-card/style.scss +2 -40
- package/dist/cjs/button/index.js +8 -3
- package/dist/cjs/button/index.test.js +61 -5
- package/dist/cjs/card/core-card.js +0 -2
- package/dist/cjs/card/style-core.scss +7 -5
- package/dist/cjs/card-feature/index.js +75 -61
- package/dist/cjs/card-feature/index.test.js +396 -54
- package/dist/cjs/card-feature/style.scss +20 -31
- package/dist/cjs/card-form/index.js +5 -5
- package/dist/cjs/card-sortable-list/index.js +5 -3
- package/dist/cjs/card-sortable-list/index.test.js +50 -0
- package/dist/cjs/collapsible-group/context.js +19 -0
- package/dist/cjs/collapsible-group/index.js +24 -0
- package/dist/cjs/collapsible-group/index.test.js +215 -0
- package/dist/cjs/collapsible-group/item.js +61 -0
- package/dist/cjs/collapsible-group/root.js +62 -0
- package/dist/cjs/collapsible-group/style.scss +47 -0
- package/dist/cjs/collapsible-group/types.js +5 -0
- package/dist/cjs/empty-state/actions.js +45 -0
- package/dist/cjs/empty-state/context.js +41 -0
- package/dist/cjs/empty-state/header.js +66 -0
- package/dist/cjs/empty-state/index.js +31 -0
- package/dist/cjs/empty-state/index.test.js +303 -0
- package/dist/cjs/empty-state/root.js +56 -0
- package/dist/cjs/empty-state/style.scss +51 -0
- package/dist/cjs/empty-state/types.js +5 -0
- package/dist/cjs/index.js +34 -20
- package/dist/cjs/info-button/index.js +59 -43
- package/dist/cjs/info-button/index.test.js +199 -0
- package/dist/cjs/info-button/style.scss +41 -9
- package/dist/cjs/modal/style.scss +12 -12
- package/dist/cjs/newspack-icon/style.scss +4 -4
- package/dist/cjs/notice/style.scss +3 -3
- package/dist/cjs/page/style.scss +16 -16
- package/dist/cjs/plugin-installer/index.js +5 -9
- package/dist/cjs/plugin-installer/style.scss +3 -14
- package/dist/cjs/section-header/index.js +31 -18
- package/dist/cjs/section-header/index.test.js +40 -0
- package/dist/cjs/section-header/style.scss +22 -6
- package/dist/cjs/settings/DateRangeSetting.js +309 -0
- package/dist/cjs/settings/SettingsSection.js +19 -5
- package/dist/cjs/settings/SettingsSection.test.js +49 -0
- package/dist/cjs/settings/index.js +3 -1
- package/dist/cjs/settings/style.scss +40 -7
- package/dist/cjs/stat-card/body.js +41 -0
- package/dist/cjs/stat-card/constants.js +11 -0
- package/dist/cjs/stat-card/context.js +54 -0
- package/dist/cjs/stat-card/delta.js +91 -0
- package/dist/cjs/stat-card/footer.js +72 -0
- package/dist/cjs/stat-card/index.js +47 -0
- package/dist/cjs/stat-card/index.test.js +938 -0
- package/dist/cjs/stat-card/label.js +66 -0
- package/dist/cjs/stat-card/root.js +69 -0
- package/dist/cjs/stat-card/secondary.js +38 -0
- package/dist/cjs/stat-card/style.scss +89 -0
- package/dist/cjs/stat-card/types.js +5 -0
- package/dist/cjs/stat-card/value.js +78 -0
- package/dist/cjs/status-indicator/index.js +66 -0
- package/dist/cjs/status-indicator/index.test.js +101 -0
- package/dist/cjs/status-indicator/statuses.js +39 -0
- package/dist/cjs/status-indicator/style.scss +9 -0
- package/dist/cjs/status-indicator/types.js +5 -0
- package/dist/cjs/style.scss +9 -9
- package/dist/cjs/tabbed-navigation/style.scss +6 -4
- package/dist/cjs/types.js +5 -0
- package/dist/cjs/web-preview/style.scss +11 -11
- package/dist/cjs/with-wizard/style.scss +10 -10
- package/dist/cjs/with-wizard-screen/style.scss +9 -9
- package/dist/cjs/wizard/index.js +33 -4
- package/dist/cjs/wizard/store/index.js +23 -1
- package/dist/esm/_mixins.scss +13 -0
- package/dist/esm/_variables.scss +12 -0
- package/dist/esm/action-card/index.js +18 -10
- package/dist/esm/action-card/index.test.js +89 -0
- package/dist/esm/action-card/style.scss +2 -40
- package/dist/esm/button/index.js +9 -4
- package/dist/esm/button/index.test.js +63 -5
- package/dist/esm/card/core-card.js +0 -2
- package/dist/esm/card/style-core.scss +7 -5
- package/dist/esm/card-feature/index.js +78 -62
- package/dist/esm/card-feature/index.test.js +397 -55
- package/dist/esm/card-feature/style.scss +20 -31
- package/dist/esm/card-form/index.js +5 -5
- package/dist/esm/card-sortable-list/index.js +6 -4
- package/dist/esm/card-sortable-list/index.test.js +46 -0
- package/dist/esm/collapsible-group/context.js +13 -0
- package/dist/esm/collapsible-group/index.js +17 -0
- package/dist/esm/collapsible-group/index.test.js +215 -0
- package/dist/esm/collapsible-group/item.js +53 -0
- package/dist/esm/collapsible-group/root.js +54 -0
- package/dist/esm/collapsible-group/style.scss +47 -0
- package/dist/esm/collapsible-group/types.js +1 -0
- package/dist/esm/empty-state/actions.js +37 -0
- package/dist/esm/empty-state/context.js +35 -0
- package/dist/esm/empty-state/header.js +58 -0
- package/dist/esm/empty-state/index.js +23 -0
- package/dist/esm/empty-state/index.test.js +299 -0
- package/dist/esm/empty-state/root.js +56 -0
- package/dist/esm/empty-state/style.scss +51 -0
- package/dist/esm/empty-state/types.js +1 -0
- package/dist/esm/index.js +4 -2
- package/dist/esm/info-button/index.js +54 -43
- package/dist/esm/info-button/index.test.js +195 -0
- package/dist/esm/info-button/style.scss +41 -9
- package/dist/esm/modal/style.scss +12 -12
- package/dist/esm/newspack-icon/style.scss +4 -4
- package/dist/esm/notice/style.scss +3 -3
- package/dist/esm/page/style.scss +16 -16
- package/dist/esm/plugin-installer/index.js +5 -9
- package/dist/esm/plugin-installer/style.scss +3 -14
- package/dist/esm/section-header/index.js +27 -14
- package/dist/esm/section-header/index.test.js +36 -0
- package/dist/esm/section-header/style.scss +22 -6
- package/dist/esm/settings/DateRangeSetting.js +304 -0
- package/dist/esm/settings/SettingsSection.js +16 -3
- package/dist/esm/settings/SettingsSection.test.js +45 -0
- package/dist/esm/settings/index.js +3 -1
- package/dist/esm/settings/style.scss +40 -7
- package/dist/esm/stat-card/body.js +36 -0
- package/dist/esm/stat-card/constants.js +5 -0
- package/dist/esm/stat-card/context.js +48 -0
- package/dist/esm/stat-card/delta.js +86 -0
- package/dist/esm/stat-card/footer.js +67 -0
- package/dist/esm/stat-card/index.js +33 -0
- package/dist/esm/stat-card/index.test.js +939 -0
- package/dist/esm/stat-card/label.js +61 -0
- package/dist/esm/stat-card/root.js +64 -0
- package/dist/esm/stat-card/secondary.js +33 -0
- package/dist/esm/stat-card/style.scss +89 -0
- package/dist/esm/stat-card/types.js +1 -0
- package/dist/esm/stat-card/value.js +73 -0
- package/dist/esm/status-indicator/index.js +52 -0
- package/dist/esm/status-indicator/index.test.js +96 -0
- package/dist/esm/status-indicator/statuses.js +33 -0
- package/dist/esm/status-indicator/style.scss +9 -0
- package/dist/esm/status-indicator/types.js +1 -0
- package/dist/esm/style.scss +9 -9
- package/dist/esm/tabbed-navigation/style.scss +6 -4
- package/dist/esm/types.js +1 -0
- package/dist/esm/web-preview/style.scss +11 -11
- package/dist/esm/with-wizard/style.scss +10 -10
- package/dist/esm/with-wizard-screen/style.scss +9 -9
- package/dist/esm/wizard/index.js +38 -7
- package/dist/esm/wizard/store/index.js +23 -1
- package/package.json +1 -1
- package/src/_mixins.scss +13 -0
- package/src/_variables.scss +12 -0
- package/src/action-card/action-card.d.ts +3 -2
- package/src/action-card/index.js +12 -12
- package/src/action-card/index.test.js +56 -0
- package/src/action-card/style.scss +2 -40
- package/src/button/index.test.js +52 -5
- package/src/button/index.tsx +9 -4
- package/src/card/core-card.js +0 -2
- package/src/card/style-core.scss +7 -5
- package/src/card-feature/README.md +68 -27
- package/src/card-feature/index.test.js +242 -27
- package/src/card-feature/index.tsx +77 -67
- package/src/card-feature/style.scss +20 -31
- package/src/card-form/README.md +10 -10
- package/src/card-form/index.tsx +4 -8
- package/src/card-sortable-list/README.md +4 -5
- package/src/card-sortable-list/index.test.js +29 -0
- package/src/card-sortable-list/index.tsx +7 -4
- package/src/collapsible-group/README.md +50 -0
- package/src/collapsible-group/context.ts +13 -0
- package/src/collapsible-group/index.test.js +168 -0
- package/src/collapsible-group/index.tsx +17 -0
- package/src/collapsible-group/item.tsx +42 -0
- package/src/collapsible-group/root.tsx +42 -0
- package/src/collapsible-group/style.scss +47 -0
- package/src/collapsible-group/types.ts +22 -0
- package/src/drawer/README.md +2 -2
- package/src/empty-state/README.md +165 -0
- package/src/empty-state/actions.tsx +37 -0
- package/src/empty-state/context.ts +40 -0
- package/src/empty-state/header.tsx +48 -0
- package/src/empty-state/index.test.js +247 -0
- package/src/empty-state/index.tsx +22 -0
- package/src/empty-state/root.tsx +39 -0
- package/src/empty-state/style.scss +51 -0
- package/src/empty-state/types.ts +33 -0
- package/src/index.js +4 -2
- package/src/info-button/README.md +115 -0
- package/src/info-button/index.test.js +163 -0
- package/src/info-button/index.tsx +64 -0
- package/src/info-button/style.scss +41 -9
- package/src/modal/style.scss +12 -12
- package/src/newspack-icon/style.scss +4 -4
- package/src/notice/style.scss +3 -3
- package/src/page/style.scss +16 -16
- package/src/plugin-installer/index.js +3 -9
- package/src/plugin-installer/style.scss +3 -14
- package/src/section-header/index.js +27 -14
- package/src/section-header/index.test.js +28 -0
- package/src/section-header/style.scss +22 -6
- package/src/settings/DateRangeSetting.js +266 -0
- package/src/settings/SettingsSection.js +24 -4
- package/src/settings/SettingsSection.test.js +45 -0
- package/src/settings/index.js +2 -0
- package/src/settings/style.scss +40 -7
- package/src/stat-card/README.md +434 -0
- package/src/stat-card/body.tsx +28 -0
- package/src/stat-card/constants.ts +5 -0
- package/src/stat-card/context.ts +53 -0
- package/src/stat-card/delta.tsx +88 -0
- package/src/stat-card/footer.tsx +68 -0
- package/src/stat-card/index.test.js +818 -0
- package/src/stat-card/index.tsx +48 -0
- package/src/stat-card/label.tsx +61 -0
- package/src/stat-card/root.tsx +40 -0
- package/src/stat-card/secondary.tsx +27 -0
- package/src/stat-card/style.scss +89 -0
- package/src/stat-card/types.ts +84 -0
- package/src/stat-card/value.tsx +72 -0
- package/src/status-indicator/README.md +123 -0
- package/src/status-indicator/index.test.js +70 -0
- package/src/status-indicator/index.tsx +39 -0
- package/src/status-indicator/statuses.ts +35 -0
- package/src/status-indicator/style.scss +9 -0
- package/src/status-indicator/types.ts +28 -0
- package/src/style.scss +9 -9
- package/src/tabbed-navigation/style.scss +6 -4
- package/src/types.ts +25 -0
- package/src/web-preview/style.scss +11 -11
- package/src/with-wizard/style.scss +10 -10
- package/src/with-wizard-screen/style.scss +9 -9
- package/src/wizard/index.js +49 -7
- package/src/wizard/store/index.js +26 -1
- package/dist/cjs/accordion/index.js +0 -72
- package/dist/cjs/accordion/index.test.js +0 -80
- package/dist/cjs/accordion/style.scss +0 -35
- package/dist/cjs/badge/index.js +0 -32
- package/dist/cjs/badge/style.scss +0 -36
- package/dist/esm/accordion/index.js +0 -63
- package/dist/esm/accordion/index.test.js +0 -79
- package/dist/esm/accordion/style.scss +0 -35
- package/dist/esm/badge/index.js +0 -24
- package/dist/esm/badge/style.scss +0 -36
- package/src/accordion/index.js +0 -46
- package/src/accordion/index.test.js +0 -62
- package/src/accordion/style.scss +0 -35
- package/src/badge/index.tsx +0 -26
- package/src/badge/style.scss +0 -36
- package/src/info-button/index.js +0 -38
|
@@ -0,0 +1,938 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
5
|
+
var _react = require("@testing-library/react");
|
|
6
|
+
var _element = require("@wordpress/element");
|
|
7
|
+
var _ = _interopRequireWildcard(require("."));
|
|
8
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
9
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
10
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
11
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /**
|
|
12
|
+
* External dependencies
|
|
13
|
+
*/ /**
|
|
14
|
+
* WordPress dependencies
|
|
15
|
+
*/ /**
|
|
16
|
+
* Internal dependencies
|
|
17
|
+
*/
|
|
18
|
+
var renderOrphan = function renderOrphan(node) {
|
|
19
|
+
var consoleError = jest.spyOn(console, 'error').mockImplementation(function () {});
|
|
20
|
+
try {
|
|
21
|
+
expect(function () {
|
|
22
|
+
return (0, _react.render)(node);
|
|
23
|
+
}).toThrow('StatCard subcomponents must be rendered inside StatCard.Root.');
|
|
24
|
+
} finally {
|
|
25
|
+
consoleError.mockRestore();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
describe('StatCard.Root', function () {
|
|
29
|
+
// The hero scale is a container query against this class, so losing it
|
|
30
|
+
// silently resizes the figure.
|
|
31
|
+
it('carries the class the container query is scoped to', function () {
|
|
32
|
+
var _render = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
33
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
|
|
34
|
+
children: "body"
|
|
35
|
+
})
|
|
36
|
+
})),
|
|
37
|
+
container = _render.container;
|
|
38
|
+
expect(container.querySelector('.newspack-stat-card')).toBeInTheDocument();
|
|
39
|
+
expect(container.querySelector('.newspack-stat-card__content')).toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// The footer only pins to the bottom while the content region is a column.
|
|
43
|
+
it('lays the content region out as a column', function () {
|
|
44
|
+
var _render2 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
45
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
|
|
46
|
+
children: "body"
|
|
47
|
+
})
|
|
48
|
+
})),
|
|
49
|
+
container = _render2.container;
|
|
50
|
+
expect(container.querySelector('.newspack-stat-card__content')).toHaveStyle({
|
|
51
|
+
flexDirection: 'column'
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
it('merges className onto the card', function () {
|
|
55
|
+
var _render3 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
56
|
+
className: "consumer-tile",
|
|
57
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
|
|
58
|
+
children: "body"
|
|
59
|
+
})
|
|
60
|
+
})),
|
|
61
|
+
container = _render3.container;
|
|
62
|
+
expect(container.querySelector('.newspack-stat-card')).toHaveClass('consumer-tile');
|
|
63
|
+
});
|
|
64
|
+
it('renders its children', function () {
|
|
65
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
66
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
|
|
67
|
+
children: "body"
|
|
68
|
+
})
|
|
69
|
+
}));
|
|
70
|
+
expect(_react.screen.getByText('body')).toBeInTheDocument();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// A wrapper in another repo needs the node to anchor a popover or measure the tile.
|
|
74
|
+
it('forwards a ref and passes other props to the card', function () {
|
|
75
|
+
var ref = {
|
|
76
|
+
current: null
|
|
77
|
+
};
|
|
78
|
+
var _render4 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
79
|
+
ref: ref,
|
|
80
|
+
id: "tile-1",
|
|
81
|
+
"data-testid": "tile",
|
|
82
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
|
|
83
|
+
children: "body"
|
|
84
|
+
})
|
|
85
|
+
})),
|
|
86
|
+
container = _render4.container;
|
|
87
|
+
var card = container.querySelector('.newspack-stat-card');
|
|
88
|
+
expect(ref.current).toBe(card);
|
|
89
|
+
expect(card).toHaveAttribute('id', 'tile-1');
|
|
90
|
+
expect(card).toHaveAttribute('data-testid', 'tile');
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
describe('StatCard.Label', function () {
|
|
94
|
+
it('renders an h3 by default', function () {
|
|
95
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
96
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Label, {
|
|
97
|
+
children: "Subscribers reached"
|
|
98
|
+
})
|
|
99
|
+
}));
|
|
100
|
+
expect(_react.screen.getByRole('heading', {
|
|
101
|
+
level: 3,
|
|
102
|
+
name: 'Subscribers reached'
|
|
103
|
+
})).toBeInTheDocument();
|
|
104
|
+
});
|
|
105
|
+
it('follows the level set on Root', function () {
|
|
106
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
107
|
+
heading: 4,
|
|
108
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Label, {
|
|
109
|
+
children: "Subscribers reached"
|
|
110
|
+
})
|
|
111
|
+
}));
|
|
112
|
+
expect(_react.screen.getByRole('heading', {
|
|
113
|
+
level: 4,
|
|
114
|
+
name: 'Subscribers reached'
|
|
115
|
+
})).toBeInTheDocument();
|
|
116
|
+
});
|
|
117
|
+
it('lets its own heading override Root', function () {
|
|
118
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
119
|
+
heading: 4,
|
|
120
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Label, {
|
|
121
|
+
heading: 2,
|
|
122
|
+
children: "Subscribers reached"
|
|
123
|
+
})
|
|
124
|
+
}));
|
|
125
|
+
expect(_react.screen.getByRole('heading', {
|
|
126
|
+
level: 2,
|
|
127
|
+
name: 'Subscribers reached'
|
|
128
|
+
})).toBeInTheDocument();
|
|
129
|
+
});
|
|
130
|
+
it('falls back to h3 for a level outside 2-6', function () {
|
|
131
|
+
var consoleWarn = jest.spyOn(console, 'warn').mockImplementation(function () {});
|
|
132
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
133
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Label, {
|
|
134
|
+
heading: 7,
|
|
135
|
+
children: "Subscribers reached"
|
|
136
|
+
})
|
|
137
|
+
}));
|
|
138
|
+
expect(_react.screen.getByRole('heading', {
|
|
139
|
+
level: 3,
|
|
140
|
+
name: 'Subscribers reached'
|
|
141
|
+
})).toBeInTheDocument();
|
|
142
|
+
expect(consoleWarn).toHaveBeenCalled();
|
|
143
|
+
consoleWarn.mockRestore();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Inside the heading, the control's text would join its accessible name.
|
|
147
|
+
it('renders the suffix beside the heading rather than inside it', function () {
|
|
148
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
149
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Label, {
|
|
150
|
+
suffix: /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
|
|
151
|
+
type: "button",
|
|
152
|
+
children: "About this metric"
|
|
153
|
+
}),
|
|
154
|
+
children: "Subscribers reached"
|
|
155
|
+
})
|
|
156
|
+
}));
|
|
157
|
+
var heading = _react.screen.getByRole('heading', {
|
|
158
|
+
level: 3,
|
|
159
|
+
name: 'Subscribers reached'
|
|
160
|
+
});
|
|
161
|
+
expect(heading).not.toContainElement(_react.screen.getByRole('button', {
|
|
162
|
+
name: 'About this metric'
|
|
163
|
+
}));
|
|
164
|
+
});
|
|
165
|
+
it('merges className onto the row, not the heading', function () {
|
|
166
|
+
var _render5 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
167
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Label, {
|
|
168
|
+
className: "consumer-label",
|
|
169
|
+
children: "Subscribers reached"
|
|
170
|
+
})
|
|
171
|
+
})),
|
|
172
|
+
container = _render5.container;
|
|
173
|
+
expect(container.querySelector('.newspack-stat-card__label')).toHaveClass('consumer-label');
|
|
174
|
+
expect(_react.screen.getByRole('heading', {
|
|
175
|
+
level: 3
|
|
176
|
+
})).not.toHaveClass('consumer-label');
|
|
177
|
+
});
|
|
178
|
+
it('throws outside Root', function () {
|
|
179
|
+
renderOrphan(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Label, {
|
|
180
|
+
children: "Orphan"
|
|
181
|
+
}));
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
describe('StatCard.Body', function () {
|
|
185
|
+
it('renders its children', function () {
|
|
186
|
+
var _render6 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
187
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Body, {
|
|
188
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
|
|
189
|
+
children: "body"
|
|
190
|
+
})
|
|
191
|
+
})
|
|
192
|
+
})),
|
|
193
|
+
container = _render6.container;
|
|
194
|
+
expect(container.querySelector('.newspack-stat-card__body')).toBeInTheDocument();
|
|
195
|
+
expect(_react.screen.getByText('body')).toBeInTheDocument();
|
|
196
|
+
});
|
|
197
|
+
it('merges className onto the body', function () {
|
|
198
|
+
var _render7 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
199
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Body, {
|
|
200
|
+
className: "consumer-body",
|
|
201
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
|
|
202
|
+
children: "body"
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
})),
|
|
206
|
+
container = _render7.container;
|
|
207
|
+
expect(container.querySelector('.newspack-stat-card__body')).toHaveClass('consumer-body');
|
|
208
|
+
});
|
|
209
|
+
it('throws outside Root', function () {
|
|
210
|
+
renderOrphan(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Body, {
|
|
211
|
+
children: "Orphan"
|
|
212
|
+
}));
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
describe('StatCard.Value', function () {
|
|
216
|
+
it('renders a formatted value as-is, with nothing spoken over it', function () {
|
|
217
|
+
var _render8 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
218
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
219
|
+
value: "1,284"
|
|
220
|
+
})
|
|
221
|
+
})),
|
|
222
|
+
container = _render8.container;
|
|
223
|
+
expect(_react.screen.getByText('1,284')).toBeInTheDocument();
|
|
224
|
+
expect(container.querySelector('[data-visually-hidden]')).not.toBeInTheDocument();
|
|
225
|
+
expect(container.querySelector('[aria-hidden="true"]')).not.toBeInTheDocument();
|
|
226
|
+
});
|
|
227
|
+
it('merges className onto the value', function () {
|
|
228
|
+
var _render9 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
229
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
230
|
+
value: "1,284",
|
|
231
|
+
className: "consumer-value"
|
|
232
|
+
})
|
|
233
|
+
})),
|
|
234
|
+
container = _render9.container;
|
|
235
|
+
expect(container.querySelector('.newspack-stat-card__value')).toHaveClass('consumer-value');
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// The glyph exists to tell a missing figure from a zero, so a zero has to survive it.
|
|
239
|
+
it('renders a zero as the figure it is', function () {
|
|
240
|
+
var _render0 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
241
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
242
|
+
value: 0
|
|
243
|
+
})
|
|
244
|
+
})),
|
|
245
|
+
container = _render0.container;
|
|
246
|
+
expect(_react.screen.getByText('0')).toBeInTheDocument();
|
|
247
|
+
expect(_react.screen.queryByText(_.STAT_CARD_NULL_GLYPH)).not.toBeInTheDocument();
|
|
248
|
+
expect(container.querySelector('[data-visually-hidden]')).not.toBeInTheDocument();
|
|
249
|
+
});
|
|
250
|
+
it('renders the null glyph with an accessible name for a null value', function () {
|
|
251
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
252
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
253
|
+
value: null
|
|
254
|
+
})
|
|
255
|
+
}));
|
|
256
|
+
expect(_react.screen.getByText(_.STAT_CARD_NULL_GLYPH)).toHaveAttribute('aria-hidden', 'true');
|
|
257
|
+
expect(_react.screen.getByText('Not applicable')).toHaveAttribute('data-visually-hidden');
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// `value={ data?.count }` before the data arrives must not read as a zero.
|
|
261
|
+
it('treats undefined as no figure', function () {
|
|
262
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
263
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
264
|
+
value: undefined
|
|
265
|
+
})
|
|
266
|
+
}));
|
|
267
|
+
expect(_react.screen.getByText(_.STAT_CARD_NULL_GLYPH)).toHaveAttribute('aria-hidden', 'true');
|
|
268
|
+
expect(_react.screen.getByText('Not applicable')).toHaveAttribute('data-visually-hidden');
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// A field that reports "no data" as an empty string would otherwise leave a blank hero.
|
|
272
|
+
it('treats an empty value as no figure', function () {
|
|
273
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
274
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
275
|
+
value: ""
|
|
276
|
+
})
|
|
277
|
+
}));
|
|
278
|
+
expect(_react.screen.getByText(_.STAT_CARD_NULL_GLYPH)).toHaveAttribute('aria-hidden', 'true');
|
|
279
|
+
expect(_react.screen.getByText('Not applicable')).toHaveAttribute('data-visually-hidden');
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// A no-data sentinel padded by the field it came from is still no data.
|
|
283
|
+
it('treats a whitespace-only value as no figure', function () {
|
|
284
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
285
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
286
|
+
value: " "
|
|
287
|
+
})
|
|
288
|
+
}));
|
|
289
|
+
expect(_react.screen.getByText(_.STAT_CARD_NULL_GLYPH)).toHaveAttribute('aria-hidden', 'true');
|
|
290
|
+
expect(_react.screen.getByText('Not applicable')).toHaveAttribute('data-visually-hidden');
|
|
291
|
+
});
|
|
292
|
+
it('does not expose the glyph as an image', function () {
|
|
293
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
294
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
295
|
+
value: null
|
|
296
|
+
})
|
|
297
|
+
}));
|
|
298
|
+
expect(_react.screen.queryByRole('img')).not.toBeInTheDocument();
|
|
299
|
+
});
|
|
300
|
+
it('speaks valueLabel instead of the visible value', function () {
|
|
301
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
302
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
303
|
+
value: "$1.2M",
|
|
304
|
+
valueLabel: "1.2 million dollars"
|
|
305
|
+
})
|
|
306
|
+
}));
|
|
307
|
+
expect(_react.screen.getByText('$1.2M')).toHaveAttribute('aria-hidden', 'true');
|
|
308
|
+
expect(_react.screen.getByText('1.2 million dollars')).toHaveAttribute('data-visually-hidden');
|
|
309
|
+
});
|
|
310
|
+
it('lets valueLabel replace the default name of the null glyph', function () {
|
|
311
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
312
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
313
|
+
value: null,
|
|
314
|
+
valueLabel: "No conversions in this timeframe"
|
|
315
|
+
})
|
|
316
|
+
}));
|
|
317
|
+
expect(_react.screen.getByText('No conversions in this timeframe')).toHaveAttribute('data-visually-hidden');
|
|
318
|
+
expect(_react.screen.queryByText('Not applicable')).not.toBeInTheDocument();
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// A label mapped from an empty field must not leave the glyph unnamed.
|
|
322
|
+
it('falls back to the default name when valueLabel is empty', function () {
|
|
323
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
324
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
325
|
+
value: null,
|
|
326
|
+
valueLabel: ""
|
|
327
|
+
})
|
|
328
|
+
}));
|
|
329
|
+
expect(_react.screen.getByText(_.STAT_CARD_NULL_GLYPH)).toHaveAttribute('aria-hidden', 'true');
|
|
330
|
+
expect(_react.screen.getByText('Not applicable')).toHaveAttribute('data-visually-hidden');
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Whitespace is truthy, so an unguarded label would hide the figure and name it nothing.
|
|
334
|
+
it('falls back to the default name when valueLabel is only whitespace', function () {
|
|
335
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
336
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
337
|
+
value: null,
|
|
338
|
+
valueLabel: " "
|
|
339
|
+
})
|
|
340
|
+
}));
|
|
341
|
+
expect(_react.screen.getByText(_.STAT_CARD_NULL_GLYPH)).toHaveAttribute('aria-hidden', 'true');
|
|
342
|
+
expect(_react.screen.getByText('Not applicable')).toHaveAttribute('data-visually-hidden');
|
|
343
|
+
});
|
|
344
|
+
it('drops the hero scale for a text variant', function () {
|
|
345
|
+
var _render1 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
346
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
347
|
+
value: "0 of 17",
|
|
348
|
+
variant: "text"
|
|
349
|
+
})
|
|
350
|
+
})),
|
|
351
|
+
container = _render1.container;
|
|
352
|
+
expect(container.querySelector('.newspack-stat-card__value')).toHaveClass('newspack-stat-card__value--text');
|
|
353
|
+
});
|
|
354
|
+
it('keeps the null treatment in the text variant', function () {
|
|
355
|
+
var _render10 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
356
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
357
|
+
value: null,
|
|
358
|
+
variant: "text"
|
|
359
|
+
})
|
|
360
|
+
})),
|
|
361
|
+
container = _render10.container;
|
|
362
|
+
expect(container.querySelector('.newspack-stat-card__value')).toHaveClass('newspack-stat-card__value--text');
|
|
363
|
+
expect(_react.screen.getByText(_.STAT_CARD_NULL_GLYPH)).toHaveAttribute('aria-hidden', 'true');
|
|
364
|
+
expect(_react.screen.getByText('Not applicable')).toHaveAttribute('data-visually-hidden');
|
|
365
|
+
});
|
|
366
|
+
it('warns on an unknown variant and keeps the hero scale', function () {
|
|
367
|
+
var consoleWarn = jest.spyOn(console, 'warn').mockImplementation(function () {});
|
|
368
|
+
var _render11 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
369
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
370
|
+
value: "1,284",
|
|
371
|
+
variant: "headline"
|
|
372
|
+
})
|
|
373
|
+
})),
|
|
374
|
+
container = _render11.container;
|
|
375
|
+
expect(container.querySelector('.newspack-stat-card__value')).not.toHaveClass('newspack-stat-card__value--text');
|
|
376
|
+
expect(consoleWarn).toHaveBeenCalled();
|
|
377
|
+
consoleWarn.mockRestore();
|
|
378
|
+
});
|
|
379
|
+
it('keeps the hero scale by default', function () {
|
|
380
|
+
var _render12 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
381
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
382
|
+
value: "1,284"
|
|
383
|
+
})
|
|
384
|
+
})),
|
|
385
|
+
container = _render12.container;
|
|
386
|
+
expect(container.querySelector('.newspack-stat-card__value')).not.toHaveClass('newspack-stat-card__value--text');
|
|
387
|
+
});
|
|
388
|
+
it('throws outside Root', function () {
|
|
389
|
+
renderOrphan(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
390
|
+
value: "1,284"
|
|
391
|
+
}));
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
describe('StatCard.Delta', function () {
|
|
395
|
+
it('renders the change with the arrow named in text', function () {
|
|
396
|
+
var _render13 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
397
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
398
|
+
direction: "up",
|
|
399
|
+
children: "2%"
|
|
400
|
+
})
|
|
401
|
+
})),
|
|
402
|
+
container = _render13.container;
|
|
403
|
+
expect(container.querySelector('[aria-hidden="true"]')).toHaveTextContent('↑');
|
|
404
|
+
expect(_react.screen.getByText('Up')).toHaveAttribute('data-visually-hidden');
|
|
405
|
+
expect(_react.screen.getByText('2%')).toBeInTheDocument();
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// Hiding the span forms a box that speech linearises; braille and raw text get no such boundary.
|
|
409
|
+
it('separates the spoken direction from the change in the raw text', function () {
|
|
410
|
+
var _render14 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
411
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
412
|
+
direction: "up",
|
|
413
|
+
children: "2%"
|
|
414
|
+
})
|
|
415
|
+
})),
|
|
416
|
+
container = _render14.container;
|
|
417
|
+
expect(container.querySelector('[data-visually-hidden]').textContent).toBe('Up ');
|
|
418
|
+
expect(container.querySelector('.newspack-stat-card__delta').textContent).toBe('↑Up 2%');
|
|
419
|
+
});
|
|
420
|
+
it('points the arrow down without changing the colour', function () {
|
|
421
|
+
var _render15 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
422
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
423
|
+
direction: "down",
|
|
424
|
+
children: "2%"
|
|
425
|
+
})
|
|
426
|
+
})),
|
|
427
|
+
container = _render15.container;
|
|
428
|
+
expect(container.querySelector('[aria-hidden="true"]')).toHaveTextContent('↓');
|
|
429
|
+
expect(_react.screen.getByText('Down')).toHaveAttribute('data-visually-hidden');
|
|
430
|
+
var delta = container.querySelector('.newspack-stat-card__delta');
|
|
431
|
+
expect(delta).not.toHaveClass('newspack-stat-card__delta--negative');
|
|
432
|
+
expect(delta).not.toHaveClass('newspack-stat-card__delta--positive');
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
// A rise is not always good news, so the caller sets the tone separately.
|
|
436
|
+
it('takes its tone from the caller, not from the direction', function () {
|
|
437
|
+
var _render16 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
438
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
439
|
+
direction: "up",
|
|
440
|
+
tone: "negative",
|
|
441
|
+
children: "2%"
|
|
442
|
+
})
|
|
443
|
+
})),
|
|
444
|
+
container = _render16.container;
|
|
445
|
+
expect(container.querySelector('.newspack-stat-card__delta')).toHaveClass('newspack-stat-card__delta--negative');
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Three sources compose here: the base class, the tone modifier and the consumer's.
|
|
449
|
+
it('merges className onto the delta alongside the tone', function () {
|
|
450
|
+
var _render17 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
451
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
452
|
+
direction: "down",
|
|
453
|
+
tone: "negative",
|
|
454
|
+
className: "custom-delta",
|
|
455
|
+
children: "2%"
|
|
456
|
+
})
|
|
457
|
+
})),
|
|
458
|
+
container = _render17.container;
|
|
459
|
+
var delta = container.querySelector('.newspack-stat-card__delta');
|
|
460
|
+
expect(delta).toHaveClass('newspack-stat-card__delta--negative');
|
|
461
|
+
expect(delta).toHaveClass('custom-delta');
|
|
462
|
+
});
|
|
463
|
+
it('lets directionLabel replace the spoken direction', function () {
|
|
464
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
465
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
466
|
+
direction: "up",
|
|
467
|
+
directionLabel: "Increased by",
|
|
468
|
+
children: "2%"
|
|
469
|
+
})
|
|
470
|
+
}));
|
|
471
|
+
expect(_react.screen.getByText('Increased by')).toHaveAttribute('data-visually-hidden');
|
|
472
|
+
expect(_react.screen.queryByText('Up')).not.toBeInTheDocument();
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
// No arrow and the word "Down" would be worse than saying nothing at all.
|
|
476
|
+
it('leaves an unrecognised direction unspoken', function () {
|
|
477
|
+
var consoleWarn = jest.spyOn(console, 'warn').mockImplementation(function () {});
|
|
478
|
+
var _render18 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
479
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
480
|
+
direction: "sideways",
|
|
481
|
+
children: "2%"
|
|
482
|
+
})
|
|
483
|
+
})),
|
|
484
|
+
container = _render18.container;
|
|
485
|
+
expect(container.querySelector('[aria-hidden="true"]')).not.toBeInTheDocument();
|
|
486
|
+
expect(container.querySelector('[data-visually-hidden]')).not.toBeInTheDocument();
|
|
487
|
+
expect(_react.screen.getByText('2%')).toBeInTheDocument();
|
|
488
|
+
expect(consoleWarn).toHaveBeenCalled();
|
|
489
|
+
consoleWarn.mockRestore();
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
// A label mapped from an empty field must not leave the arrow unnamed.
|
|
493
|
+
// The caller chose the words, so a missing arrow must not silence them.
|
|
494
|
+
it('speaks a directionLabel where there is no arrow to name', function () {
|
|
495
|
+
var consoleWarn = jest.spyOn(console, 'warn').mockImplementation(function () {});
|
|
496
|
+
var _render19 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
497
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
498
|
+
direction: "sideways",
|
|
499
|
+
directionLabel: "Increased by",
|
|
500
|
+
children: "2%"
|
|
501
|
+
})
|
|
502
|
+
})),
|
|
503
|
+
container = _render19.container;
|
|
504
|
+
expect(container.querySelector('[aria-hidden="true"]')).not.toBeInTheDocument();
|
|
505
|
+
expect(_react.screen.getByText('Increased by')).toHaveAttribute('data-visually-hidden');
|
|
506
|
+
consoleWarn.mockRestore();
|
|
507
|
+
});
|
|
508
|
+
it('falls back to the spoken direction when directionLabel is empty', function () {
|
|
509
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
510
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
511
|
+
direction: "up",
|
|
512
|
+
directionLabel: "",
|
|
513
|
+
children: "2%"
|
|
514
|
+
})
|
|
515
|
+
}));
|
|
516
|
+
expect(_react.screen.getByText('Up')).toHaveAttribute('data-visually-hidden');
|
|
517
|
+
});
|
|
518
|
+
it('falls back to the spoken direction when directionLabel is only whitespace', function () {
|
|
519
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
520
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
521
|
+
direction: "up",
|
|
522
|
+
directionLabel: " ",
|
|
523
|
+
children: "2%"
|
|
524
|
+
})
|
|
525
|
+
}));
|
|
526
|
+
expect(_react.screen.getByText('Up')).toHaveAttribute('data-visually-hidden');
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
// Word order and valence both live in the caller's sentence, not in DOM order.
|
|
530
|
+
it('lets label name the whole delta and hides what it restates', function () {
|
|
531
|
+
var _render20 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
532
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
533
|
+
direction: "up",
|
|
534
|
+
tone: "negative",
|
|
535
|
+
label: "2% more refunds than last month",
|
|
536
|
+
children: "2%"
|
|
537
|
+
})
|
|
538
|
+
})),
|
|
539
|
+
container = _render20.container;
|
|
540
|
+
expect(container.querySelector('[aria-hidden="true"]')).toHaveTextContent('↑2%');
|
|
541
|
+
expect(_react.screen.getByText('2% more refunds than last month')).toHaveAttribute('data-visually-hidden');
|
|
542
|
+
expect(_react.screen.queryByText('Up')).not.toBeInTheDocument();
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
// The whole-delta sentence outranks the one-word swap, which only prose said until now.
|
|
546
|
+
it('lets label win over directionLabel', function () {
|
|
547
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
548
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
549
|
+
direction: "up",
|
|
550
|
+
label: "2% more refunds than last month",
|
|
551
|
+
directionLabel: "Increased by",
|
|
552
|
+
children: "2%"
|
|
553
|
+
})
|
|
554
|
+
}));
|
|
555
|
+
expect(_react.screen.getByText('2% more refunds than last month')).toHaveAttribute('data-visually-hidden');
|
|
556
|
+
expect(_react.screen.queryByText('Increased by')).not.toBeInTheDocument();
|
|
557
|
+
expect(_react.screen.queryByText('Up')).not.toBeInTheDocument();
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
// Falling back past a blank label should land on the caller's word, not the built-in one.
|
|
561
|
+
it('falls back from a blank label to directionLabel rather than the default', function () {
|
|
562
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
563
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
564
|
+
direction: "up",
|
|
565
|
+
label: " ",
|
|
566
|
+
directionLabel: "Increased by",
|
|
567
|
+
children: "2%"
|
|
568
|
+
})
|
|
569
|
+
}));
|
|
570
|
+
expect(_react.screen.getByText('Increased by')).toHaveAttribute('data-visually-hidden');
|
|
571
|
+
expect(_react.screen.queryByText('Up')).not.toBeInTheDocument();
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
// A blank sentence would hide the arrow and the change behind nothing at all.
|
|
575
|
+
it('keeps the arrow and the change when label is only whitespace', function () {
|
|
576
|
+
var _render21 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
577
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
578
|
+
direction: "up",
|
|
579
|
+
label: " ",
|
|
580
|
+
children: "2%"
|
|
581
|
+
})
|
|
582
|
+
})),
|
|
583
|
+
container = _render21.container;
|
|
584
|
+
expect(container.querySelector('[aria-hidden="true"]')).toHaveTextContent('↑');
|
|
585
|
+
expect(_react.screen.getByText('Up')).toHaveAttribute('data-visually-hidden');
|
|
586
|
+
expect(_react.screen.getByText('2%')).toBeInTheDocument();
|
|
587
|
+
});
|
|
588
|
+
it('sits in a row beside the figure when passed as a Value suffix', function () {
|
|
589
|
+
var _render22 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
590
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
591
|
+
value: "1,284",
|
|
592
|
+
suffix: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
593
|
+
direction: "up",
|
|
594
|
+
tone: "positive",
|
|
595
|
+
children: "2%"
|
|
596
|
+
})
|
|
597
|
+
})
|
|
598
|
+
})),
|
|
599
|
+
container = _render22.container;
|
|
600
|
+
var figure = container.querySelector('.newspack-stat-card__figure');
|
|
601
|
+
expect(figure).toHaveStyle({
|
|
602
|
+
flexDirection: 'row'
|
|
603
|
+
});
|
|
604
|
+
expect(figure.querySelector('.newspack-stat-card__value')).toBeInTheDocument();
|
|
605
|
+
expect(figure.querySelector('.newspack-stat-card__delta')).toBeInTheDocument();
|
|
606
|
+
});
|
|
607
|
+
it('adds no row when the value has no suffix', function () {
|
|
608
|
+
var _render23 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
609
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
610
|
+
value: "1,284"
|
|
611
|
+
})
|
|
612
|
+
})),
|
|
613
|
+
container = _render23.container;
|
|
614
|
+
expect(container.querySelector('.newspack-stat-card__figure')).not.toBeInTheDocument();
|
|
615
|
+
});
|
|
616
|
+
it('throws outside Root', function () {
|
|
617
|
+
renderOrphan(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
618
|
+
direction: "up",
|
|
619
|
+
children: "2%"
|
|
620
|
+
}));
|
|
621
|
+
});
|
|
622
|
+
});
|
|
623
|
+
describe('StatCard.Secondary', function () {
|
|
624
|
+
it('renders its children', function () {
|
|
625
|
+
var _render24 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
626
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Secondary, {
|
|
627
|
+
children: "Up from 1,190 last month"
|
|
628
|
+
})
|
|
629
|
+
})),
|
|
630
|
+
container = _render24.container;
|
|
631
|
+
expect(container.querySelector('.newspack-stat-card__secondary')).toBeInTheDocument();
|
|
632
|
+
expect(_react.screen.getByText('Up from 1,190 last month')).toBeInTheDocument();
|
|
633
|
+
});
|
|
634
|
+
it('merges className onto the line', function () {
|
|
635
|
+
var _render25 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
636
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Secondary, {
|
|
637
|
+
className: "consumer-secondary",
|
|
638
|
+
children: "Up from 1,190 last month"
|
|
639
|
+
})
|
|
640
|
+
})),
|
|
641
|
+
container = _render25.container;
|
|
642
|
+
expect(container.querySelector('.newspack-stat-card__secondary')).toHaveClass('consumer-secondary');
|
|
643
|
+
});
|
|
644
|
+
it('throws outside Root', function () {
|
|
645
|
+
renderOrphan(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Secondary, {
|
|
646
|
+
children: "Orphan"
|
|
647
|
+
}));
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
describe('StatCard.Footer', function () {
|
|
651
|
+
it('wraps a bare description in the description styling', function () {
|
|
652
|
+
var _render26 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
653
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Footer, {
|
|
654
|
+
children: "Readers who received at least one campaign."
|
|
655
|
+
})
|
|
656
|
+
})),
|
|
657
|
+
container = _render26.container;
|
|
658
|
+
var description = container.querySelector('.newspack-stat-card__description');
|
|
659
|
+
expect(description.tagName).toBe('P');
|
|
660
|
+
expect(description).toHaveTextContent('Readers who received at least one campaign.');
|
|
661
|
+
});
|
|
662
|
+
it('merges className onto the footer', function () {
|
|
663
|
+
var _render27 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
664
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Footer, {
|
|
665
|
+
className: "consumer-footer",
|
|
666
|
+
children: "Readers who received at least one campaign."
|
|
667
|
+
})
|
|
668
|
+
})),
|
|
669
|
+
container = _render27.container;
|
|
670
|
+
expect(container.querySelector('.newspack-stat-card__footer')).toHaveClass('consumer-footer');
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
// An interpolated sentence arrives as several children and has to stay one sentence.
|
|
674
|
+
it('keeps a run of text children in one paragraph', function () {
|
|
675
|
+
var count = 12;
|
|
676
|
+
var _render28 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
677
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_["default"].Footer, {
|
|
678
|
+
children: ["Applies to ", count, " products."]
|
|
679
|
+
})
|
|
680
|
+
})),
|
|
681
|
+
container = _render28.container;
|
|
682
|
+
var descriptions = container.querySelectorAll('.newspack-stat-card__description');
|
|
683
|
+
expect(descriptions).toHaveLength(1);
|
|
684
|
+
expect(descriptions[0]).toHaveTextContent('Applies to 12 products.');
|
|
685
|
+
});
|
|
686
|
+
it('passes elements through untouched', function () {
|
|
687
|
+
var _render29 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
688
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Footer, {
|
|
689
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
|
|
690
|
+
type: "button",
|
|
691
|
+
children: "See the products"
|
|
692
|
+
})
|
|
693
|
+
})
|
|
694
|
+
})),
|
|
695
|
+
container = _render29.container;
|
|
696
|
+
expect(container.querySelector('.newspack-stat-card__description')).not.toBeInTheDocument();
|
|
697
|
+
expect(_react.screen.getByRole('button', {
|
|
698
|
+
name: 'See the products'
|
|
699
|
+
})).toBeInTheDocument();
|
|
700
|
+
});
|
|
701
|
+
it('wraps only the text when an action sits beside it', function () {
|
|
702
|
+
var _render30 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
703
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_["default"].Footer, {
|
|
704
|
+
children: ['Products this rule applies to.', /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
|
|
705
|
+
type: "button",
|
|
706
|
+
children: "See the products"
|
|
707
|
+
})]
|
|
708
|
+
})
|
|
709
|
+
})),
|
|
710
|
+
container = _render30.container;
|
|
711
|
+
expect(container.querySelectorAll('.newspack-stat-card__description')).toHaveLength(1);
|
|
712
|
+
expect(_react.screen.getByText('Products this rule applies to.')).toHaveClass('newspack-stat-card__description');
|
|
713
|
+
expect(_react.screen.getByRole('button', {
|
|
714
|
+
name: 'See the products'
|
|
715
|
+
})).toBeInTheDocument();
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// An empty or whitespace-only child would otherwise leave a stray paragraph.
|
|
719
|
+
it('renders nothing for an empty description', function () {
|
|
720
|
+
var _render31 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
721
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Footer, {
|
|
722
|
+
children: ''
|
|
723
|
+
})
|
|
724
|
+
})),
|
|
725
|
+
container = _render31.container;
|
|
726
|
+
expect(container.querySelector('.newspack-stat-card__description')).not.toBeInTheDocument();
|
|
727
|
+
});
|
|
728
|
+
it('renders nothing for a whitespace-only description', function () {
|
|
729
|
+
var _render32 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
730
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Footer, {
|
|
731
|
+
children: ' '
|
|
732
|
+
})
|
|
733
|
+
})),
|
|
734
|
+
container = _render32.container;
|
|
735
|
+
expect(container.querySelector('.newspack-stat-card__description')).not.toBeInTheDocument();
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
// `createInterpolateElement` returns a Fragment, which has to stay part of the run.
|
|
739
|
+
it('keeps an interpolated sentence in the description styling', function () {
|
|
740
|
+
var _render33 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
741
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Footer, {
|
|
742
|
+
children: (0, _element.createInterpolateElement)('Applies to <b>12</b> products.', {
|
|
743
|
+
b: /*#__PURE__*/(0, _jsxRuntime.jsx)("strong", {})
|
|
744
|
+
})
|
|
745
|
+
})
|
|
746
|
+
})),
|
|
747
|
+
container = _render33.container;
|
|
748
|
+
var descriptions = container.querySelectorAll('.newspack-stat-card__description');
|
|
749
|
+
expect(descriptions).toHaveLength(1);
|
|
750
|
+
expect(descriptions[0]).toHaveTextContent('Applies to 12 products.');
|
|
751
|
+
expect(descriptions[0].querySelector('strong')).toBeInTheDocument();
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
// The documented escape hatch: inline markup would otherwise split into a block per child.
|
|
755
|
+
it('passes a self-wrapped description through as one paragraph', function () {
|
|
756
|
+
var _render34 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
757
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Footer, {
|
|
758
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("p", {
|
|
759
|
+
className: "newspack-stat-card__description",
|
|
760
|
+
children: ["Applies to ", /*#__PURE__*/(0, _jsxRuntime.jsx)("strong", {
|
|
761
|
+
children: "12"
|
|
762
|
+
}), " products."]
|
|
763
|
+
})
|
|
764
|
+
})
|
|
765
|
+
})),
|
|
766
|
+
container = _render34.container;
|
|
767
|
+
var descriptions = container.querySelectorAll('.newspack-stat-card__description');
|
|
768
|
+
expect(descriptions).toHaveLength(1);
|
|
769
|
+
expect(descriptions[0]).toHaveTextContent('Applies to 12 products.');
|
|
770
|
+
});
|
|
771
|
+
it('throws outside Root', function () {
|
|
772
|
+
renderOrphan(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Footer, {
|
|
773
|
+
children: "Orphan"
|
|
774
|
+
}));
|
|
775
|
+
});
|
|
776
|
+
});
|
|
777
|
+
describe('StatCard leaf slots', function () {
|
|
778
|
+
var leaves = [['Label', function (props) {
|
|
779
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Label, _objectSpread(_objectSpread({}, props), {}, {
|
|
780
|
+
children: "Reach"
|
|
781
|
+
}));
|
|
782
|
+
}, '.newspack-stat-card__label'], ['Body', function (props) {
|
|
783
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Body, _objectSpread({}, props));
|
|
784
|
+
}, '.newspack-stat-card__body'], ['Value', function (props) {
|
|
785
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, _objectSpread({
|
|
786
|
+
value: "1,284"
|
|
787
|
+
}, props));
|
|
788
|
+
}, '.newspack-stat-card__value'], ['Delta', function (props) {
|
|
789
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, _objectSpread(_objectSpread({
|
|
790
|
+
direction: "up"
|
|
791
|
+
}, props), {}, {
|
|
792
|
+
children: "2%"
|
|
793
|
+
}));
|
|
794
|
+
}, '.newspack-stat-card__delta'], ['Secondary', function (props) {
|
|
795
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Secondary, _objectSpread({}, props));
|
|
796
|
+
}, '.newspack-stat-card__secondary'], ['Footer', function (props) {
|
|
797
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Footer, _objectSpread(_objectSpread({}, props), {}, {
|
|
798
|
+
children: "Note"
|
|
799
|
+
}));
|
|
800
|
+
}, '.newspack-stat-card__footer']];
|
|
801
|
+
|
|
802
|
+
// Insights hangs a full amount off an abbreviated figure, which has nowhere
|
|
803
|
+
// else to go without adding an element the body layout would have to carry.
|
|
804
|
+
it.each(leaves)('%s forwards a ref and passes other props through', function (name, renderLeaf, selector) {
|
|
805
|
+
var ref = {
|
|
806
|
+
current: null
|
|
807
|
+
};
|
|
808
|
+
var _render35 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
809
|
+
children: renderLeaf({
|
|
810
|
+
ref: ref,
|
|
811
|
+
title: 'hint',
|
|
812
|
+
'data-testid': 'leaf'
|
|
813
|
+
})
|
|
814
|
+
})),
|
|
815
|
+
container = _render35.container;
|
|
816
|
+
var element = container.querySelector(selector);
|
|
817
|
+
expect(ref.current).toBe(element);
|
|
818
|
+
expect(element).toHaveAttribute('title', 'hint');
|
|
819
|
+
expect(element).toHaveAttribute('data-testid', 'leaf');
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
// The figure is what a wrapper needs to reach, not the row it may share.
|
|
823
|
+
it('puts a Value ref on the figure rather than the row it shares with a suffix', function () {
|
|
824
|
+
var ref = {
|
|
825
|
+
current: null
|
|
826
|
+
};
|
|
827
|
+
var _render36 = (0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
828
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
829
|
+
ref: ref,
|
|
830
|
+
value: "1,284",
|
|
831
|
+
suffix: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
832
|
+
direction: "up",
|
|
833
|
+
children: "2%"
|
|
834
|
+
})
|
|
835
|
+
})
|
|
836
|
+
})),
|
|
837
|
+
container = _render36.container;
|
|
838
|
+
expect(ref.current).toBe(container.querySelector('.newspack-stat-card__value'));
|
|
839
|
+
});
|
|
840
|
+
});
|
|
841
|
+
describe('StatCard outside Root', function () {
|
|
842
|
+
// Nothing above these cards catches an error, so a mistake in a branch only
|
|
843
|
+
// some sites reach must not blank the whole screen.
|
|
844
|
+
it('falls back to the default context in production rather than throwing', function () {
|
|
845
|
+
var consoleWarn = jest.spyOn(console, 'warn').mockImplementation(function () {});
|
|
846
|
+
var previous = process.env.NODE_ENV;
|
|
847
|
+
process.env.NODE_ENV = 'production';
|
|
848
|
+
try {
|
|
849
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
850
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Label, {
|
|
851
|
+
children: "Reach"
|
|
852
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
853
|
+
value: "1,284"
|
|
854
|
+
})]
|
|
855
|
+
}));
|
|
856
|
+
expect(_react.screen.getByRole('heading', {
|
|
857
|
+
level: 3
|
|
858
|
+
})).toHaveTextContent('Reach');
|
|
859
|
+
expect(_react.screen.getByText('1,284')).toBeInTheDocument();
|
|
860
|
+
expect(consoleWarn).toHaveBeenCalledWith('StatCard subcomponents must be rendered inside StatCard.Root.');
|
|
861
|
+
} finally {
|
|
862
|
+
process.env.NODE_ENV = previous;
|
|
863
|
+
consoleWarn.mockRestore();
|
|
864
|
+
}
|
|
865
|
+
});
|
|
866
|
+
});
|
|
867
|
+
describe('StatCard spoken labels', function () {
|
|
868
|
+
// A bundle registered against another text domain never loads this package's strings.
|
|
869
|
+
it('lets Root replace the name of the null glyph', function () {
|
|
870
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Root, {
|
|
871
|
+
labels: {
|
|
872
|
+
notApplicable: 'Sans objet'
|
|
873
|
+
},
|
|
874
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
875
|
+
value: null
|
|
876
|
+
})
|
|
877
|
+
}));
|
|
878
|
+
expect(_react.screen.getByText('Sans objet')).toHaveAttribute('data-visually-hidden');
|
|
879
|
+
expect(_react.screen.queryByText('Not applicable')).not.toBeInTheDocument();
|
|
880
|
+
});
|
|
881
|
+
it('lets Root replace the spoken directions', function () {
|
|
882
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsxs)(_["default"].Root, {
|
|
883
|
+
labels: {
|
|
884
|
+
up: 'En hausse',
|
|
885
|
+
down: 'En baisse'
|
|
886
|
+
},
|
|
887
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
888
|
+
direction: "up",
|
|
889
|
+
children: "2%"
|
|
890
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
891
|
+
direction: "down",
|
|
892
|
+
children: "4%"
|
|
893
|
+
})]
|
|
894
|
+
}));
|
|
895
|
+
expect(_react.screen.getByText('En hausse')).toHaveAttribute('data-visually-hidden');
|
|
896
|
+
expect(_react.screen.getByText('En baisse')).toHaveAttribute('data-visually-hidden');
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
// The per-instance props were always the override, and stay it.
|
|
900
|
+
it('lets valueLabel and directionLabel win over Root labels', function () {
|
|
901
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsxs)(_["default"].Root, {
|
|
902
|
+
labels: {
|
|
903
|
+
notApplicable: 'Sans objet',
|
|
904
|
+
up: 'En hausse'
|
|
905
|
+
},
|
|
906
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
907
|
+
value: null,
|
|
908
|
+
valueLabel: "Pas encore mesur\xE9"
|
|
909
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
910
|
+
direction: "up",
|
|
911
|
+
directionLabel: "Progression de",
|
|
912
|
+
children: "2%"
|
|
913
|
+
})]
|
|
914
|
+
}));
|
|
915
|
+
expect(_react.screen.getByText('Pas encore mesuré')).toHaveAttribute('data-visually-hidden');
|
|
916
|
+
expect(_react.screen.getByText('Progression de')).toHaveAttribute('data-visually-hidden');
|
|
917
|
+
expect(_react.screen.queryByText('Sans objet')).not.toBeInTheDocument();
|
|
918
|
+
expect(_react.screen.queryByText('En hausse')).not.toBeInTheDocument();
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
// A translation that came back empty must not leave the glyph or the arrow unnamed.
|
|
922
|
+
it('falls back to the built-in default for a blank Root label', function () {
|
|
923
|
+
(0, _react.render)(/*#__PURE__*/(0, _jsxRuntime.jsxs)(_["default"].Root, {
|
|
924
|
+
labels: {
|
|
925
|
+
notApplicable: ' ',
|
|
926
|
+
up: ''
|
|
927
|
+
},
|
|
928
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Value, {
|
|
929
|
+
value: null
|
|
930
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_["default"].Delta, {
|
|
931
|
+
direction: "up",
|
|
932
|
+
children: "2%"
|
|
933
|
+
})]
|
|
934
|
+
}));
|
|
935
|
+
expect(_react.screen.getByText('Not applicable')).toHaveAttribute('data-visually-hidden');
|
|
936
|
+
expect(_react.screen.getByText('Up')).toHaveAttribute('data-visually-hidden');
|
|
937
|
+
});
|
|
938
|
+
});
|