brut-js 0.0.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/.projections.json +10 -0
- package/CODE_OF_CONDUCT.txt +99 -0
- package/LICENSE.txt +370 -0
- package/README.md +118 -0
- package/package.json +30 -0
- package/specs/AjaxSubmit.spec.js +241 -0
- package/specs/Autosubmit.spec.js +127 -0
- package/specs/ConfirmSubmit.spec.js +193 -0
- package/specs/ConstraintViolationMessage.spec.js +33 -0
- package/specs/ConstraintViolationMessages.spec.js +27 -0
- package/specs/Form.spec.js +136 -0
- package/specs/I18nTranslation.spec.js +19 -0
- package/specs/LocaleDetection.spec.js +22 -0
- package/specs/Message.spec.js +15 -0
- package/specs/Tabs.spec.js +41 -0
- package/specs/config/asset_metadata.json +7 -0
- package/specs/public/js/bundle.js +1284 -0
- package/specs/public/js/bundle.js.map +7 -0
- package/src/AjaxSubmit.js +364 -0
- package/src/Autosubmit.js +61 -0
- package/src/BaseCustomElement.js +261 -0
- package/src/ConfirmSubmit.js +114 -0
- package/src/ConfirmationDialog.js +141 -0
- package/src/ConstraintViolationMessage.js +101 -0
- package/src/ConstraintViolationMessages.js +90 -0
- package/src/Form.js +117 -0
- package/src/I18nTranslation.js +59 -0
- package/src/LocaleDetection.js +93 -0
- package/src/Logger.js +90 -0
- package/src/Message.js +55 -0
- package/src/RichString.js +113 -0
- package/src/Tabs.js +167 -0
- package/src/appForTestingOnly.js +15 -0
- package/src/index.js +119 -0
- package/src/testing/index.js +348 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { withHTML } from "../src/testing/index.js"
|
|
2
|
+
|
|
3
|
+
describe("<brut-form>", () => {
|
|
4
|
+
withHTML(`
|
|
5
|
+
<brut-form>
|
|
6
|
+
<form>
|
|
7
|
+
<label>
|
|
8
|
+
<input required type="text" name="text">
|
|
9
|
+
<brut-constraint-violation-messages>
|
|
10
|
+
</brut-constraint-violation-messages>
|
|
11
|
+
</label>
|
|
12
|
+
<label>
|
|
13
|
+
<input required type="number" name="number">
|
|
14
|
+
<brut-constraint-violation-messages>
|
|
15
|
+
</brut-constraint-violation-messages>
|
|
16
|
+
</label>
|
|
17
|
+
<input type="submit">Save</input>
|
|
18
|
+
<brut-ajax-submit>
|
|
19
|
+
<button>Save Ajaxily</button>
|
|
20
|
+
</brut-ajax-submit>
|
|
21
|
+
</form>
|
|
22
|
+
</brut-form>
|
|
23
|
+
`).test("sets data-submitted on submit with invalid form + updates messages", ({window,document,assert}) => {
|
|
24
|
+
|
|
25
|
+
const brutForm = document.querySelector("brut-form")
|
|
26
|
+
const form = brutForm.querySelector("form")
|
|
27
|
+
const button = form.querySelector("input[type=submit]")
|
|
28
|
+
const textFieldLabel = form.querySelector("label:has(input[type=text])")
|
|
29
|
+
const numberFieldLabel = form.querySelector("label:has(input[type=number])")
|
|
30
|
+
|
|
31
|
+
let submitted = false
|
|
32
|
+
let gotInvalid = false
|
|
33
|
+
let gotValid = false
|
|
34
|
+
|
|
35
|
+
form.addEventListener("submit", (event) => {
|
|
36
|
+
event.preventDefault()
|
|
37
|
+
submitted = true
|
|
38
|
+
})
|
|
39
|
+
brutForm.addEventListener("brut:valid", () => {
|
|
40
|
+
gotValid = true
|
|
41
|
+
})
|
|
42
|
+
brutForm.addEventListener("brut:invalid", () => {
|
|
43
|
+
gotInvalid = true
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
button.click()
|
|
47
|
+
|
|
48
|
+
assert(!submitted)
|
|
49
|
+
assert(!gotValid)
|
|
50
|
+
assert(gotInvalid)
|
|
51
|
+
assert(form.dataset["submitted"] != null)
|
|
52
|
+
|
|
53
|
+
let error = textFieldLabel.querySelector("brut-constraint-violation-message[key='general.cv.fe.valueMissing']")
|
|
54
|
+
assert(error)
|
|
55
|
+
error = numberFieldLabel.querySelector("brut-constraint-violation-message[key='general.cv.fe.valueMissing']")
|
|
56
|
+
assert(error)
|
|
57
|
+
|
|
58
|
+
const textField = textFieldLabel.querySelector("input")
|
|
59
|
+
textField.value = "Some Value"
|
|
60
|
+
textField.dispatchEvent(new window.Event("input"))
|
|
61
|
+
|
|
62
|
+
submitted = false
|
|
63
|
+
gotInvalid = false
|
|
64
|
+
gotValid = false
|
|
65
|
+
|
|
66
|
+
button.click()
|
|
67
|
+
|
|
68
|
+
assert(!submitted)
|
|
69
|
+
assert(!gotValid)
|
|
70
|
+
assert(gotInvalid)
|
|
71
|
+
assert(form.dataset["submitted"] != null)
|
|
72
|
+
|
|
73
|
+
error = textFieldLabel.querySelector("brut-constraint-violation-message[key='general.cv.fe.valueMissing']")
|
|
74
|
+
assert(!error)
|
|
75
|
+
error = numberFieldLabel.querySelector("brut-constraint-violation-message[key='general.cv.fe.valueMissing']")
|
|
76
|
+
assert(error)
|
|
77
|
+
|
|
78
|
+
const numberField = numberFieldLabel.querySelector("input")
|
|
79
|
+
numberField.value = "99"
|
|
80
|
+
numberField.dispatchEvent(new window.Event("input"))
|
|
81
|
+
|
|
82
|
+
submitted = false
|
|
83
|
+
gotInvalid = false
|
|
84
|
+
gotValid = false
|
|
85
|
+
|
|
86
|
+
button.click()
|
|
87
|
+
|
|
88
|
+
assert(submitted)
|
|
89
|
+
}).test("Works with ajax submissions to keep errors consistent", ({window,document,assert}) => {
|
|
90
|
+
|
|
91
|
+
const brutForm = document.querySelector("brut-form")
|
|
92
|
+
const form = brutForm.querySelector("form")
|
|
93
|
+
const ajaxSubmit = form.querySelector("brut-ajax-submit")
|
|
94
|
+
const textFieldLabel = form.querySelector("label:has(input[type=text])")
|
|
95
|
+
const numberFieldLabel = form.querySelector("label:has(input[type=number])")
|
|
96
|
+
|
|
97
|
+
const textField = textFieldLabel.querySelector("input")
|
|
98
|
+
textField.value = "Some Value"
|
|
99
|
+
textField.dispatchEvent(new window.Event("input"))
|
|
100
|
+
|
|
101
|
+
const numberField = numberFieldLabel.querySelector("input")
|
|
102
|
+
numberField.value = "99"
|
|
103
|
+
numberField.dispatchEvent(new window.Event("input"))
|
|
104
|
+
|
|
105
|
+
let submitted = false
|
|
106
|
+
let gotInvalid = false
|
|
107
|
+
let gotValid = false
|
|
108
|
+
|
|
109
|
+
form.addEventListener("submit", (event) => {
|
|
110
|
+
event.preventDefault()
|
|
111
|
+
submitted = true
|
|
112
|
+
})
|
|
113
|
+
brutForm.addEventListener("brut:valid", () => {
|
|
114
|
+
gotValid = true
|
|
115
|
+
})
|
|
116
|
+
brutForm.addEventListener("brut:invalid", () => {
|
|
117
|
+
gotInvalid = true
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
ajaxSubmit.dispatchEvent(new window.Event("brut:submitinvalid"))
|
|
121
|
+
|
|
122
|
+
assert(!submitted)
|
|
123
|
+
assert(!gotValid)
|
|
124
|
+
assert(gotInvalid)
|
|
125
|
+
|
|
126
|
+
submitted = false
|
|
127
|
+
gotInvalid = false
|
|
128
|
+
gotValid = false
|
|
129
|
+
|
|
130
|
+
ajaxSubmit.dispatchEvent(new window.Event("brut:submitok"))
|
|
131
|
+
|
|
132
|
+
assert(!submitted)
|
|
133
|
+
assert(gotValid)
|
|
134
|
+
assert(!gotInvalid)
|
|
135
|
+
})
|
|
136
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { withHTML } from "../src/testing/index.js"
|
|
2
|
+
|
|
3
|
+
describe("<brut-i18n-translation>", () => {
|
|
4
|
+
withHTML(`
|
|
5
|
+
<brut-i18n-translation key="greeting" value="Hello %{username}"></brut-i18n-translation>
|
|
6
|
+
`).test("Produces a translation", ({document,assert}) => {
|
|
7
|
+
const element = document.querySelector("brut-i18n-translation")
|
|
8
|
+
const translation = element.translation({username: "Pat"})
|
|
9
|
+
assert.equal(translation,"Hello Pat")
|
|
10
|
+
}).test("Ignores replacements not in the translation", ({document,assert}) => {
|
|
11
|
+
const element = document.querySelector("brut-i18n-translation")
|
|
12
|
+
const translation = element.translation({username: "Pat", email: "pat@example.com"})
|
|
13
|
+
assert.equal(translation,"Hello Pat")
|
|
14
|
+
}).test("Missing replacements raise an error", ({document,assert}) => {
|
|
15
|
+
const element = document.querySelector("brut-i18n-translation")
|
|
16
|
+
const code = () => { element.translation() }
|
|
17
|
+
assert.throws(code,/reading 'username'/)
|
|
18
|
+
})
|
|
19
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { withHTML, readRequestBodyIntoJSON } from "../src/testing/index.js"
|
|
2
|
+
|
|
3
|
+
describe("<brut-locale-detection>", () => {
|
|
4
|
+
withHTML(`
|
|
5
|
+
<brut-locale-detection timeout-before-ping-ms="0" url="http://example.net/locale"></brut-locale-detection>
|
|
6
|
+
`).onFetch( "/locale", [
|
|
7
|
+
{ then: { status: 200 }},
|
|
8
|
+
]
|
|
9
|
+
).test("Receives the locale and timeZone from the browser", ({document,assert,fetchRequests}) => {
|
|
10
|
+
|
|
11
|
+
assert.equal(1,fetchRequests.length)
|
|
12
|
+
return readRequestBodyIntoJSON(fetchRequests[0]).then( (json) => {
|
|
13
|
+
assert.equal(json["locale"],"en-US")
|
|
14
|
+
assert.equal(json["timeZone"],"UTC")
|
|
15
|
+
})
|
|
16
|
+
})
|
|
17
|
+
withHTML(`
|
|
18
|
+
<brut-locale-detection locale-from-server="en-US" timezone-from-server="UTC" timeout-before-ping-ms="0" url="http://example.net/locale"></brut-locale-detection>
|
|
19
|
+
`).test("makes no calls to fetch", ({document,assert,fetchRequests}) => {
|
|
20
|
+
assert.equal(fetchRequests.length,0)
|
|
21
|
+
})
|
|
22
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { withHTML } from "../src/testing/index.js"
|
|
2
|
+
|
|
3
|
+
describe("<brut-message>", () => {
|
|
4
|
+
withHTML(`
|
|
5
|
+
<brut-i18n-translation key="greeting" value="Hello Everyone!"></brut-i18n-translation>
|
|
6
|
+
<brut-message key="greeting"></brut-message>
|
|
7
|
+
<brut-message key="non-existent"></brut-message>
|
|
8
|
+
`).test("Inserts the translation", ({document,assert}) => {
|
|
9
|
+
const element = document.querySelector("brut-message[key=greeting]")
|
|
10
|
+
assert.equal(element.textContent,"Hello Everyone!")
|
|
11
|
+
}).test("Does nothing if the key is not found", ({document,assert}) => {
|
|
12
|
+
const element = document.querySelector("brut-message[key=non-existent]")
|
|
13
|
+
assert.equal(element.textContent,"")
|
|
14
|
+
})
|
|
15
|
+
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { withHTML } from "../src/testing/index.js"
|
|
2
|
+
|
|
3
|
+
describe("<brut-tabs>", () => {
|
|
4
|
+
withHTML(`
|
|
5
|
+
<brut-tabs tab-selection-pushes-and-restores-state>
|
|
6
|
+
<a role="tab" aria-selected="true" tabindex="0" aria-controls="inbox-panel" id="inbox-tab"
|
|
7
|
+
href="?tab=inbox">Inbox</a>
|
|
8
|
+
<a role="tab" aria-selected="false" tabindex="-1" aria-controls="drafts-panel" id="drafts-tab"
|
|
9
|
+
href="?tab=drafts">Drafts</a>
|
|
10
|
+
<a role="tab" aria-selected="false" tabindex="-1" aria-controls="spam-panel" id="spam-tab"
|
|
11
|
+
href="?tab=spam">Spam</a>
|
|
12
|
+
</brut-tabs>
|
|
13
|
+
<section role="tabpanel" tabindex="0" id="inbox-panel">
|
|
14
|
+
<h3>Inbox</h3>
|
|
15
|
+
</section>
|
|
16
|
+
<section role="tabpanel" tabindex="0" id="drafts-panel" hidden>
|
|
17
|
+
<h3>Drafts</h3>
|
|
18
|
+
</section>
|
|
19
|
+
<section role="tabpanel" tabindex="0" id="spam-panel" hidden>
|
|
20
|
+
<h3>Spam</h3>
|
|
21
|
+
</section>
|
|
22
|
+
`).test("Clicking on a tab sets all attributes properly", ({document,window,assert}) => {
|
|
23
|
+
|
|
24
|
+
const selectedTab = document.querySelector("[role=tab][aria-selected=true]")
|
|
25
|
+
const selectedTabPanel = document.getElementById(selectedTab.getAttribute("aria-controls"))
|
|
26
|
+
|
|
27
|
+
const unselectedTab = document.querySelector("[role=tab][aria-selected=false]")
|
|
28
|
+
const unselectedTabPanel = document.getElementById(unselectedTab.getAttribute("aria-controls"))
|
|
29
|
+
|
|
30
|
+
unselectedTab.click()
|
|
31
|
+
|
|
32
|
+
assert.equal(selectedTab.getAttribute("aria-selected"),"false")
|
|
33
|
+
assert.equal(selectedTab.getAttribute("tabindex"),"-1")
|
|
34
|
+
assert(selectedTabPanel.getAttribute("hidden") != null)
|
|
35
|
+
|
|
36
|
+
assert.equal(unselectedTab.getAttribute("aria-selected"),"true")
|
|
37
|
+
assert.equal(unselectedTab.getAttribute("tabindex"),"0")
|
|
38
|
+
assert(unselectedTabPanel.getAttribute("hidden") == null)
|
|
39
|
+
assert.equal(window.history.state["tabId"],unselectedTab.getAttribute("id"))
|
|
40
|
+
})
|
|
41
|
+
})
|