I have a TextField component that contains a unit ( p
) on the right. I change the padding between this unit and the text value dynamically within useEffect
but when I wanted to ensure that it works correctly using component Testing with Cypress, I blocked.
import classNames from "classnames";
import { IProps } from "./type";
import styles from "./style.module.css";
import { useEffect, useRef } from "react";
const TextField = ({
ID,
value,
placeholder,
type,
rounded,
outline,
disabled,
icon,
unit,
onChange,
onFocus,
onBlur,
}: IProps) => {
const unitRef = useRef<HTMLParagraphElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
// How to test this hook
useEffect(() => {
if (unitRef.current && inputRef.current) {
const unitWidth = unitRef.current.getBoundingClientRect().width;
inputRef.current.style.paddingRight = `${unitWidth + 20}px`;
}
}, [unit]);
return (
<div
className={styles.wrapper}
data-cy="textfield-wrapper"
>
{icon && (
<div
className={classNames(styles.icon, {
[styles.iconPrimary]: type === "primary",
[styles.iconSecondary]: type === "secondary",
[styles.iconTernary]: type === "ternary",
})}
data-cy="textfield-icon"
>
{icon}
</div>
)}
<input
ref={inputRef}
id={ID}
type="text"
value={value}
placeholder={placeholder}
className={classNames(styles.textfield, {
[styles.primary]: type === "primary",
[styles.secondary]: type === "secondary",
[styles.ternary]: type === "ternary",
[styles.rounded]: rounded,
[styles.outline]: outline,
[styles.paddingLeft]: icon,
[styles.paddingRight]: unit,
})}
disabled={disabled}
onChange={onChange}
onFocus={onFocus}
onBlur={onBlur}
/>
{unit && (
<p
ref={inputRef}
className={classNames(styles.unit, {
[styles.unitPrimary]: type === "primary",
[styles.unitSecondary]: type === "secondary",
[styles.unitTernary]: type === "ternary",
})}
data-cy="textfield-unit"
>
{unit}
</p>
)}
</div>
);
};
export default TextField;
``
button.cy.tsx
it("should adjusts input padding based on unit width", () => {
const onChange = () => {
console.log("TextField");
};
cy.mount(
<TextField
ID="textfield"
value="credium Textfield"
onChange={onChange}
type="primary"
icon={<IoMdHome />}
unit="kWh"
rounded
outline
/>
);
cy.get('[data-cy="textfield-wrapper"]').within(() => {
// blocked here
cy.get("input").should("have.css", "padding-right", "???");
});
});
2
Answers
It seems like the main issue you’re encountering during your Cypress testing is related to retrieving and asserting the computed CSS value for the padding-right property of the input element within the TextField component. Cypress uses a different approach for asserting CSS values due to its unique nature as an end-to-end testing tool.
To correctly assert CSS values using Cypress, you can use the .should() command along with the have.css assertion. However, you should use a CSS property value that you expect to see based on your implementation, rather than trying to match a specific value like "???" which might not be accurate.
Please use the above given code to update your test to correctly assert the padding-right value:
In the test above, the should command checks that the padding-right property is not equal to 0px. This will ensure that the assertion passes as long as the padding-right value is non-zero, which is what you expect based on your useEffect logic in the component.
Remember that the exact value of the padding-right property might vary based on the actual dimensions of your unit element and the calculations in your useEffect. Using and("not.equal", "0px") accounts for this variability while still ensuring that the padding is being adjusted as expected.
The app sets paddingRight to
${unitWidth + 20}px
, you can repeat that calculation inside the.should()
.This should succeed even if the element width changes due to window width, flex layout, media queries (mobile/tablet/desktop).
If I understand correctly, you just want to know that the padding is always width +20.
If unitRef is pointing to
<p>
I think the test code needs adjusting if my assumption about
unitRef
is correct, i.e it should be bound to the<p>
element.If so, the
.should()
callback needs both<input>
and<p>
.