@govtechsg/sgds-web-component 0.0.7 → 0.0.10

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 (263) hide show
  1. package/.github/workflows/publish-latest.yml +22 -0
  2. package/.github/workflows/publish-pr.yml +28 -0
  3. package/.husky/commit-msg +4 -0
  4. package/.husky/prepare-commit-msg +8 -0
  5. package/.storybook/main.js +16 -0
  6. package/.storybook/preview-head.html +11 -0
  7. package/.storybook/preview.js +9 -0
  8. package/.vscode/settings.json +7 -0
  9. package/CONTRIBUTING.md +56 -0
  10. package/LICENSE +20 -0
  11. package/amplify.yml +22 -0
  12. package/commitlint.config.js +1 -0
  13. package/coverage/lcov-report/base.css +224 -0
  14. package/coverage/lcov-report/block-navigation.js +87 -0
  15. package/coverage/lcov-report/button-element.scss.html +112 -0
  16. package/coverage/lcov-report/button-element.ts.html +145 -0
  17. package/coverage/lcov-report/favicon.png +0 -0
  18. package/coverage/lcov-report/index.html +116 -0
  19. package/coverage/lcov-report/prettify.css +1 -0
  20. package/coverage/lcov-report/prettify.js +2 -0
  21. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  22. package/coverage/lcov-report/sorter.js +196 -0
  23. package/coverage/lcov.info +32 -0
  24. package/index.html +430 -0
  25. package/{Button → lib/Button}/index.d.ts +0 -0
  26. package/{Button → lib/Button}/index.js +304 -39
  27. package/lib/Button/index.js.map +1 -0
  28. package/{Button → lib/Button}/package.json +0 -0
  29. package/lib/Button/sgds-button.d.ts +48 -0
  30. package/lib/Card/index.d.ts +1 -0
  31. package/lib/Card/index.js +6150 -0
  32. package/lib/Card/index.js.map +1 -0
  33. package/lib/Card/package.json +7 -0
  34. package/lib/Card/sgds-action-card.d.ts +20 -0
  35. package/lib/Checkbox/index.d.ts +1 -0
  36. package/lib/Checkbox/index.js +6366 -0
  37. package/lib/Checkbox/index.js.map +1 -0
  38. package/lib/Checkbox/package.json +7 -0
  39. package/lib/Checkbox/sgds-checkbox.d.ts +36 -0
  40. package/lib/Dropdown/index.d.ts +3 -0
  41. package/{Mainnav → lib/Dropdown}/index.js +2786 -9258
  42. package/lib/Dropdown/index.js.map +1 -0
  43. package/lib/Dropdown/package.json +7 -0
  44. package/lib/Dropdown/sgds-dropdown-item.d.ts +7 -0
  45. package/lib/Dropdown/sgds-dropdown.d.ts +7 -0
  46. package/{Footer → lib/Footer}/index.d.ts +0 -0
  47. package/{Footer → lib/Footer}/index.js +111 -95
  48. package/lib/Footer/index.js.map +1 -0
  49. package/{Footer → lib/Footer}/package.json +0 -0
  50. package/{Footer → lib/Footer}/sgds-footer.d.ts +2 -2
  51. package/lib/Input/index.d.ts +1 -0
  52. package/lib/Input/index.js +6656 -0
  53. package/lib/Input/index.js.map +1 -0
  54. package/lib/Input/package.json +7 -0
  55. package/lib/Input/sgds-input.d.ts +42 -0
  56. package/{Mainnav → lib/Mainnav}/index.d.ts +1 -0
  57. package/{index.js → lib/Mainnav/index.js} +3876 -23415
  58. package/lib/Mainnav/index.js.map +1 -0
  59. package/{Mainnav → lib/Mainnav}/package.json +0 -0
  60. package/lib/Mainnav/sgds-mainnav-dropdown.d.ts +5 -0
  61. package/lib/Mainnav/sgds-mainnav-item.d.ts +4 -0
  62. package/{Mainnav → lib/Mainnav}/sgds-mainnav.d.ts +3 -2
  63. package/{Masthead → lib/Masthead}/index.d.ts +0 -0
  64. package/{Masthead → lib/Masthead}/index.js +140 -114
  65. package/lib/Masthead/index.js.map +1 -0
  66. package/{Masthead → lib/Masthead}/package.json +0 -0
  67. package/{Masthead → lib/Masthead}/sgds-masthead.d.ts +1 -1
  68. package/lib/Modal/index.d.ts +1 -0
  69. package/lib/Modal/index.js +6432 -0
  70. package/lib/Modal/index.js.map +1 -0
  71. package/lib/Modal/package.json +7 -0
  72. package/lib/Modal/sgds-modal.d.ts +28 -0
  73. package/lib/QuantityToggle/index.d.ts +1 -0
  74. package/lib/QuantityToggle/index.js +7049 -0
  75. package/lib/QuantityToggle/index.js.map +1 -0
  76. package/lib/QuantityToggle/package.json +7 -0
  77. package/lib/QuantityToggle/sgds-quantitytoggle.d.ts +30 -0
  78. package/lib/Radio/index.d.ts +2 -0
  79. package/lib/Radio/index.js +12607 -0
  80. package/lib/Radio/index.js.map +1 -0
  81. package/lib/Radio/package.json +7 -0
  82. package/lib/Radio/sgds-radio.d.ts +31 -0
  83. package/lib/Radio/sgds-radiogroup.d.ts +41 -0
  84. package/{Sidenav → lib/Sidenav}/index.d.ts +0 -0
  85. package/{Sidenav → lib/Sidenav}/index.js +2266 -2171
  86. package/lib/Sidenav/index.js.map +1 -0
  87. package/{Sidenav → lib/Sidenav}/package.json +0 -0
  88. package/{Sidenav → lib/Sidenav}/sgds-sidenav-item.d.ts +2 -1
  89. package/lib/Sidenav/sgds-sidenav-link.d.ts +4 -0
  90. package/{Sidenav → lib/Sidenav}/sgds-sidenav.d.ts +1 -1
  91. package/lib/Tab/index.d.ts +3 -0
  92. package/lib/Tab/index.js +13557 -0
  93. package/lib/Tab/index.js.map +1 -0
  94. package/lib/Tab/package.json +7 -0
  95. package/lib/Tab/sgds-tab.d.ts +26 -0
  96. package/lib/Tab/sgds-tabgroup.d.ts +47 -0
  97. package/lib/Tab/sgds-tabpanel.d.ts +25 -0
  98. package/lib/Textarea/index.d.ts +1 -0
  99. package/lib/Textarea/index.js +6696 -0
  100. package/lib/Textarea/index.js.map +1 -0
  101. package/lib/Textarea/package.json +7 -0
  102. package/lib/Textarea/sgds-textarea.d.ts +53 -0
  103. package/lib/index.d.ts +16 -0
  104. package/lib/index.js +134580 -0
  105. package/lib/index.js.map +1 -0
  106. package/lib/umd/index.js +134587 -0
  107. package/lib/umd/index.js.map +1 -0
  108. package/lib/utils/animate.d.ts +10 -0
  109. package/lib/utils/animation-registry.d.ts +18 -0
  110. package/{utils → lib/utils}/breakpoints.d.ts +0 -0
  111. package/lib/utils/card-element.d.ts +11 -0
  112. package/lib/utils/defaultvalue.d.ts +2 -0
  113. package/lib/utils/dropdown-element.d.ts +37 -0
  114. package/lib/utils/event.d.ts +2 -0
  115. package/lib/utils/form.d.ts +38 -0
  116. package/{utils → lib/utils}/generateId.d.ts +0 -0
  117. package/lib/utils/link-element.d.ts +7 -0
  118. package/lib/utils/mergeDeep.d.ts +2 -0
  119. package/lib/utils/modal.d.ts +12 -0
  120. package/lib/utils/object.d.ts +2 -0
  121. package/lib/utils/offset.d.ts +4 -0
  122. package/lib/utils/scroll.d.ts +13 -0
  123. package/{utils → lib/utils}/sgds-element.d.ts +0 -0
  124. package/lib/utils/slot.d.ts +22 -0
  125. package/lib/utils/tabbable.d.ts +8 -0
  126. package/lib/utils/watch.d.ts +14 -0
  127. package/mocks/dropdown.d.ts +4 -0
  128. package/mocks/dropdown.ts +27 -0
  129. package/mocks/link.d.ts +3 -0
  130. package/mocks/link.ts +6 -0
  131. package/package.json +65 -10
  132. package/rollup.config.js +73 -0
  133. package/rollup.test.config.js +42 -0
  134. package/scripts/buildUtils.js +30 -0
  135. package/scripts/frankBuild.js +49 -0
  136. package/src/Button/index.ts +1 -0
  137. package/src/Button/sgds-button.scss +28 -0
  138. package/src/Button/sgds-button.ts +153 -0
  139. package/src/Card/index.ts +1 -0
  140. package/src/Card/sgds-action-card.scss +27 -0
  141. package/src/Card/sgds-action-card.ts +115 -0
  142. package/src/Checkbox/index.ts +1 -0
  143. package/src/Checkbox/sgds-checkbox.scss +4 -0
  144. package/src/Checkbox/sgds-checkbox.ts +149 -0
  145. package/src/Dropdown/index.ts +3 -0
  146. package/src/Dropdown/sgds-dropdown-item.ts +39 -0
  147. package/src/Dropdown/sgds-dropdown.scss +5 -0
  148. package/src/Dropdown/sgds-dropdown.ts +54 -0
  149. package/src/Footer/index.ts +3 -0
  150. package/src/Footer/sgds-footer.scss +5 -0
  151. package/src/Footer/sgds-footer.ts +121 -0
  152. package/src/Input/index.ts +1 -0
  153. package/src/Input/sgds-input.scss +20 -0
  154. package/src/Input/sgds-input.ts +178 -0
  155. package/src/Mainnav/index.ts +4 -0
  156. package/src/Mainnav/sgds-mainnav-dropdown.scss +13 -0
  157. package/src/Mainnav/sgds-mainnav-dropdown.ts +45 -0
  158. package/src/Mainnav/sgds-mainnav-item.scss +24 -0
  159. package/src/Mainnav/sgds-mainnav-item.ts +8 -0
  160. package/src/Mainnav/sgds-mainnav.scss +39 -0
  161. package/src/Mainnav/sgds-mainnav.ts +183 -0
  162. package/src/Masthead/index.ts +1 -0
  163. package/src/Masthead/sgds-masthead.scss +217 -0
  164. package/src/Masthead/sgds-masthead.ts +189 -0
  165. package/src/Modal/index.ts +1 -0
  166. package/src/Modal/sgds-modal.scss +128 -0
  167. package/src/Modal/sgds-modal.ts +309 -0
  168. package/src/QuantityToggle/index.ts +1 -0
  169. package/src/QuantityToggle/sgds-quantitytoggle.scss +10 -0
  170. package/src/QuantityToggle/sgds-quantitytoggle.ts +130 -0
  171. package/src/Radio/index.ts +2 -0
  172. package/src/Radio/sgds-radio.scss +5 -0
  173. package/src/Radio/sgds-radio.ts +120 -0
  174. package/src/Radio/sgds-radiogroup.scss +22 -0
  175. package/src/Radio/sgds-radiogroup.ts +221 -0
  176. package/src/Sidenav/index.ts +4 -0
  177. package/src/Sidenav/sgds-sidenav-item.scss +73 -0
  178. package/src/Sidenav/sgds-sidenav-item.ts +145 -0
  179. package/src/Sidenav/sgds-sidenav-link.scss +25 -0
  180. package/src/Sidenav/sgds-sidenav-link.ts +8 -0
  181. package/src/Sidenav/sgds-sidenav.scss +6 -0
  182. package/src/Sidenav/sgds-sidenav.ts +33 -0
  183. package/src/Tab/index.ts +3 -0
  184. package/src/Tab/sgds-tab.scss +84 -0
  185. package/src/Tab/sgds-tab.ts +87 -0
  186. package/src/Tab/sgds-tabgroup.scss +198 -0
  187. package/src/Tab/sgds-tabgroup.ts +295 -0
  188. package/src/Tab/sgds-tabpanel.scss +12 -0
  189. package/src/Tab/sgds-tabpanel.ts +55 -0
  190. package/src/Textarea/index.ts +1 -0
  191. package/src/Textarea/sgds-textarea.scss +23 -0
  192. package/src/Textarea/sgds-textarea.ts +201 -0
  193. package/src/index.ts +16 -0
  194. package/src/utils/animate.ts +69 -0
  195. package/src/utils/animation-registry.ts +71 -0
  196. package/src/utils/base.scss +14 -0
  197. package/src/utils/breakpoints.ts +5 -0
  198. package/src/utils/card-element.ts +42 -0
  199. package/src/utils/components.style.scss +531 -0
  200. package/src/utils/defaultvalue.ts +51 -0
  201. package/src/utils/dropdown-element.ts +244 -0
  202. package/src/utils/event.ts +13 -0
  203. package/src/utils/form.ts +183 -0
  204. package/src/utils/generateId.ts +4 -0
  205. package/src/utils/link-element.ts +34 -0
  206. package/src/utils/mergeDeep.ts +22 -0
  207. package/src/utils/modal.ts +64 -0
  208. package/src/utils/object.ts +2 -0
  209. package/src/utils/offset.ts +6 -0
  210. package/src/utils/scroll.ts +57 -0
  211. package/src/utils/sgds-element.ts +18 -0
  212. package/src/utils/slot.ts +102 -0
  213. package/src/utils/tabbable.ts +81 -0
  214. package/src/utils/watch.ts +62 -0
  215. package/stories/ActionCard.stories.mdx +199 -0
  216. package/stories/Button.stories.mdx +194 -0
  217. package/stories/Checkbox.stories.mdx +196 -0
  218. package/stories/Dropdown.stories.mdx +152 -0
  219. package/stories/Footer.stories.mdx +261 -0
  220. package/stories/Input.stories.mdx +236 -0
  221. package/stories/MainNav.stories.mdx +169 -0
  222. package/stories/Masthead.stories.mdx +112 -0
  223. package/stories/Modal.stories.mdx +103 -0
  224. package/stories/QuantityToggle.stories.mdx +97 -0
  225. package/stories/Radio.stories.mdx +262 -0
  226. package/stories/Sample.stories.js +29 -0
  227. package/stories/Sample.stories.mdx +33 -0
  228. package/stories/SideNav.stories.mdx +245 -0
  229. package/stories/common.js +185 -0
  230. package/stories/textarea.stories.mdx +253 -0
  231. package/test/button.element.test.ts +185 -0
  232. package/test/checkbox.test.ts +240 -0
  233. package/test/dropdown.test.ts +637 -0
  234. package/test/footer.test.ts +181 -0
  235. package/test/generateId.test.ts +18 -0
  236. package/test/input.element.test.ts +316 -0
  237. package/test/link-element.test.ts +38 -0
  238. package/test/mainnav.test.ts +313 -0
  239. package/test/masthead.test.ts +116 -0
  240. package/test/modal.test.ts +149 -0
  241. package/test/quantitytoggle.test.ts +76 -0
  242. package/test/radio.test.ts +310 -0
  243. package/test/selectable-card.test.ts +159 -0
  244. package/test/sidenav.test.ts +390 -0
  245. package/test/tab.test.ts +76 -0
  246. package/test/textarea.test.ts +126 -0
  247. package/tsconfig.json +26 -0
  248. package/tsconfig.test.json +24 -0
  249. package/typings/scss.d.ts +5 -0
  250. package/web-dev-server.config.mjs +7 -0
  251. package/web-test-runner.config.mjs +47 -0
  252. package/Button/index.js.map +0 -1
  253. package/Button/sgds-button.d.ts +0 -23
  254. package/Footer/index.js.map +0 -1
  255. package/Mainnav/index.js.map +0 -1
  256. package/Mainnav/sgds-mainnav-item.d.ts +0 -7
  257. package/Masthead/index.js.map +0 -1
  258. package/Sidenav/index.js.map +0 -1
  259. package/Sidenav/sgds-sidenav-link.d.ts +0 -7
  260. package/index.d.ts +0 -5
  261. package/index.js.map +0 -1
  262. package/umd/index.js +0 -52092
  263. package/umd/index.js.map +0 -1
