Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Component Testing] checkValidity not working on custom input elements #19201

Open
TheDutchCoder opened this issue Dec 2, 2021 · 6 comments
Open
Labels
pkg/driver This is due to an issue in the packages/driver directory type: enhancement Requested enhancement of existing feature

Comments

@TheDutchCoder
Copy link

TheDutchCoder commented Dec 2, 2021

Current behavior

When checking checkValidity inside of a custom component that uses an input, the check will always return true, even when it's invalid.

This might be due to attributes not properly propagating from TSX?

ChalkInput is a Vue3 component, basically:

<template>
  <div>
    <label>Label</label>
    <input type="text" @focus="checkValid" @blur="checkValid" class="text-green focus:text-red" />
  </div>
</template>

<script lang="ts>
export default {
  setup () {
    const checkValid = (e) => {
      console.log(e.target.checkValidity()) // will always trigger true
    }
  }

  return { checkValid }
}
</script>
    mount(() =>
      <div class="p-10">
        <ChalkInput v-model={ text.value } required min-length="4"></ChalkInput>
      </div>
    )
    // `min-length` appears in the DOM, but is never validated when typing

    cy.get('#test-input')
      .trigger('focus') // never natively focusses the element
      .type('huh') // typing works
      .trigger('blur') // never natively blurs the element

    // console will show validity is passing while typing, even though `required` and `min-length` are defined on the input

It's almost as if events aren't sent natively from the element, because their handlers work, but the input is never actually focussed (easy to test with Tailwind classes like focus:text-red) and validity is never actually checked. Are certain things (like attributes) somehow stubbed?

When I manually input things in the component (inside of Cypress), everything works just as expected, so it's an internal issue I think.

Desired behavior

Native (input) events to work like in the browser.

Test code to reproduce

Component:

<template>
  <div>
    <label>Label</label>
    <input type="text" class="text-green focus:text-red" />
  </div>
</template>

Test:

import { mount } from '@cypress/vue'
import ChalkInput from '../input.vue'
import { ref } from 'vue'

const getInput = () => cy.get('[data-testid="chalk-input"]')

describe('ChalkInput', () => {
  it('focusses', () => {
    const text = ref('')

    mount(() =>
      <div class="p-10">
        <ChalkInput></ChalkInput>
      </div>
    )

    getInput()
      .trigger('focus')
      .type('hello') // `hello` should appear, but text will be green
  })
})

Cypress Version

9.1.0

Other

No response

@TheDutchCoder
Copy link
Author

TheDutchCoder commented Dec 2, 2021

Even better test-case:

    const text = ref('')
    const test = (e) => {
      console.log(e.target.checkValidity())
    }

    mount(() => <input type="text" required minlength="4" id="test-input" onInput={ test } />)

    cy.get('#test-input')
      .type('h') // this isn't valid, but somehow it logs `true`

@TheDutchCoder
Copy link
Author

I guess this discussion is relevant: https://stackoverflow.com/questions/66896018/html-input-checkvalidity-always-returns-true-even-with-minlength-violations

And it seems to point to the issue being that JS is interacting with the field, not a user. I don't even know if there's a real way around this then.

@TheDutchCoder
Copy link
Author

Alright, using pattern=".{4,}" works, so I guess this is just an API limitation.
Maybe we can add this to the docs somewhere?

@TheDutchCoder
Copy link
Author

Update: pattern isn't supported on textarea, so this bug actually prevents people from checking if (custom) validators run properly.

@JessicaSachs
Copy link
Contributor

JessicaSachs commented Mar 17, 2022

👋🏻 Thanks for the awesome write up @TheDutchCoder. Since you were able to isolate this bug in the driver instead of in the component testing mount layer, can you provide a minimal reproduction with e2e and we can re-purpose this issue to track the Cypress driver bug in checkValidity?

https://github.com/cypress-io/cypress-test-tiny

@lmiller1990 lmiller1990 added CT Issue related to component testing and removed component testing labels Aug 15, 2022
@lmiller1990 lmiller1990 added pkg/driver This is due to an issue in the packages/driver directory and removed CT Issue related to component testing labels Feb 22, 2023
@lmiller1990
Copy link
Contributor

I guess this discussion is relevant: https://stackoverflow.com/questions/66896018/html-input-checkvalidity-always-returns-true-even-with-minlength-violations
And it seems to point to the issue being that JS is interacting with the field, not a user. I don't even know if there's a real way around this then.

This is the crux of the issue - HTML validations are ignored when using JS to update the value in <input>, etc. Validations are for humans typing - not programmatically.

You could try Cypress Real Events. Other than this, I don't expect this behavior is something we will be changing in the future. When you hit submit, the default HTML validation (or your own JS validation) should trigger, though, so if you are using <form> correctly, it should still be impossible to submit an invalid form.

@lmiller1990 lmiller1990 added the type: enhancement Requested enhancement of existing feature label Feb 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg/driver This is due to an issue in the packages/driver directory type: enhancement Requested enhancement of existing feature
Projects
None yet
Development

No branches or pull requests

4 participants