keyDown w testach nie wstawia wartości do inputa

0

Mam taki kod dotyczący testowania:

import React from "react";
import { render, fireEvent } from "react-testing-library";
import App from "./App";

test("App works", () => {
  const { container } = render(<App />);
  const inputElement = container.querySelector("#some-input");

  fireEvent.keyDown(inputElement, { key: "2" });
  expect(inputElement.getAttribute("value")).toBe("2");
});

oraz taki komponent:

import React, { useState } from "react";

const App = () => {
  const [inputValue, setInputValue] = useState("");

  return (
    <input
      id="some-input"
      value={inputValue}
      onChange={(event) => setInputValue(event.target.value)}
    ></input>
  );
};

export default App;

Czy jest ktoś w stanie wytłumaczyć dlaczego tutaj expect(inputElement.getAttribute("value")).toBe(2); nadal atrybut value ma wartość "" ? Dlaczego fireEvent.keyDown nie zmieniło tej wartości w testach ?

Wiem, że można użyć np. fireEvent.change albo fireEvent.input, ale akurat tutaj interesuje mnie wykorzystanie fireEvent.keyDown, ponieważ mam podobny przypadek w kodzie, gdzie operuje na divach i nie ma możliwości ich zmiany na inputy, ponieważ pochodzą z zewnętrznej biblioteki.

Czy jest ktoś w stanie pomóc ?

0

ja tam we froncie nie robię ale testy jednostkowe na interakcje z userem???

2

Czy jest ktoś w stanie wytłumaczyć dlaczego tutaj expect(inputElement.getAttribute("value")).toBe(2); nadal atrybut value ma wartość "" ? Dlaczego fireEvent.keyDown nie zmieniło tej wartości w testach ?

Odpowiedź na to pytanie wydaje mi się dość prosta.

Input jest połączony ze stanem komponentu, a w tym przypadku stan komponentu zmienia event onChange, nie onKeyDown.

Gdyby input nie był połączony ze stanem to prawdopodobnie by zadziałało.

Wiem, że można użyć np. fireEvent.change albo fireEvent.input, ale akurat tutaj interesuje mnie wykorzystanie fireEvent.keyDown, ponieważ mam podobny przypadek w kodzie, gdzie operuje na divach i nie ma możliwości ich zmiany na inputy, ponieważ pochodzą z zewnętrznej biblioteki.

Nie możesz użyć w tym wypadku fireEvent.change, a dopiero w tym drugim fireEvent.keydown?

0
Xarviel napisał(a):

Czy jest ktoś w stanie wytłumaczyć dlaczego tutaj expect(inputElement.getAttribute("value")).toBe(2); nadal atrybut value ma wartość "" ? Dlaczego fireEvent.keyDown nie zmieniło tej wartości w testach ?

Odpowiedź na to pytanie wydaje mi się dość prosta.

Input jest połączony ze stanem komponentu, a w tym przypadku stan komponentu zmienia event onChange, nie onKeyDown.

Gdyby input nie był połączony ze stanem to prawdopodobnie by zadziałało.

Wiem, że można użyć np. fireEvent.change albo fireEvent.input, ale akurat tutaj interesuje mnie wykorzystanie fireEvent.keyDown, ponieważ mam podobny przypadek w kodzie, gdzie operuje na divach i nie ma możliwości ich zmiany na inputy, ponieważ pochodzą z zewnętrznej biblioteki.

Nie możesz użyć w tym wypadku fireEvent.change, a dopiero w tym drugim fireEvent.keydown?

Czyli jakbyś to widział ? Problem jest taki, że w innym kodzie mam pseudo inputa zrobionego na divach i nie mogę zmienić wartości przy użyciu fireEvent.change, bo div nie ma value. Divów w html nie zmienie na inputy, bo ten pseudo input jest brany z zewnętrznej biblioteki.

