Home > Software engineering >  hover testing not working on react component
hover testing not working on react component

Time:09-07

Testing opacity while hover button is not working. Tried with both userEvent.hover(hoverButton) and fireEvent.mouseOver(hoverButton) unfortunately the result is same. At the same time the other properties are working, for example 'cursor:not-allowed'

Button.js

import styled from 'styled-components';

const ButtonWrapper = styled.button`
  color: #fff;
  background-color: tomato;
  font-size: 14px; 
  padding: 6px 30px;
  height: 35px;

  &:not(:disabled):hover {
    opacity: 0.8;
    background: red;
  }

  ${({ disabled }) =>
    disabled && `
      opacity: 0.4;
      cursor: not-allowed;
    `}
`;

  // background-color: ${(props) => props.theme.buttonColors[props.kind]};

const Button = ({ children, className, disabled, size = 'medium' }) => {

  return <ButtonWrapper
    className={className}
    disabled={disabled}
    onClick={() => console.log('Hello mate')}
    size={size}
  >{children}</ButtonWrapper>;
}

export default Button;

Button.test.js

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

test('should render button', () => {
  render(<Button>Click on me</Button>);
  expect(screen.getByText(/Click on me/i)).toBeInTheDocument();
});

test('should render disabled button', () => {
  render(<Button disabled>hover on me</Button>);
  const hoverButton = screen.getByRole('button');
  
  expect(hoverButton).toBeDisabled();
  expect(hoverButton).toHaveStyle('opacity: 0.4')
  expect(hoverButton).toHaveStyle('cursor:not-allowed')
});

test('should hover button', () => {
  render(<Button>hover on me</Button>);
  // const hoverButton = screen.getByRole('button');
  const hoverButton = screen.getByRole('button', { name: 'hover on me' });
  
  userEvent.hover(hoverButton);
  // fireEvent.mouseOver(hoverButton)

  expect(hoverButton).toHaveStyle('opacity: 0.8')
  expect(hoverButton).toHaveStyle(`background-color: #000`);
});

test('toMatchSnapshot', () => {
  const { asFragment } = render(<Button>Click on me</Button>);
  expect(asFragment()).toMatchSnapshot();
});

CodePudding user response:

Problem

I found a few obstacles that you're running into:

  1. There's a mistake in the test, where the background-color was expected to be #000 when it's set as background: redu in the Button.js file.
  2. I'm pretty confident that the testing-library's hover interaction doesn't update the computed styles. I verified this using getComputedStyle in the DOM versus in the test. That said, you can use jest-styled-components' toHaveStyleRule, to check for pseudo styles however that's not really not going to cover what you're attempting to test.
  3. Currently, there's really no way for you to test a button's current appearance based upon a browser interaction, unless that interaction add/removes styles dynamically using some sort of React state or prop (similar to what you've done with disabled). As a result, there's no way to accurately determine it's appearance since every Button has the same pseudo styles (the snapshots showcase this, but also looking at the DOM will showcase the same thing):
exports[`Button disabled snapshot 1`] = `
<DocumentFragment>
  .c0 {
  color: #fff;
  background-color: tomato;
  font-size: 14px;
  padding: 6px 30px;
  height: 35px;
  opacity: 0.4;
  cursor: not-allowed;
}

.c0:not(:disabled):hover {
  opacity: 0.8;
  background: red;
}

<button
    
    disabled=""
  >
    Click on me
  </button>
</DocumentFragment>
`;

exports[`Button enabled snapshot 1`] = `
<DocumentFragment>
  .c0 {
  color: #fff;
  background-color: tomato;
  font-size: 14px;
  padding: 6px 30px;
  height: 35px;
}

.c0:not(:disabled):hover {
  opacity: 0.8;
  background: red;
}

<button
    
  >
    Click on me
  </button>
</DocumentFragment>
`;

Recommendation:

You don't need to test against native interactions/style changes with the DOM. Instead, test against what you do control. In this case, you're controlling whether or not a button can be disabled and appending styles based upon that prop. Other than testing that (which you've already done), in this case, any other tests should be considered ancillary/superfluous.

Taking a step back, what exactly are you trying to test? It seems like you are trying to test if a browser can apply a style via a specific CSS selector to a button? This seems rather unnecessary, no?

Not recommended:

This will test if an element contains a particular pseudo style, but again, it's shared and there's really no way to determine when its styles are active (even if you added a disabled button prop, this test will still pass because it still contains the pseudo styles!):

test("should contain button hover styles", () => {
  render(<Button>hover on me</Button>);
  const hoverButton = screen.getByRole("button");

  expect(hoverButton).toHaveStyleRule("opacity", "0.8", {
    modifier: ":not(:disabled):hover",
  });
  expect(hoverButton).toHaveStyleRule("background", "red", {
    modifier: ":not(:disabled):hover",
  });
});
  • Related