ReactJS Jest Tesing - fireEvent.click() не запускает кнопку

Тестирую первый раз в жизни. У меня есть приложение секундомера, и я хочу проверить, работает ли секундомер. Я делаю это, нажимая кнопку и проверяя, что 00:00:00 все еще там.

Проблема в том, что 00:00:00 все еще находятся в промежутке после нажатия кнопки. Программа работает нормально, никаких проблем. В чем проблема с этим триггерином?

У меня есть кнопка START для этого:

class SecondTimer extends React.Component {
  constructor(props) {
    super(props);

    
    this.state = {
      running: false, // Format to false, so when start a program clock is not running
      currentTimeMs: 0,
      currentTimeSec: 0,
      currentTimeMin: 0,
    };
  }

 start = () => {
    if (!this.state.running) {
      this.setState({ running: true });
      this.watch = setInterval(() => this.pace(), 10);
    }
  };

{this.state.running === false && (
            <Button className = {"start-stop-reset-nappi"} variant = "success" size = "lg" onClick=
            {this.start}>START</Button>
          )}

И у меня есть span, где показано время (значение перед запуском 00:00:00, изображение ниже).

        <span>
          {this.props.formatTime(this.props.currentTimeMin)}:
          {this.props.formatTime(this.props.currentTimeSec)}:
          {this.props.formatTime(this.props.currentTimeMs)}
        </span>

Тогда у меня есть этот тест:

import { render, screen, fireEvent } from '@testing-library/react';
import SecondTimer from '../components/SecondTimer.jsx';


test('Test - Secondmeter running or not', () => {
  render(<SecondTimer />);

  const start = screen.getByText("START") // Here I'll check is there button (text) like START
  fireEvent.click(start); // Then I "Click" it

  const numbers = screen.getByText(/00:00:00/i) // Check is the 00:00:00 still on screen after triggering the button
  expect(numbers).toBeInTheDocument() 

});


Полный код компонента:

import React from 'react';
import SecondTimerNumbers from './SecondTimerNumbers.jsx';
import SecondTimerList from './SecondTimerList.jsx';
import { Button } from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';


class SecondTimer extends React.Component {
  constructor(props) {
    super(props);

    

    // Start funktio määrittää running arvon -> true, joka kertoo sen, että kello käy. Tallentaa tänne ajan, josta SeconTimerNumber hakee tiedon
    this.state = {
      running: false, // Alustettu falseksi, eli ohjelman avatessa kello ei käy
      currentTimeMs: 0,
      currentTimeSec: 0,
      currentTimeMin: 0,
    };
  }

  

  // Muuttaa kelloajan numeraaliset luvut stringiksi, sekä lisää yhdet nollat lukuun, jotta luvut ei ns. pompi silmillä.
  formatTime = (val, ...rest) => {
    let value = val.toString();
    if (value.length < 2) {
      value = '0' + value;
    }
    if (rest[0] === 'ms' && value.length < 3) {
      value = '0' + value;
    }
    return value;
  };

  // Start napista painalla käynnistää tämän funktion. Muuttaa state running trueksi, eli kello käy. SetInterval on Reactin oma sekuntikello, ja this.pace 10 määrittelee sadasosasekunnit
  start = () => {
    if (!this.state.running) {
      this.setState({ running: true });
      this.watch = setInterval(() => this.pace(), 10);
    }
  };

  // Stop painikkeesta muuttaa running staten falseksi -> kello pysähtyy, sekä tyhjentää sekuntikellon (pysäyttää).
  stop = () => {
    this.setState({ running: false });
    clearInterval(this.watch);
  };

  // Määrittelee kellon toiminnan
  pace = () => {
    this.setState({ currentTimeMs: this.state.currentTimeMs + 10 }); // Lisää 10ms kerrallaan

    // Kun millisekunteja 1000, lisää yhden sekunnin, sekä muuttaa millisekuntien arvoksi 0 kierroksen jälkeen
    if (this.state.currentTimeMs >= 1000) {
      this.setState({ currentTimeSec: this.state.currentTimeSec + 1 });
      this.setState({ currentTimeMs: 0 });
    }

    // Kun sekunteja on 60, lisää yhden minuutin, sekä muuttaa sekuntien arvoksi 0 kierroksen jälkeen
    if (this.state.currentTimeSec >= 60) {
      this.setState({ currentTimeMin: this.state.currentTimeMin + 1 });
      this.setState({ currentTimeSec: 0 });
    }
  };

