reactjs - dom-testing-library veya react-testing-library'de input değerini test etmenin en iyi yolu


dom-testing-library/react-testing-library içinde bir <input> öğesinin değerini test etmenin en iyi yolu nedir?

Kullandığım yaklaşım, ham giriş öğesini kendisiyle closest() yöntemi aracılığıyla almak, bu da bana value özniteliğine doğrudan erişim sağlamak:

const input = getByLabelText("Some Label")
expect(input.closest("input").value).toEqual("Some Value")

Doğrudan HTML özniteliklerine erişmeden bunu yapabileceğim bir yol olmasını umuyordum. Test kütüphanesinin ruhuna uygun gibi görünmüyordu. Belki jest-dom toHaveTextContent eşleyicisi gibi bir şey:

const input = getByLabelText("Some Label")
expect(input).toHaveTextContent("Some Value")

GÜNCELLE

Yorumlarda yapılan isteğe dayanarak, giriş kutusundaki değeri test etme ihtiyacı hissettiğim bir durumu gösteren bir kod örneği burada.

Bu, uygulamamda oluşturduğum modal bileşenin basitleştirilmiş bir versiyonudur. Yani, son derece basitleştirilmiş. Buradaki temel fikir, modalin açıldığında girdinin bir string prop'a dayalı olarak önceden doldurulmuş şekilde gelmesi. Kullanıcı bu girdiyi özgürce düzenleyebilir ve bir düğmeye basarak gönderebilir. Ancak, kullanıcı modalı kapatıp tekrar açarsa, metnin o orijinal string prop'a sıfırlanmasını istiyorum. Bunun için bir test yazdım çünkü modalın önceki bir versiyonu girdi değerini sıfırlamıyordu.

Bunu TypeScript ile yazıyorum, böylece her prop'un türleri çok net olsun.

interface Props {
  onClose: () => void
  isOpen: boolean
  initialValue: string
}

export default function MyModal({ onClose, isOpen, initialValue }) {
  const [inputValue, setInputValue] = useState(initialValue)

  // useEffect does the reset!
  useEffect(() => {
    if (!isOpen) {
      setNameInput(initialValue)
    }
  }, [isOpen, initialValue])

  return (
    <SomeExternalLibraryModal isOpen={isOpen} onClose={onClose}>
      <form>
        <input
          value={inputValue}
          onChange={(e: ChangeEvent<HTMLInputElement>) =>
            setInputValue(e.target.value)
          }
        />
        <button onClick={onClose}>Cancel</button>
      </form>
    </SomeExternalLibraryModal>
  )
}

Cevap #1

Bu test kütüphanesinin sizin test etmenizi istediği şekilde test etme yönteminizden şüphelenmeniz doğru. Bu soruya en basit cevap, getByDisplayValue sorgusunu kullanmak olurdu. Bu sorgu, bulmaya çalıştığınız değere sahip bir input, textarea veya select öğesi arayacaktır. Örneğin, bileşeninizi örnek alırsak, inputValue='test' olduğunu doğrulamaya çalışıyor olsaydım, şöyle arardım

expect(screen.getByDisplayValue('test')).toBeInTheDocument();

Yapmanız gereken tek şey bu. Testinizin yalnızca MyModal bileşenini render ettiğini varsayıyorum. Birden fazla inputunuz olsa bile, test felsefesi açısından fark etmez. getByDisplayValue herhangi bir inputta bu değeri bulduğu sürece, test başarılıdır. Eğer birden fazla inputunuz varsa ve belirli inputun bu değere sahip olduğunu test etmek istiyorsanız, o zaman elementin içine girip doğru input olduğunu kontrol edebilirsiniz:

not: bunun çalışması için jest-dom gerekecek.

expect(screen.getByDisplayValue('test')).toHaveAttribute('id', 'the-id');

veya (jest-dom olmadan):

expect(screen.getByDisplayValue('test').id).toBe('the-id');

Elbette istediğiniz herhangi bir özelliği arayabilirsiniz.

Değerin test edilmesi için son bir alternatif, girdiyi role göre bulmaktır. Bu, örneğinizdeki durumda çalışmaz, ancak bir etiket ekleyip bunu htmlFor özelliği aracılığıyla girdinize bağlarsanız çalışır. Daha sonra şöyle test edebilirsiniz:

expect(screen.getByRole('input', { name: 'the-inputs-id' })).toHaveValue('test');

veya (jest-dom olmadan):

expect(screen.getByRole('input', { name: 'the-inputs-id' }).value).toBe('test');

Buna göre, doğru girdi değerine sahip olduğundan emin olurken değeri test etmenin en iyi yolunun bu olduğunu düşünüyorum. getByRole yöntemini önerirdim, ancak yine de örneğinize bir etiket eklemeniz gerekecek.

Cevap #2

screen.getByDisplayValue() kullanarak görüntülenen değere sahip giriş öğesini alabilir ve bunu kendi öğenizle karşılaştırabilirsiniz.

type TestElement = Document | Element | Window | Node

function hasInputValue(e: TestElement, inputValue: string) {
  return screen.getByDisplayValue(inputValue) === e
}

Testinizde:

const input = screen.getByLabelText("Some Label")

fireEvent.change(input, { target: { value: '123' } })
expect(hasInputValue(input, "123")).toBe(true)

Cevap #3

expect(screen.getByLabelText("Name")).toHaveValue("hello"); - bu, input için değeri almanızı sağlar :)

<label class="label" for="name">
      Name
</label>
<div class="control ">
       <input
          class="input"
          for="name"
          id="name"
          name="name"
          value="hello"
       />
</div>

Test :

userEvent.type(screen.getByLabelText("Name"), "hello")
await waitFor(() => {
   expect(screen.getByLabelText("Name")).toHaveValue("hello");
});

Cevap #4

@testing-library/dom (veya buradaki sarılı kütüphanelerden herhangi biri) kullanarak

Şunu yapabilirsiniz:

expect(inputField).toHaveDisplayValue('some input value');

Tam örnek:

test('should show input with initial value set', async () => {
  render(<Input type="text" value="John Doe" data-testid="form-field-firstname" />);

  const inputField = await screen.findByTestId(`form-field-firstname`);
  await waitFor(() => expect(inputField).toHaveDisplayValue('John Doe')));
});

İlgili makaleler