Choć nawet jak dodałem onKeyDown do inputa jako event handler to i tak ten test nie działa poprawnie (nadal w teście nie zmienia wartości):

import React from "react";
import { render, fireEvent } from "react-testing-library";
import App from "./App";

test("App works", () => {
  const { container } = render(<App />);
  const inputElement = container.querySelector("#some-input");

  inputElement.focus();
  fireEvent.keyDown(inputElement, { key: "2" });

  expect(inputElement.getAttribute("value")).toBe("2");
});
import React, { useState } from "react";

const App = () => {
  const [inputValue, setInputValue] = useState("");

  return (
    <input
      id="some-input"
      value={inputValue}
      onKeyDown={(event) => setInputValue(event.target.key)}
    ></input>
  );
};

export default App;

0

Nie wiem z której wersji biblioteki korzystasz, ale jak sprawdzam najnowszą to jest kilka różnic w porównaniu do Twojego przykładu.

W aktualnej wersji podają, żeby do wyszukiwania elementów używać czegoś takiego jak screen, a do emulacji eventów userEvent :D

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import App from "./App";

test('example', async () => {
  render(<App />);
  const inputElement = screen.getByRole('textbox'); // Pobranie znacznika <input />

  await userEvent.type(inputElement, 'Hello World'); // Wprowadzenie tekstu

  expect(inputElement).toHaveValue('Hello, World!'); // Porównanie, czy wprowadzony tekst się zgadza
})

Z tego co czytałem to userEvent różni się tym od fireEvent, że uruchamia więcej eventów i bardziej przypomina pracę w przeglądarce.

fireEvent.keydown(...) -> odpala tylko jeden event keydown

natomiast

userEvent.type -> odpala eventy związane z kliknięciem, eventy związane z wpisywaniem tekstu keydown, keyup, input, change itd czyli to samo co zadziało by się w normalnej przeglądarce podczas całego procesu.

https://testing-library.com/docs/user-event/utility#type
https://testing-library.com/docs/queries/about

0

Hmm, ale czemu u mnie to nie działa z fireEventem ? W aplikacji używamy fireEventa. Czemu ten test nie zadziała ? Może źle wywoływany jest fireEvent.keyDown ? Próbowałem go wywoływać na kilka sposobów, ale ciągle jest to samo.

import React from "react";
import { render, fireEvent } from "react-testing-library";
import App from "./App";

test("App works", () => {
  const { container } = render(<App />);
  const inputElement = container.querySelector("#some-input");

  inputElement.focus();
  fireEvent.keyDown(inputElement, { key: "2" });

  expect(inputElement.getAttribute("value")).toBe("2");
});
import React, { useState } from "react";

const App = () => {
  const [inputValue, setInputValue] = useState("");

  return (
    <input
      id="some-input"
      value={inputValue}
      onKeyDown={(event) => setInputValue(event.target.key)}
    ></input>
  );
};

export default App;

I np. jeszcze w swoim kodzie aplikacji mam coś takiego, że jak użyje takiego zapisu:

fireEvent.keyDown(inputElements, { key: "ArrowUp" });

to inkrementuje mi o 1 wartość w inpucie, który przyjmuje numbery.

Natomiast jeśli mam taki zapis:

fireEvent.keyDown(inputElements, { key: "1" });

to już w ogóle nie zmienia wartości w inpucie. O co chodzi ? Może jest przekazywana zła wartość w key ? Może dla liczb te key powinno się inaczej nazywać albo w ogóle nie można czegoś takiego robić ? W internecie nie znalazłem info na ten temat.

0
abrakadaber napisał(a):

ja tam we froncie nie robię ale testy jednostkowe na interakcje z userem???

No pewnie ze tak. W jaki inny sposób chcesz mieć pewność że front działa dobrze? Bo chyba nie testami manualnymi?

Dobrze robi. Takie same testy są w testach so edytora postów w Coyote.

1 użytkowników online, w tym zalogowanych: 0, gości: 1