Skip to content

Commit

Permalink
clean up test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
joelhawksley committed Nov 25, 2024
1 parent 47113c1 commit 84bda82
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 22 deletions.
7 changes: 3 additions & 4 deletions custom-elements.json
Original file line number Diff line number Diff line change
Expand Up @@ -201,19 +201,18 @@
},
{
"kind": "field",
"name": "validateAfterFirstBlur",
"name": "onlyValidateOnBlur",
"type": {
"text": "boolean"
},
"readonly": true
},
{
"kind": "field",
"name": "shouldValidate",
"name": "validateOnKeystroke",
"type": {
"text": "boolean"
},
"readonly": true
}
}
],
"attributes": [
Expand Down
8 changes: 4 additions & 4 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ <h2 tabindex="-1" id="success1" class="success" hidden>Your submission was succe
<button value="1" name="form">submit</button>
</form>

<!-- <h2>Form that has custom validity messages</h2>
<h2>Form that has custom validity messages</h2>
<p>Input 422 for an error response.</p>
<h2 tabindex="-1" id="success2" class="success" hidden>Your submission was successful</h2>
<form id="custom">
Expand All @@ -34,13 +34,13 @@ <h2 tabindex="-1" id="success2" class="success" hidden>Your submission was succe
<p id="state2" aria-atomic="true" aria-live="polite" class="state"></p>
</auto-check>
<button value="2" name="form">submit</button>
</form> -->
</form>

<h2>validate-after-first-blur</h2>
<h2>only-validate-on-blur</h2>
<h2 tabindex="-1" id="success3" class="success" hidden>Your submission was successful</h2>
<form>
<label for="simple-field2">Desired username*:</label>
<auto-check csrf="foo" src="/demo" required validate-after-first-blur>
<auto-check csrf="foo" src="/demo" required only-validate-on-blur>
<input id="simple-field2" autofocus name="foo" required aria-describedby="state3" />
<p id="state3" aria-atomic="true" aria-live="polite" class="state"></p>
</auto-check>
Expand Down
38 changes: 26 additions & 12 deletions src/auto-check-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ export class AutoCheckElement extends HTMLElement {
const input = this.input
if (!input) return

if (!this.validateAfterFirstBlur) {
this.setAttribute('should-validate', '')
if (!this.onlyValidateOnBlur) {
this.setAttribute('validate-on-keystroke', '')
}

const checker = debounce(check.bind(null, this), 300)
Expand Down Expand Up @@ -192,13 +192,21 @@ export class AutoCheckElement extends HTMLElement {
return AllowedHttpMethods[this.getAttribute('http-method') as keyof typeof AllowedHttpMethods] || 'POST'
}

get validateAfterFirstBlur(): boolean {
const value = this.getAttribute('validate-after-first-blur')
get onlyValidateOnBlur(): boolean {
const value = this.getAttribute('only-validate-on-blur')
return value === 'true' || value === ''
}

get shouldValidate(): boolean {
const value = this.getAttribute('should-validate')
set validateOnKeystroke(enabled: boolean) {
if (enabled) {
this.setAttribute('validate-on-keystroke', '')
} else {
this.removeAttribute('validate-on-keystroke')
}
}

get validateOnKeystroke(): boolean {
const value = this.getAttribute('validate-on-keystroke')
return value === 'true' || value === ''
}
}
Expand All @@ -213,9 +221,9 @@ function handleChange(checker: () => void, event: Event) {
if (input.value.length === 0) return

if (
(event.type !== 'blur' && !autoCheckElement.validateAfterFirstBlur) || // Existing default behavior
(event.type === 'blur' && autoCheckElement.validateAfterFirstBlur) || // Only validate on blur if validate-after-first-blur is set
(autoCheckElement.validateAfterFirstBlur && autoCheckElement.shouldValidate) // Only validate on key inputs in validate-after-first-blur mode if should-validate is set (when input is invalid)
(event.type !== 'blur' && !autoCheckElement.onlyValidateOnBlur) || // Existing default behavior
(event.type === 'blur' && autoCheckElement.onlyValidateOnBlur) || // Only validate on blur if only-validate-on-blur is set
(autoCheckElement.onlyValidateOnBlur && autoCheckElement.validateOnKeystroke) // Only validate on key inputs in only-validate-on-blur mode if validate-on-keystroke is set (when input is invalid)
) {
checker()
setLoadingState(event)
Expand Down Expand Up @@ -333,12 +341,18 @@ async function check(autoCheckElement: AutoCheckElement) {
if (autoCheckElement.required) {
input.setCustomValidity('')
}
if (autoCheckElement.validateAfterFirstBlur) {
autoCheckElement.removeAttribute('should-validate')
// We do not have good test coverage for this code path.
// To test, ensure that the input only validates on blur
// once it has been "healed" by a valid input after
// previously being in an invalid state.
if (autoCheckElement.onlyValidateOnBlur) {
autoCheckElement.validateOnKeystroke = false
}
input.dispatchEvent(new AutoCheckSuccessEvent(response.clone()))
} else {
autoCheckElement.setAttribute('should-validate', '')
if (autoCheckElement.onlyValidateOnBlur) {
autoCheckElement.validateOnKeystroke = true
}
const event = new AutoCheckErrorEvent(response.clone())
input.dispatchEvent(event)
if (autoCheckElement.required) {
Expand Down
37 changes: 35 additions & 2 deletions test/auto-check.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ describe('auto-check element', function () {
})
})

describe('when validate-after-first-blur is true', function () {
describe('when only-validate-on-blur is true', function () {
let checker
let input

beforeEach(function () {
const container = document.createElement('div')
container.innerHTML = `
<auto-check csrf="foo" src="/success" validate-after-first-blur>
<auto-check csrf="foo" src="/success" only-validate-on-blur>
<input>
</auto-check>`
document.body.append(container)
Expand All @@ -45,6 +45,35 @@ describe('auto-check element', function () {
assert.deepEqual(events, [])
})

it('does not emit on blur if input is blank', async function () {
const events = []
input.addEventListener('auto-check-start', event => events.push(event.type))
triggerBlur(input)
assert.deepEqual(events, [])
})

it('emits on blur', async function () {
const events = []
input.addEventListener('auto-check-start', event => events.push(event.type))
triggerInput(input, 'hub')
triggerBlur(input)
assert.deepEqual(events, ['auto-check-start'])
})

it('emits on input change if input is invalid after blur', async function () {
const events = []
input.addEventListener('auto-check-start', event => events.push(event.type))

checker.src = '/fail'
triggerInput(input, 'hub')
triggerBlur(input)
await once(input, 'auto-check-complete')
triggerInput(input, 'hub2')
triggerInput(input, 'hub3')

assert.deepEqual(events, ['auto-check-start', 'auto-check-start', 'auto-check-start'])
})

afterEach(function () {
document.body.innerHTML = ''
checker = null
Expand Down Expand Up @@ -361,3 +390,7 @@ function triggerInput(input, value) {
input.value = value
return input.dispatchEvent(new InputEvent('input'))
}

function triggerBlur(input) {
return input.dispatchEvent(new FocusEvent('blur'))
}

0 comments on commit 84bda82

Please sign in to comment.