@scottish-government/designsystem-react 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.editorconfig +12 -0
  2. package/.github/workflows/release-package.yml +96 -0
  3. package/@types/common/ConditionalWrapper.d.ts +6 -0
  4. package/@types/common/HintText.d.ts +6 -0
  5. package/@types/common/Icon.d.ts +11 -0
  6. package/@types/common/ScreenReaderText.d.ts +4 -0
  7. package/@types/common/WrapperTag.d.ts +5 -0
  8. package/@types/components/Accordion.d.ts +15 -0
  9. package/@types/components/AspectBox.d.ts +5 -0
  10. package/@types/components/BackToTop.d.ts +5 -0
  11. package/@types/components/Breadcrumbs.d.ts +14 -0
  12. package/@types/components/Button.d.ts +17 -0
  13. package/@types/components/Checkbox.d.ts +13 -0
  14. package/@types/components/ConfirmationMessage.d.ts +7 -0
  15. package/@types/components/ContentsNav.d.ts +15 -0
  16. package/@types/components/DatePicker.d.ts +19 -0
  17. package/@types/components/Details.d.ts +6 -0
  18. package/@types/components/ErrorMessage.d.ts +6 -0
  19. package/@types/components/Metadata.d.ts +11 -0
  20. package/@types/components/NotificationBanner.d.ts +9 -0
  21. package/@types/components/NotificationPanel.d.ts +7 -0
  22. package/@types/components/PageHeader.d.ts +6 -0
  23. package/@types/components/PhaseBanner.d.ts +5 -0
  24. package/@types/components/Question.d.ts +11 -0
  25. package/@types/components/RadioButton.d.ts +15 -0
  26. package/@types/components/Select.d.ts +14 -0
  27. package/@types/components/SequentialNavigation.d.ts +14 -0
  28. package/@types/components/SideNavigation.d.ts +19 -0
  29. package/@types/components/SiteNavigation.d.ts +13 -0
  30. package/@types/components/SiteSearch.d.ts +14 -0
  31. package/@types/components/SkipLinks.d.ts +14 -0
  32. package/@types/components/Tag.d.ts +7 -0
  33. package/@types/components/TaskList.d.ts +21 -0
  34. package/@types/components/TextInput.d.ts +12 -0
  35. package/@types/components/Textarea.d.ts +4 -0
  36. package/@types/global.d.ts +1 -0
  37. package/@types/sgds.d.ts +35 -0
  38. package/package.json +36 -0
  39. package/src/common/conditional-wrapper.test.tsx +36 -0
  40. package/src/common/conditional-wrapper.tsx +9 -0
  41. package/src/common/hint-text.test.tsx +47 -0
  42. package/src/common/hint-text.tsx +21 -0
  43. package/src/common/icon.test.tsx +100 -0
  44. package/src/common/icon.tsx +28 -0
  45. package/src/common/screen-reader-text.test.tsx +31 -0
  46. package/src/common/screen-reader-text.tsx +17 -0
  47. package/src/common/wrapper-tag.test.tsx +42 -0
  48. package/src/common/wrapper-tag.tsx +15 -0
  49. package/src/components/accordion/accordion.test.tsx +212 -0
  50. package/src/components/accordion/accordion.tsx +108 -0
  51. package/src/components/aspect-box/aspect-box.test.tsx +81 -0
  52. package/src/components/aspect-box/aspect-box.tsx +57 -0
  53. package/src/components/back-to-top/back-to-top.test.tsx +45 -0
  54. package/src/components/back-to-top/back-to-top.tsx +33 -0
  55. package/src/components/breadcrumbs/breadcrumbs.test.tsx +77 -0
  56. package/src/components/breadcrumbs/breadcrumbs.tsx +53 -0
  57. package/src/components/button/button.test.tsx +125 -0
  58. package/src/components/button/button.tsx +48 -0
  59. package/src/components/checkbox/checkbox.test.tsx +180 -0
  60. package/src/components/checkbox/checkbox.tsx +107 -0
  61. package/src/components/confirmation-message/confirmation-message.test.tsx +46 -0
  62. package/src/components/confirmation-message/confirmation-message.tsx +32 -0
  63. package/src/components/contents-nav/contents-nav.test.tsx +136 -0
  64. package/src/components/contents-nav/contents-nav.tsx +54 -0
  65. package/src/components/date-picker/date-picker.test.tsx +209 -0
  66. package/src/components/date-picker/date-picker.tsx +129 -0
  67. package/src/components/details/details.test.tsx +38 -0
  68. package/src/components/details/details.tsx +25 -0
  69. package/src/components/error-message/error-message.test.tsx +40 -0
  70. package/src/components/error-message/error-message.tsx +23 -0
  71. package/src/components/inset-text/inset-text.test.tsx +33 -0
  72. package/src/components/inset-text/inset-text.tsx +19 -0
  73. package/src/components/notification-banner/notification-banner.test.tsx +93 -0
  74. package/src/components/notification-banner/notification-banner.tsx +70 -0
  75. package/src/components/notification-panel/notification-panel.test.tsx +77 -0
  76. package/src/components/notification-panel/notification-panel.tsx +31 -0
  77. package/src/components/page-header/page-header.test.tsx +48 -0
  78. package/src/components/page-header/page-header.tsx +22 -0
  79. package/src/components/page-metadata/page-metadata.test.tsx +56 -0
  80. package/src/components/page-metadata/page-metadata.tsx +39 -0
  81. package/src/components/phase-banner/phase-banner.test.tsx +67 -0
  82. package/src/components/phase-banner/phase-banner.tsx +27 -0
  83. package/src/components/question/question.test.tsx +69 -0
  84. package/src/components/question/question.tsx +33 -0
  85. package/src/components/radio-button/radio-button.test.tsx +190 -0
  86. package/src/components/radio-button/radio-button.tsx +88 -0
  87. package/src/components/select/select.test.tsx +208 -0
  88. package/src/components/select/select.tsx +86 -0
  89. package/src/components/sequential-navigation/sequential-navigation.test.tsx +67 -0
  90. package/src/components/sequential-navigation/sequential-navigation.tsx +55 -0
  91. package/src/components/side-navigation/side-navigation.test.tsx +156 -0
  92. package/src/components/side-navigation/side-navigation.tsx +85 -0
  93. package/src/components/site-navigation/site-navigation.test.tsx +63 -0
  94. package/src/components/site-navigation/site-navigation.tsx +40 -0
  95. package/src/components/site-search/site-search.test.tsx +153 -0
  96. package/src/components/site-search/site-search.tsx +97 -0
  97. package/src/components/skip-links/skip-links.test.tsx +84 -0
  98. package/src/components/skip-links/skip-links.tsx +39 -0
  99. package/src/components/tag/tag.test.tsx +45 -0
  100. package/src/components/tag/tag.tsx +23 -0
  101. package/src/components/task-list/task-list.test.tsx +409 -0
  102. package/src/components/task-list/task-list.tsx +132 -0
  103. package/src/components/text-input/text-input.test.tsx +307 -0
  104. package/src/components/text-input/text-input.tsx +98 -0
  105. package/src/components/textarea/textarea.test.tsx +212 -0
  106. package/src/components/textarea/textarea.tsx +82 -0
  107. package/src/components/warning-text/warning-text.test.tsx +40 -0
  108. package/src/components/warning-text/warning-text.tsx +21 -0
  109. package/tsconfig.json +45 -0
  110. package/vite.config.ts +12 -0
  111. package/vitest-setup.ts +13 -0