  // Määrittää (resetoi) staten allaolevat arvot nollaksi, jolloin sekuntikello voidaan taas aloittaa alusta
  resetTime = () => {
    this.setState({
      currentTimeMs: 0,
      currentTimeSec: 0,
      currentTimeMin: 0,
    });
  };



  // UserInterface eli käyttöliittymä renderöityy tässä
  render() {
    return (
      <div className = {'main-div'}>
        <div className = {'left'}>
          {this.state.running === false && (
            <Button className = {"start-stop-reset-nappi"} variant = "success" size = "lg" onClick = {this.start}>START</Button>
          )}
          {this.state.running === true && (
            <Button className = {'start-stop-reset-nappi'} variant = "warning" size = "lg" onClick = {this.stop}>PAUSE</Button>
          )}
          <Button className = {'start-stop-reset-nappi'} variant = "danger" size = "lg" onClick = {this.resetTime}>RESET</Button>



          <div className = {'tulostaulu-main'}>
          <SecondTimerNumbers
            ref = "display"
            {...this.state}
            formatTime = {this.formatTime}
          />
          </div>
            
        </div>
        
        <div className = {'right'}>
          <SecondTimerList clickResetTime = {this.resetTime}  {...this.state} formatTime = {this.formatTime} />
        </div>

      </div>
    );// Yllä oleva ClickResetTime funktio on tämän sivut resetTime funktio.
    // Tällä saan kutsuttua funktiota toisesta componentista, tavallaan "injektoin" funktion tähän componenttiin.
  }
}

export default SecondTimer;

Не могли бы вы уточнить ожидаемое поведение и наблюдаемое поведение?

srk 10.12.2020 17:41

Похоже, время отображения текста 00:00:00 всегда отображается в зависимости от нажатия кнопки или нет. Можете ли вы поделиться всем кодом вашего компонента?

tmhao2005 10.12.2020 18:13

@tmhao2005 Добавлен код этого компонента. В тесте всегда 00:00:00, что fireEvent.click() не работает? Приложение работает нормально, это только тестовая проблема. Когда вы нажимаете эту кнопку START, часы должны начать работать, но это не так.

Joko Joko 10.12.2020 18:35

Итак, вы ожидаете, что таймер будет работать, то есть 00:00:00 НЕ должен отображаться?

srk 10.12.2020 18:47
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
4
4 021
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я действительно не знаю, в чем проблема с вашим тестом. Я создал небольшой тест на основе вашего текущего, который работает очень хорошо.

Идея теста довольно проста. Когда я нажал кнопку, я ожидаю увидеть изменение в секундах. Ключевым моментом является использование waitFor API с указанной опцией timeout, чтобы убедиться, что тестовая библиотека разрешает изменение вашего пользовательского интерфейса.

Вот фрагмент:

import React from "react";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import { SecondTimer } from "./App";

test("should work", async () => {
  render(<SecondTimer />);

  const start = screen.getByText("START");
  fireEvent.click(start);

  await waitFor(() => screen.getByText(/00:02:00/i), {
    timeout: 2000 // wait 2s 
  });

  const numbers = screen.getByText(/00:02:00/i);

  expect(numbers).toBeInTheDocument();
});

Вот codesanbox, который я создал специально для вас (настройка для запуска теста основана на скрипте create-react-app):

https://codesandbox.io/s/morning-browser-92uks?file=/src/App.test.js

ПРИМЕЧАНИЕ. Чтобы запустить тест, щелкните вкладку Tests рядом с Browser в области предварительного просмотра.

Спасибо! Я немного изменил ваш код, timeout: 2000 было недостаточно. Почему-то этот скрипт работает медленно или что-то в этом роде, span получил только 00:01:290 по истечении тайм-аута. Я увеличил тайм-аут до 3000, затем он ждет еще одну секунду и получает 00:02:00. Теперь работает :)) Спасибо!

Joko Joko 11.12.2020 21:02

Другие вопросы по теме