@@ -0,0 +1,181 @@
1
+ import { SgdsFooter, ColumnLinks } from "../src/Footer";
2
+ import "../src/Footer/sgds-footer";
3
+ import { fixture, assert, expect } from "@open-wc/testing";
4
+ import { html } from "lit";
5
+
6
+ describe("button-element", () => {
7
+ it("is defined", () => {
8
+ const el = document.createElement("sgds-footer");
9
+ assert.instanceOf(el, SgdsFooter);
10
+ });
11
+ it("renders with default values", async () => {
12
+ const el = await fixture(html`<sgds-footer></sgds-footer>`);
13
+ assert.shadowDom.equal(
14
+ el,
15
+ `
16
+ <footer class="sgds footer">
17
+ <section class="footer-top" part="footer-top">
18
+ <div class="container-fluid">
19
+ <div class="row footer-header">
20
+ <div class="col col-lg-6 col-md-12">
21
+ <div class="title"></div>
22
+ <div class="description"></div>
23
+ </div>
24
+ </div>
25
+ <div class="row footer-items">
26
+ </div>
27
+ <div class="row footer-contact-links">
28
+ <div class="col">
29
+ <div class="d-flex justify-content-lg-end">
30
+ <ul>
31
+ <li><a href="#">Contact</a></li>
32
+ <li><a href="#">Feedback</a></li>
33
+ <li>
34
+ <a
35
+ href="https://www.reach.gov.sg/"
36
+ target="_blank"
37
+ rel="noopener noreferrer"
38
+ >Reach.gov.sg</a
39
+ >
40
+ </li>
41
+ </ul>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ </section>
47
+ <section class="footer-bottom" part="footer-bottom">
48
+ <div class="container-fluid">
49
+ <div class="row footer-mandatory-links">
50
+ <div class="col">
51
+ <ul>
52
+ <li>
53
+ <a
54
+ href="#"
55
+ target="_blank"
56
+ rel="noopener noreferrer"
57
+ >Report Vulnerability</a
58
+ >
59
+ </li>
60
+ <li><a href="#">Privacy Statement</a></li>
61
+ <li><a href="#">Terms of use</a></li>
62
+ </ul>
63
+ </div>
64
+ </div>
65
+ <div class="row footer-copyrights">
66
+ <div class="col">
67
+ <div class="d-flex justify-content-lg-end text-end">
68
+ © ${new Date().getFullYear()} Government of Singapore<br />
69
+ Last Updated
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </section>
75
+ </footer>
76
+ `
77
+ );
78
+ });
79
+
80
+ it("description prop forward to .description class", async () => {
81
+ const el = await fixture(
82
+ html`<sgds-footer description="test description"></sgds-footer>`
83
+ );
84
+ expect(el.shadowRoot?.querySelector(".description")?.textContent).to.equal(
85
+ "test description"
86
+ );
87
+ });
88
+
89
+ it("title prop forward to approriate .title class", async () => {
90
+ const el = await fixture(
91
+ html`<sgds-footer title="test title"></sgds-footer>`
92
+ );
93
+ expect(el.shadowRoot?.querySelector(".title")?.textContent).to.equal(
94
+ "test title"
95
+ );
96
+ });
97
+ it("lastUpdatedDate prop forward to approriate div el", async () => {
98
+ const el = await fixture(
99
+ html`<sgds-footer lastUpdatedDate="08 Feb 2022"></sgds-footer>`
100
+ );
101
+ expect(
102
+ el.shadowRoot?.querySelector(".footer-copyrights>div.col>div")
103
+ ?.textContent
104
+ ).to.contain("08 Feb 2022");
105
+ });
106
+
107
+ it("contactHref prop forward to contact's href attr", async () => {
108
+ const el = await fixture(
109
+ html`<sgds-footer contactHref="test"></sgds-footer>`
110
+ );
111
+ expect(
112
+ el.shadowRoot?.querySelector("a[href='test']")?.textContent
113
+ ).to.contain("Contact");
114
+ });
115
+
116
+ it("feedbackHref prop forward to feedback's href attr", async () => {
117
+ const el = await fixture(
118
+ html`<sgds-footer feedbackHref="test"></sgds-footer>`
119
+ );
120
+ expect(
121
+ el.shadowRoot?.querySelector("a[href='test']")?.textContent
122
+ ).to.contain("Feedback");
123
+ });
124
+ it("vulnerabilityHref prop forward to Report Vulnerability's href attr", async () => {
125
+ const el = await fixture(
126
+ html`<sgds-footer vulnerabilityHref="test"></sgds-footer>`
127
+ );
128
+ expect(
129
+ el.shadowRoot?.querySelector("a[href='test']")?.textContent
130
+ ).to.contain("Report Vulnerability");
131
+ });
132
+ it("privacyHref prop forward to Privacy Statement's href attr", async () => {
133
+ const el = await fixture(
134
+ html`<sgds-footer privacyHref="test"></sgds-footer>`
135
+ );
136
+ expect(
137
+ el.shadowRoot?.querySelector("a[href='test']")?.textContent
138
+ ).to.contain("Privacy Statement");
139
+ });
140
+ it("termsOfUseHref prop forward to Terms of use's href attr", async () => {
141
+ const el = await fixture(
142
+ html`<sgds-footer termsOfUseHref="test"></sgds-footer>`
143
+ );
144
+ expect(
145
+ el.shadowRoot?.querySelector("a[href='test']")?.textContent
146
+ ).to.contain("Terms of use");
147
+ });
148
+
149
+
150
+ it("links prop accepts an array", async () => {
151
+ const linkArray: ColumnLinks[] = [
152
+ {
153
+ title: "test-1",
154
+ links: [
155
+ { href: "test-href-1", label: "test-label-1" },
156
+ { href: "test-href-2", label: "test-label-2" },
157
+ ],
158
+ },
159
+ {
160
+ title: "test-2",
161
+ links: [
162
+ { href: "test-href-1", label: "test-label-1" },
163
+ { href: "test-href-2", label: "test-label-2" },
164
+ ],
165
+ },
166
+ ];
167
+ const el = await fixture(
168
+ html`<sgds-footer .links=${linkArray}></sgds-footer>`
169
+ );
170
+
171
+ expect(el.shadowRoot?.querySelectorAll('.footer-items>div').length).to.equal(2)
172
+ expect(el.shadowRoot?.querySelectorAll('.footer-items>div')[0].textContent).to.contain('test-1')
173
+ expect(el.shadowRoot?.querySelectorAll('.footer-items>div')[1].textContent).to.contain('test-2')
174
+ expect(el.shadowRoot?.querySelectorAll('ul.links>li>a').length).to.equal(4)
175
+ expect(el.shadowRoot?.querySelectorAll('li>a[href="test-href-1"]').length).to.equal(2)
176
+ expect(el.shadowRoot?.querySelectorAll('li>a[href="test-href-1"]')[0].textContent).to.equal('test-label-1')
177
+ expect(el.shadowRoot?.querySelectorAll('li>a[href="test-href-2"]').length).to.equal(2)
178
+ expect(el.shadowRoot?.querySelectorAll('li>a[href="test-href-2"]')[0].textContent).to.equal('test-label-2')
179
+
180
+ });
181
+ });
@@ -0,0 +1,18 @@
1
+ import generateId from "../src/utils/generateId";
2
+ import { expect } from "@open-wc/testing";
3
+ import sinon from "sinon";
4
+
5
+ describe("generateId function", () => {
6
+ sinon.stub(Math, "random").returns(1234567);
7
+
8
+ it("returns a string", () => {
9
+ expect(typeof generateId()).to.equal("string");
10
+ });
11
+ it("returns an id with the correct structure", () => {
12
+ expect(generateId()).to.equal("id-3456-sgds--");
13
+ });
14
+
15
+ it("when suffix specified , should return with suffix", () => {
16
+ expect(generateId("test", 'test')).to.equal("id-3456-sgds-test-test");
17
+ });
18
+ });
@@ -0,0 +1,316 @@
1
+ import { SgdsInput } from "../src/Input/sgds-input";
2
+ import type SgdsButton from "../src/Button/sgds-button";
3
+ import "../src/Input";
4
+ import "../src/Button";
5
+ import {
6
+ expect,
7
+ fixture,
8
+ html,
9
+ oneEvent,
10
+ waitUntil,
11
+ assert,
12
+ elementUpdated,
13
+ } from "@open-wc/testing";
14
+ import sinon from "sinon";
15
+ import { sendKeys } from "@web/test-runner-commands";
16
+
17
+ describe("sgds-input", () => {
18
+ it("is defined", () => {
19
+ const el = document.createElement("sgds-input");
20
+ assert.instanceOf(el, SgdsInput);
21
+ });
22
+ it("renders with default values", async () => {
23
+ const el = await fixture(
24
+ html`<sgds-input inputId="test-id" label="label"></sgds-input>`
25
+ );
26
+ assert.shadowDom.equal(
27
+ el,
28
+ `
29
+ <label class="form-label" for="test-id">label</label>
30
+ <input type="text" class="form-control " id="test-id" placeholder="Placeholder" aria-invalid="false">
31
+ <div class="invalid-feedback" id="test-id-invalid">default feedback</div>
32
+ `
33
+ );
34
+ });
35
+
36
+ it("should be disabled with the disabled attribute", async () => {
37
+ const el = await fixture<SgdsInput>(
38
+ html` <sgds-input disabled></sgds-input> `
39
+ );
40
+ const input = el.shadowRoot!.querySelector<HTMLInputElement>("input")!;
41
+
42
+ expect(input.disabled).to.be.true;
43
+ });
44
+
45
+ // Labels
46
+ it("should replace label value the if updated", async () => {
47
+ const el = await fixture(html`<sgds-input></sgds-input>`);
48
+ el.setAttribute("label", "Enter your name");
49
+ await elementUpdated(el);
50
+ const labelText = el.shadowRoot?.querySelector(".form-label");
51
+ expect(labelText?.textContent).to.contain("Enter your name");
52
+ });
53
+
54
+ // Hint Text
55
+ it("should render hint text element if hintText attribute is defined", async () => {
56
+ const el = await fixture(html`<sgds-input hintText="hint"></sgds-input>`);
57
+ const hintText = el.shadowRoot?.querySelector(".form-text");
58
+ el.setAttribute("hintText", "hint");
59
+ await elementUpdated(el);
60
+ expect(hintText?.textContent).to.equal("hint");
61
+ expect(hintText).to.exist;
62
+ });
63
+
64
+ // Icon
65
+ it("should render with fom-control-group if iconName attribute is defined", async () => {
66
+ const el = await fixture(
67
+ html`<sgds-input iconName="search" inputId="defaultID"></sgds-input>`
68
+ );
69
+ assert.shadowDom.equal(
70
+ el,
71
+ `
72
+ <div class="sgds form-control-group">
73
+ <span class="form-control-icon">
74
+ <sl-icon name="search"></sl-icon>
75
+ </span>
76
+ <input type="text" class="form-control " id="defaultID" placeholder="Placeholder" aria-invalid="false">
77
+ <div class="invalid-feedback" id="defaultID-invalid">default feedback</div>
78
+ </div>
79
+ `
80
+ );
81
+ });
82
+
83
+ it("updates the iconName attribute value to 'stack'", async () => {
84
+ const el = await fixture(html`<sgds-input iconName="search"></sgds-input>`);
85
+ const iconElement = el.shadowRoot?.querySelector("sl-icon");
86
+ iconElement?.setAttribute("name", "stack");
87
+ await elementUpdated(el);
88
+ expect(iconElement?.getAttribute("name")).to.equal("stack");
89
+ });
90
+
91
+ //Name
92
+ it("updates the name attribute value to 'Hello'", async () => {
93
+ const el = await fixture(html`<sgds-input></sgds-input>`);
94
+ el?.setAttribute("name", "Hello");
95
+ await elementUpdated(el);
96
+ const name = el.shadowRoot?.querySelector(".form-control");
97
+ expect(name?.getAttribute("name")).to.equal("Hello");
98
+ });
99
+
100
+ //Placeholder
101
+ it("updates the default placeholder value to 'Hello'", async () => {
102
+ const el = await fixture(html`<sgds-input></sgds-input>`);
103
+ el?.setAttribute("placeholder", "Hello");
104
+ await elementUpdated(el);
105
+ const placeHolder = el.shadowRoot?.querySelector(".form-control");
106
+ expect(placeHolder?.getAttribute("placeholder")).to.equal("Hello");
107
+ });
108
+
109
+ it("should focus the input when clicking on the label", async () => {
110
+ const el = await fixture<SgdsInput>(
111
+ html` <sgds-input label="Name"></sgds-input> `
112
+ );
113
+ const label = el.shadowRoot?.querySelector("label")!;
114
+ const submitHandler = sinon.spy();
115
+
116
+ el.addEventListener("sgds-focus", submitHandler);
117
+ (label as HTMLElement).click();
118
+ await waitUntil(() => submitHandler.calledOnce);
119
+
120
+ expect(submitHandler).to.have.been.calledOnce;
121
+ });
122
+ });
123
+ describe("when using constraint validation", () => {
124
+ it("by default, invalid and valid should be false", async () => {
125
+ const el = await fixture<SgdsInput>(html` <sgds-input></sgds-input> `);
126
+ expect(el.invalid).to.be.false;
127
+ expect(el.valid).to.be.false;
128
+ expect(el.reportValidity()).to.be.true;
129
+ });
130
+ it("when required, validation occurs upon typing ", async () => {
131
+ const el = await fixture<SgdsInput>(
132
+ html` <sgds-input required></sgds-input> `
133
+ );
134
+ expect(el.invalid).to.be.false;
135
+ expect(el.valid).to.be.false;
136
+
137
+ el.focus()
138
+ await sendKeys({ type: "s" });
139
+ await el.updateComplete;
140
+
141
+ expect(el.value).to.equal('s')
142
+ expect(el.invalid).to.be.false;
143
+ expect(el.valid).to.be.true;
144
+ expect(el.reportValidity()).to.be.true;
145
+
146
+ await sendKeys({press: 'Backspace'})
147
+ await el.updateComplete;
148
+ expect(el.value).to.equal('')
149
+
150
+ expect(el.invalid).to.be.true;
151
+ expect(el.valid).to.be.false;
152
+ expect(el.reportValidity()).to.be.false;
153
+ });
154
+
155
+ it('should be invalid when the pattern does not match', async () => {
156
+ const el = await fixture<SgdsInput>(html` <sgds-input pattern="failtest" value="fail"></sgds-input> `);
157
+ expect(el.invalid).to.be.false;
158
+ expect(el.valid).to.be.false;
159
+ expect(el.reportValidity()).to.be.false;
160
+
161
+ await sendKeys({type: 'tes'})
162
+ await el.updateComplete
163
+ expect(el.value).to.equal('failtes')
164
+ expect(el.invalid).to.be.true;
165
+ expect(el.valid).to.be.false;
166
+ expect(el.reportValidity()).to.be.false;
167
+
168
+ await sendKeys({type: 't'})
169
+ await el.updateComplete
170
+ expect(el.value).to.equal('failtest')
171
+ expect(el.invalid).to.be.false;
172
+ expect(el.valid).to.be.true;
173
+ expect(el.reportValidity()).to.be.true;
174
+
175
+ await sendKeys({press: 'Backspace'})
176
+ await el.updateComplete
177
+ expect(el.value).to.equal('failtes')
178
+ expect(el.invalid).to.be.true;
179
+ expect(el.valid).to.be.false;
180
+ expect(el.reportValidity()).to.be.false;
181
+
182
+ });
183
+
184
+ it("should be invalid when required and disabled is removed", async () => {
185
+ const el = await fixture<SgdsInput>(
186
+ html` <sgds-input disabled required></sgds-input> `
187
+ );
188
+ el.disabled = false;
189
+ await el.updateComplete;
190
+ expect(el.invalid).to.be.true;
191
+ });
192
+ });
193
+
194
+ describe("when calling HTMLFormElement.reportValidity()", () => {
195
+ it("should be invalid when the input is empty and form.reportValidity() is called", async () => {
196
+ const form = await fixture<HTMLFormElement>(html`
197
+ <form>
198
+ <sgds-input required value=""></sgds-input>
199
+ </form>
200
+ `);
201
+
202
+ expect(form.reportValidity()).to.be.false;
203
+ });
204
+
205
+ it("should be valid when the input is empty, reportValidity() is called, and the form has novalidate", async () => {
206
+ const form = await fixture<HTMLFormElement>(html`
207
+ <form novalidate>
208
+ <sgds-input required value=""></sgds-input>
209
+ </form>
210
+ `);
211
+
212
+ expect(form.reportValidity()).to.be.true;
213
+ });
214
+
215
+ it("fires sgds-input event when value is entered", async () => {
216
+ const el = await fixture<SgdsInput>(html` <sgds-input></sgds-input> `);
217
+ const inputHandler = sinon.spy();
218
+ el.focus();
219
+ el.addEventListener("sgds-input", inputHandler);
220
+ await sendKeys({ press: "A" });
221
+ waitUntil(() => inputHandler.calledOnce);
222
+ expect(inputHandler).to.have.been.calledOnce;
223
+ });
224
+ });
225
+
226
+ describe("when submitting a form", () => {
227
+ it("should submit the form when pressing enter in a form without a submit button", async () => {
228
+ const form = await fixture<HTMLFormElement>(
229
+ html` <form><sgds-input></sgds-input></form> `
230
+ );
231
+ const input = form.querySelector<SgdsInput>("sgds-input")!;
232
+ const submitHandler = sinon.spy((event: SubmitEvent) =>
233
+ event.preventDefault()
234
+ );
235
+
236
+ form.addEventListener("submit", submitHandler);
237
+ input.focus();
238
+ await sendKeys({ press: "Enter" });
239
+ await waitUntil(() => submitHandler.calledOnce);
240
+
241
+ expect(submitHandler).to.have.been.calledOnce;
242
+ });
243
+
244
+ it("should submit the form when pressing enter in a form with a submit button", async () => {
245
+ const form = await fixture<HTMLFormElement>(html`
246
+ <form>
247
+ <sgds-input></sgds-input>
248
+ <sgds-button type="submit"></sgds-button>
249
+ </form>
250
+ `);
251
+ const input = form.querySelector<SgdsInput>("sgds-input")!;
252
+ const submitButton = form.querySelector<SgdsButton>("sgds-button")!;
253
+ const submitHandler = sinon.spy((event: SubmitEvent) =>
254
+ event.preventDefault()
255
+ );
256
+
257
+ form.addEventListener("submit", submitHandler);
258
+ submitButton.click();
259
+ await waitUntil(() => submitHandler.calledOnce);
260
+ expect(submitHandler).to.have.been.calledOnce;
261
+ });
262
+
263
+ it("should prevent submission when pressing enter in an input and canceling the keydown event", async () => {
264
+ const form = await fixture<HTMLFormElement>(
265
+ html` <form><sgds-input></sgds-input></form> `
266
+ );
267
+ const input = form.querySelector<SgdsInput>("sgds-input")!;
268
+ const submitHandler = sinon.spy((event: SubmitEvent) =>
269
+ event.preventDefault()
270
+ );
271
+ const keydownHandler = sinon.spy((event: KeyboardEvent) => {
272
+ if (event.key === "Enter") {
273
+ event.preventDefault();
274
+ }
275
+ });
276
+
277
+ form.addEventListener("submit", submitHandler);
278
+ input.addEventListener("keydown", keydownHandler);
279
+ input.focus();
280
+ await sendKeys({ press: "Enter" });
281
+ await waitUntil(() => keydownHandler.calledOnce);
282
+
283
+ expect(keydownHandler).to.have.been.calledOnce;
284
+ expect(submitHandler).to.not.have.been.called;
285
+ });
286
+ });
287
+
288
+ describe("when resetting a form", () => {
289
+ it("should reset the element to its initial value", async () => {
290
+ const form = await fixture<HTMLFormElement>(html`
291
+ <form>
292
+ <sgds-input name="a" value="test"></sgds-input>
293
+ <sgds-button type="reset">Reset</sgds-button>
294
+ </form>
295
+ `);
296
+ const button = form.querySelector<SgdsButton>("sgds-button")!;
297
+ const input = form.querySelector<SgdsInput>("sgds-input")!;
298
+ input.value = "1234";
299
+
300
+ await input.updateComplete;
301
+
302
+ setTimeout(() => button.click());
303
+ await oneEvent(form, "reset");
304
+ await input.updateComplete;
305
+
306
+ expect(input.value).to.equal("test");
307
+
308
+ input.defaultValue = "";
309
+
310
+ setTimeout(() => button.click());
311
+ await oneEvent(form, "reset");
312
+ await input.updateComplete;
313
+
314
+ expect(input.value).to.equal("");
315
+ });
316
+ });
@@ -0,0 +1,38 @@
1
+ import "../mocks/link";
2
+ import { MockLink } from "../mocks/link";
3
+ import { fixture, assert, expect } from "@open-wc/testing";
4
+ import { html } from "lit";
5
+
6
+ describe("link-element", () => {
7
+ it("renders with default values", async () => {
8
+ const el = await fixture<MockLink>(html`<mock-link></mock-link>`);
9
+ assert.shadowDom.equal(
10
+ el,
11
+ ` <li>
12
+ <a
13
+ aria-disabled="false"
14
+ class="nav-link"
15
+ href=""
16
+ >
17
+ <slot>
18
+ </slot>
19
+ </a>
20
+ </li>
21
+ `
22
+ );
23
+ });
24
+ it("href prop is forwarded to a tag href attr", async () => {
25
+ const el = await fixture(html`<mock-link href="#">test</mock-link>`);
26
+ expect(el.shadowRoot?.querySelector("a")).to.have.attribute("href", "#");
27
+ });
28
+ it("active prop is forwarded to <a> class", async () => {
29
+ const el = await fixture(html`<mock-link active>test</mock-link>`);
30
+ expect(el.shadowRoot?.querySelector("a")).to.have.class("active");
31
+ });
32
+ it('disabled prop apply disable props and attr to anchor element', async() => {
33
+ const el = await fixture(html`<mock-link disabled>test</mock-link>`);
34
+ expect(el.shadowRoot?.querySelector("a")).to.have.class("disabled");
35
+ expect(el.shadowRoot?.querySelector("a")).to.have.attribute("disabled");
36
+ expect(el.shadowRoot?.querySelector("a")).to.have.attribute("aria-disabled", "true");
37
+ })
38
+ });