@@ -0,0 +1,107 @@
1
+ import { useEffect, useRef } from 'react';
2
+ // @ts-ignore
3
+ import DSCheckboxes from '@scottish-government/design-system/src/forms/checkbox/checkboxes'
4
+ import HintText from '../../common/hint-text';
5
+
6
+ export const Checkbox: React.FC<SGDS.Component.Checkbox> = ({
7
+ checked,
8
+ hintText,
9
+ id,
10
+ exclusive,
11
+ label,
12
+ name,
13
+ onBlur,
14
+ onChange,
15
+ small
16
+ }) => {
17
+ const hintTextId = `hint-text-${id}`;
18
+ const behaviour = exclusive && 'exclusive';
19
+
20
+ function handleBlur(event: React.FocusEvent) {
21
+ if (typeof onBlur === 'function') {
22
+ onBlur(event);
23
+ }
24
+ }
25
+
26
+ function handleChange(event: React.ChangeEvent) {
27
+ if (typeof onChange === 'function') {
28
+ onChange(event);
29
+ }
30
+ }
31
+
32
+ return (
33
+ <>
34
+ {exclusive && <p className="ds_checkbox-separator">or</p>}
35
+ <div
36
+ className={[
37
+ 'ds_checkbox',
38
+ small && 'ds_checkbox--small'
39
+ ].join(' ')}>
40
+
41
+ <input
42
+ aria-describedby={hintText ? hintTextId : undefined}
43
+ className="ds_checkbox__input"
44
+ data-behaviour={behaviour}
45
+ defaultChecked={!!checked}
46
+ id={id}
47
+ name={name || id}
48
+ onBlur={handleBlur}
49
+ onChange={handleChange}
50
+ type="checkbox" />
51
+ <label
52
+ className="ds_checkbox__label"
53
+ htmlFor={id}
54
+ >{label}</label>
55
+ {hintText && <HintText id={hintTextId} text={hintText} />}
56
+ </div>
57
+ </>
58
+ );
59
+ };
60
+
61
+ /**
62
+ * @param {Object} props - Properties for the element
63
+ * @param {Array} items - Checkboxes
64
+ * @param {boolean} small - Use the small display style for all checkboxes
65
+ * @returns {JSX.Element} - The element
66
+ */
67
+ export const CheckboxGroup: React.FC<SGDS.Component.Checkbox.Group> = ({
68
+ items,
69
+ small,
70
+ ...props
71
+ }) => {
72
+ const ref = useRef(null);
73
+
74
+ useEffect(() => {
75
+ if (ref.current) {
76
+ new DSCheckboxes(ref.current).init();
77
+ }
78
+ }, [ref])
79
+
80
+ return (
81
+ <div
82
+ className="ds_checkboxes ds_field-group"
83
+ data-module="ds-checkboxes"
84
+ ref={ref}
85
+ {...props}
86
+ >
87
+ {items && items.map((item, index: number) => (
88
+ <Checkbox
89
+ exclusive={item.exclusive}
90
+ checked={item.checked}
91
+ hintText={item.hintText}
92
+ id={item.id}
93
+ key={'checkbox' + index}
94
+ label={item.label}
95
+ onBlur={item.onBlur}
96
+ onChange={item.onChange}
97
+ small={small || item.small}
98
+ />
99
+ ))}
100
+ </div>
101
+ )
102
+ };
103
+
104
+ Checkbox.displayName = 'Checkbox';
105
+ CheckboxGroup.displayName = 'CheckboxGroup';
106
+
107
+ export default CheckboxGroup;
@@ -0,0 +1,46 @@
1
+ import { test, expect } from 'vitest';
2
+ import { render, screen } from '@testing-library/react';
3
+ import ConfirmationMessage from './confirmation-message';
4
+
5
+ const titleString = 'Landlord added successfully';
6
+
7
+ test('renders correctly with icon, title and message', () => {
8
+ render(
9
+ <ConfirmationMessage title={titleString}>
10
+ <p>You have added the landlord <strong>John Smith</strong> to the application.</p>
11
+ </ConfirmationMessage>
12
+ );
13
+
14
+ const container = document.querySelector('.ds_confirmation-message');
15
+ const header = screen.getByRole('heading');
16
+
17
+ expect(container?.ariaLive).toEqual('polite');
18
+
19
+ expect(header.tagName).toEqual('H3');
20
+ expect(header.textContent).toEqual(titleString)
21
+ });
22
+
23
+ test("does not render body when no children specified", () => {
24
+ const { container } = render(<ConfirmationMessage title={titleString} />);
25
+
26
+ expect(
27
+ container.querySelector(".ds_confirmation-message__body"),
28
+ ).not.toBeInTheDocument();
29
+ });
30
+
31
+ test('renders confirmation message with custom aria live and custom heaer level', () => {
32
+ const titleString = 'Landlord added successfully';
33
+
34
+ render(
35
+ <ConfirmationMessage headerLevel="h2" ariaLive="alert" title={titleString}>
36
+ <p>You have added the landlord <strong>John Smith</strong> to the application.</p>
37
+ </ConfirmationMessage>
38
+ );
39
+
40
+ const container = document.querySelector('.ds_confirmation-message');
41
+ const header = screen.getByRole('heading');
42
+
43
+ expect(container?.ariaLive).toEqual('alert');
44
+
45
+ expect(header.tagName).toEqual('H2');
46
+ });
@@ -0,0 +1,32 @@
1
+ import Icon from '../../common/icon';
2
+ import WrapperTag from '../../common/wrapper-tag';
3
+
4
+ const ConfirmationMessage: React.FC<SGDS.Component.ConfirmationMessage> = ({
5
+ ariaLive = 'polite',
6
+ children,
7
+ headerLevel = 'h3',
8
+ title
9
+ }) => {
10
+ return (
11
+ <div
12
+ aria-live={ariaLive}
13
+ className="ds_confirmation-message"
14
+ >
15
+ <Icon className="ds_confirmation-message__icon" icon="check_circle" iconSize="24" />
16
+
17
+ <WrapperTag
18
+ className="ds_confirmation-message__title"
19
+ tagName={headerLevel}
20
+ >
21
+ {title}
22
+ </WrapperTag>
23
+ {children && <div className="ds_confirmation-message__body">
24
+ {children}
25
+ </div>}
26
+ </div>
27
+ );
28
+ };
29
+
30
+ ConfirmationMessage.displayName = 'ConfirmationMessage';
31
+
32
+ export default ConfirmationMessage;
@@ -0,0 +1,136 @@
1
+ import { test, expect } from 'vitest';
2
+ import { render, screen, within } from '@testing-library/react';
3
+ import ContentsNav, {Link} from './contents-nav';
4
+
5
+ test('contents nav renders correctly', () => {
6
+ const items = [
7
+ {
8
+ title: 'Apply for Blue Badge',
9
+ current: true
10
+ },
11
+ {
12
+ title: 'Eligibility',
13
+ href: '#2'
14
+ },
15
+ {
16
+ title: 'Using your Blue Badge',
17
+ href: '#3'
18
+ },
19
+ {
20
+ title: 'Report a lost, stolen or misuesd Blue Badge',
21
+ href: '#4'
22
+ },
23
+ {
24
+ title: 'Changing or handing back a Blue Badge',
25
+ href: '#5'
26
+ }
27
+ ];
28
+
29
+ const label = 'Pages in this guide';
30
+
31
+ render(
32
+ <ContentsNav label={label} items={items} />
33
+ )
34
+
35
+ const contentsNav = screen.getByRole('navigation');
36
+ const contentsNavTitle = within(contentsNav).getByRole('heading');
37
+ const contentsNavList = within(contentsNav).getByRole('list');
38
+
39
+ expect(contentsNav).toHaveClass('ds_contents-nav');
40
+ expect(contentsNav.ariaLabel).toEqual(label);
41
+ expect(contentsNav.tagName).toEqual('NAV');
42
+ expect(contentsNavTitle).toHaveClass('ds_contents-nav__title');
43
+ expect(contentsNavTitle.textContent).toEqual('Contents');
44
+ expect(contentsNavList).toHaveClass('ds_contents-nav__list');
45
+ expect(contentsNavList.tagName).toEqual('UL');
46
+ expect(contentsNavList.children.length).toEqual(items.length);
47
+ });
48
+
49
+ test('contents nav with custom title', () => {
50
+ const title = 'My title';
51
+
52
+ render(
53
+ <ContentsNav title={title} items={[]} />
54
+ );
55
+
56
+ const contentsNav = screen.getByRole('navigation');
57
+ const contentsNavTitle = within(contentsNav).getByRole('heading');
58
+ expect(contentsNavTitle.textContent).toEqual(title);
59
+ });
60
+
61
+ test('contents nav item', () => {
62
+ const href = '#foo';
63
+ const content = 'My content';
64
+
65
+ render(
66
+ <Link href={href} title={content} />
67
+ );
68
+
69
+ const listItem = screen.getByRole('listitem');
70
+ const link = within(listItem).getByRole('link');
71
+
72
+ expect(listItem).toHaveClass('ds_contents-nav__item');
73
+ expect(listItem.tagName).toEqual('LI');
74
+ expect(link).toHaveClass('ds_contents-nav__link');
75
+ expect(link.tagName).toEqual('A');
76
+ expect(link.textContent).toEqual(content);
77
+ expect(link).toHaveAttribute('href', href);
78
+ });
79
+
80
+ test('contents nav current item with href', () => {
81
+ const href = '#foo';
82
+ const content = 'My content';
83
+
84
+ render(
85
+ <Link current href={href} title={content} />
86
+ );
87
+
88
+ const listItem = screen.getByRole('listitem');
89
+ const link = within(listItem).getByText(content);
90
+
91
+ expect(listItem.ariaCurrent).toEqual('page');
92
+ expect(link.tagName).toEqual('SPAN');
93
+ expect(link).toHaveClass('ds_current');
94
+ });
95
+
96
+ test('contents nav current item without href', () => {
97
+ const content = 'My content';
98
+
99
+ render(
100
+ <Link current title={content} />
101
+ );
102
+
103
+ const listItem = screen.getByRole('listitem');
104
+ const link = within(listItem).getByText(content);
105
+
106
+ expect(listItem.ariaCurrent).toEqual('page');
107
+ expect(link.tagName).toEqual('SPAN');
108
+ expect(link).toHaveClass('ds_current');
109
+ });
110
+
111
+ test('contents nav item without href', () => {
112
+ const content = 'My content';
113
+
114
+ render(
115
+ <Link title={content} />
116
+ );
117
+
118
+ const listItem = screen.getByRole('listitem');
119
+ const link = within(listItem).getByText(content);
120
+
121
+ expect(link.tagName).toEqual('SPAN');
122
+ expect(link).not.toHaveClass('ds_current');
123
+ });
124
+
125
+ test('passing additional props', () => {
126
+ render(
127
+ <ContentsNav data-test="foo" items={[
128
+ {
129
+ title: 'Apply for Blue Badge',
130
+ }
131
+ ]} />
132
+ )
133
+
134
+ const contentsNav = screen.getByRole('navigation');
135
+ expect(contentsNav?.dataset.test).toEqual('foo');
136
+ });
@@ -0,0 +1,54 @@
1
+ import WrapperTag from '../../common/wrapper-tag';
2
+
3
+ export const Link: React.FC<SGDS.Component.ContentsNav.Link> = ({
4
+ title,
5
+ current,
6
+ href
7
+ }) => {
8
+ // determine which HTML tag to use
9
+ const tagName = href && !current ? 'a' : 'span';
10
+
11
+ return (
12
+ <li
13
+ aria-current={current && 'page' || undefined}
14
+ className="ds_contents-nav__item"
15
+ >
16
+ <WrapperTag
17
+ tagName={tagName}
18
+ className={[
19
+ 'ds_contents-nav__link',
20
+ current && 'ds_current'
21
+ ].join(' ')}
22
+ href={!current ? href : undefined}
23
+ >
24
+ {title}
25
+ </WrapperTag>
26
+ </li>
27
+ );
28
+ };
29
+
30
+ const ContentsNav: React.FC<SGDS.Component.ContentsNav> = function({
31
+ items,
32
+ label = 'Pages in this section',
33
+ title = 'Contents',
34
+ ...props
35
+ }) {
36
+ return (
37
+ <nav
38
+ aria-label={label}
39
+ className="ds_contents-nav"
40
+ {...props}
41
+ >
42
+ <h2 className="ds_contents-nav__title">{title}</h2>
43
+ <ul className="ds_contents-nav__list">
44
+ {items && items.map((item, index: number) => (
45
+ <Link current={item.current} href={item.href} title={item.title} key={'link' + index} />
46
+ ))}
47
+ </ul>
48
+ </nav>
49
+ );
50
+ };
51
+
52
+ ContentsNav.displayName = 'ContentsNav';
53
+
54
+ export default ContentsNav;
@@ -0,0 +1,209 @@
1
+ import { test, expect, vi } from 'vitest';
2
+ import { render, screen, within, fireEvent } from '@testing-library/react';
3
+ import DatePicker from './date-picker';
4
+
5
+ const labelText = 'Date of birth';
6
+ const id = 'date-picker';
7
+
8
+ test('date picker renders correctly', () => {
9
+ render(
10
+ <DatePicker
11
+ id={id}
12
+ label={labelText}
13
+ />
14
+ );
15
+
16
+ // a little hacky. maybe testid would be better?
17
+ const datePicker = screen.getAllByRole('generic')[1];
18
+ const label = within(datePicker).getByText(labelText);
19
+ const textInput = within(datePicker).getByRole('textbox');
20
+
21
+ expect(datePicker).toHaveClass('ds_datepicker');
22
+ expect(label).toHaveClass('ds_label');
23
+ expect(label).toHaveAttribute('for', textInput.id);
24
+ expect(label.tagName).toEqual('LABEL');
25
+ expect(textInput).toHaveClass('ds_input', 'ds_input--fixed-10');
26
+ expect(textInput.id).toEqual(id);
27
+
28
+ // todo: check for DS script being fired
29
+ });
30
+
31
+ test('date picker with disabled dates', () => {
32
+ const disabledDates = '18/05/2023 19/05/2023'
33
+ render(
34
+ <DatePicker
35
+ id={id}
36
+ label={labelText}
37
+ disabledDates={disabledDates}
38
+ />
39
+ );
40
+ const datePicker = screen.getAllByRole('generic')[1];
41
+
42
+ expect(datePicker).toHaveAttribute('data-disableddates', disabledDates);
43
+ });
44
+
45
+ test('date picker with hint text', () => {
46
+ const hintText = 'My hint text'
47
+ render(
48
+ <DatePicker
49
+ id={id}
50
+ label={labelText}
51
+ hintText={hintText}
52
+ />
53
+ );
54
+ const datePicker = screen.getAllByRole('generic')[1];
55
+ const hintTextEl = screen.getByText(hintText);
56
+ const textInput = within(datePicker).getByRole('textbox');
57
+
58
+ expect(hintTextEl).toBeInTheDocument();
59
+ expect(textInput).toHaveAttribute('aria-describedby', hintTextEl.id);
60
+ });
61
+
62
+ test('date picker with custom icon path', () => {
63
+ const iconPath = '/my/icon/path'
64
+ render(
65
+ <DatePicker
66
+ id={id}
67
+ label={labelText}
68
+ iconPath={iconPath}
69
+ />
70
+ );
71
+ const datePicker = screen.getAllByRole('generic')[1];
72
+ const label = within(datePicker).getByText(labelText);
73
+ const textInput = within(datePicker).getByRole('textbox');
74
+
75
+ // todo
76
+ });
77
+
78
+ test('date picker with max date', () => {
79
+ const maxDate = '28/05/2023'
80
+ render(
81
+ <DatePicker
82
+ id={id}
83
+ label={labelText}
84
+ maxDate={maxDate}
85
+ />
86
+ );
87
+ const datePicker = screen.getAllByRole('generic')[1];
88
+
89
+ expect(datePicker).toHaveAttribute('data-maxDate', maxDate);
90
+ });
91
+
92
+ test('date picker with min date', () => {
93
+ const minDate = '28/05/2023'
94
+ render(
95
+ <DatePicker
96
+ id={id}
97
+ label={labelText}
98
+ minDate={minDate}
99
+ />
100
+ );
101
+ const datePicker = screen.getAllByRole('generic')[1];
102
+
103
+ expect(datePicker).toHaveAttribute('data-mindate', minDate);
104
+ });
105
+
106
+ test('date picker with blur fn', () => {
107
+ const onBlurFn = vi.fn();
108
+ render(
109
+ <DatePicker
110
+ id={id}
111
+ label={labelText}
112
+ onBlur={onBlurFn}
113
+ />
114
+ );
115
+ const datePicker = screen.getAllByRole('generic')[1];
116
+ const textInput = within(datePicker).getByRole('textbox');
117
+
118
+ fireEvent.blur(textInput);
119
+
120
+ expect(onBlurFn).toHaveBeenCalled();
121
+ });
122
+
123
+ test('date picker with change fn', () => {
124
+ const onChangeFn = vi.fn();
125
+ render(
126
+ <DatePicker
127
+ id={id}
128
+ label={labelText}
129
+ onChange={onChangeFn}
130
+ />
131
+ );
132
+ const datePicker = screen.getAllByRole('generic')[1];
133
+ const textInput = within(datePicker).getByRole('textbox');
134
+
135
+ fireEvent.change(textInput, {target: {value: 'foo'}});
136
+
137
+ expect(onChangeFn).toHaveBeenCalled();
138
+ });
139
+
140
+ test('date picker with initial value', () => {
141
+ const initialValue = '28/05/2023';
142
+ render(
143
+ <DatePicker
144
+ id={id}
145
+ label={labelText}
146
+ value={initialValue}
147
+ />
148
+ );
149
+ const datePicker = screen.getAllByRole('generic')[1];
150
+ const textInput = within(datePicker).getByRole('textbox');
151
+
152
+ expect(textInput).toHaveValue(initialValue);
153
+ });
154
+
155
+ test('date picker with multiple inputs', () => {
156
+ const initialValue = '28/05/2023';
157
+ render(
158
+ <DatePicker
159
+ id={id}
160
+ label={labelText}
161
+ multiple
162
+ value={initialValue}
163
+ />
164
+ );
165
+
166
+ const datePicker = screen.getAllByRole('generic')[1];
167
+ const textInputs = within(datePicker).getAllByRole('textbox');
168
+ const dateInput = textInputs[0];
169
+ const monthInput = textInputs[1];
170
+ const yearInput = textInputs[2];
171
+ const dateLabel = within(datePicker).getByText('Day');
172
+ const monthLabel = within(datePicker).getByText('Month');
173
+ const yearLabel = within(datePicker).getByText('Year');
174
+
175
+ expect(textInputs.length).toEqual(3);
176
+
177
+ expect(dateInput).toHaveValue(initialValue.split('/')[0]);
178
+ expect(monthInput).toHaveValue(initialValue.split('/')[1]);
179
+ expect(yearInput).toHaveValue(initialValue.split('/')[2]);
180
+
181
+ expect(dateInput).toHaveAttribute('id', `${id}-day`);
182
+ expect(monthInput).toHaveAttribute('id', `${id}-month`);
183
+ expect(yearInput).toHaveAttribute('id', `${id}-year`);
184
+
185
+ expect(dateInput).toHaveClass('ds_input', 'ds_input--fixed-2', 'js-datepicker-date');
186
+ expect(monthInput).toHaveClass('ds_input', 'ds_input--fixed-2', 'js-datepicker-month');
187
+ expect(yearInput).toHaveClass('ds_input', 'ds_input--fixed-4', 'js-datepicker-year');
188
+
189
+ expect(dateLabel).toHaveClass('ds_label');
190
+ expect(monthLabel).toHaveClass('ds_label');
191
+ expect(yearLabel).toHaveClass('ds_label');
192
+
193
+ expect(dateLabel).toHaveAttribute('for', dateInput.id);
194
+ expect(monthLabel).toHaveAttribute('for', monthInput.id);
195
+ expect(yearLabel).toHaveAttribute('for', yearInput.id);
196
+ });
197
+
198
+ test('passing additional props', () => {
199
+ render(
200
+ <DatePicker
201
+ id={id}
202
+ label={labelText}
203
+ data-test="foo"
204
+ />
205
+ )
206
+
207
+ const datePicker = screen.getAllByRole('generic')[1];
208
+ expect(datePicker?.dataset.test).toEqual('foo');
209
+ });