Skip to content

Commit 91a71c9

Browse files
test: update Rating tests to use Testing Library and improve structure
1 parent 102565e commit 91a71c9

File tree

5 files changed

+695
-559
lines changed

5 files changed

+695
-559
lines changed

packages/pluggableWidgets/rating-web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"publish-marketplace": "rui-publish-marketplace",
3939
"release": "cross-env MPKOUTPUT=StarRating.mpk pluggable-widgets-tools release:web",
4040
"start": "cross-env MPKOUTPUT=StarRating.mpk pluggable-widgets-tools start:server",
41-
"test": "pluggable-widgets-tools test:unit:web",
41+
"test": "pluggable-widgets-tools test:unit:web:enzyme-free",
4242
"update-changelog": "rui-update-changelog-widget",
4343
"verify": "rui-verify-package-format"
4444
},
Lines changed: 74 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,103 @@
11
import { createElement } from "react";
2-
import { mount, shallow } from "enzyme";
2+
import { render, screen, fireEvent } from "@testing-library/react";
33
import { Rating, RatingProps } from "../Rating";
4+
import "@testing-library/jest-dom";
45

5-
describe("Rating", () => {
6-
const defaultProps: RatingProps = {
7-
className: "",
8-
animated: true,
9-
disabled: false,
10-
emptyIcon: <div className="empty" />,
11-
fullIcon: <div className="full" />,
12-
value: 0,
13-
onChange: undefined,
14-
maximumValue: 5,
15-
style: undefined
16-
};
6+
const defaultProps: RatingProps = {
7+
className: "",
8+
animated: true,
9+
disabled: false,
10+
emptyIcon: <div className="empty" />,
11+
fullIcon: <div className="full" />,
12+
value: 0,
13+
onChange: undefined,
14+
maximumValue: 5,
15+
style: undefined
16+
};
1717

18+
function renderRating(props?: Partial<RatingProps>) {
19+
return render(<Rating {...defaultProps} {...props} />);
20+
}
21+
22+
describe("Rating rendering", () => {
1823
it("renders correctly the structure", () => {
19-
const rating = shallow(<Rating {...defaultProps} />);
20-
expect(rating).toMatchSnapshot();
24+
const { asFragment } = renderRating();
25+
expect(asFragment()).toMatchSnapshot();
2126
});
2227

2328
it("renders correctly the structure when disabled", () => {
24-
const rating = shallow(<Rating {...defaultProps} disabled />);
25-
expect(rating).toMatchSnapshot();
29+
const { asFragment } = renderRating({ disabled: true });
30+
expect(asFragment()).toMatchSnapshot();
2631
});
2732

2833
it("renders correctly the structure without animations", () => {
29-
const rating = shallow(<Rating {...defaultProps} animated={false} />);
30-
expect(rating).toMatchSnapshot();
34+
const { asFragment } = renderRating({ animated: false });
35+
expect(asFragment()).toMatchSnapshot();
3136
});
3237

3338
it("renders correctly the structure with custom class", () => {
34-
const rating = shallow(<Rating {...defaultProps} className="my-custom-class" />);
35-
expect(rating).toMatchSnapshot();
39+
const { asFragment } = renderRating({ className: "my-custom-class" });
40+
expect(asFragment()).toMatchSnapshot();
3641
});
3742

3843
it("renders the correct amount of items", () => {
39-
const rating = mount(<Rating {...defaultProps} maximumValue={2} />);
40-
expect(rating.find(".rating-item")).toHaveLength(2);
44+
renderRating({ maximumValue: 2 });
45+
expect(screen.getAllByRole("radio")).toHaveLength(2);
4146
});
4247

4348
it("renders the correct amount of items when value is superior to maximumValue", () => {
44-
const rating = mount(<Rating {...defaultProps} maximumValue={2} value={5} />);
45-
expect(rating.find(".rating-item")).toHaveLength(2);
46-
expect(rating.find("div.full")).toHaveLength(2);
49+
const { container } = renderRating({ maximumValue: 2, value: 5 });
50+
expect(screen.getAllByRole("radio")).toHaveLength(2);
51+
expect(container.querySelectorAll(".full")).toHaveLength(2);
4752
});
53+
});
4854

49-
describe("with events", () => {
50-
it("triggers the event with correct value on click", () => {
51-
const onChange = jest.fn();
52-
const rating = mount(<Rating {...defaultProps} onChange={onChange} />);
53-
const options = rating.find(".rating-item");
54-
options.at(0).simulate("click");
55-
expect(onChange).toHaveBeenCalled();
56-
expect(onChange).toHaveBeenCalledWith(1);
57-
});
55+
describe("Rating events", () => {
56+
it("triggers the event with correct value on click", () => {
57+
const onChange = jest.fn();
58+
renderRating({ onChange });
59+
const radios = screen.getAllByRole("radio");
60+
fireEvent.click(radios[0]);
61+
expect(onChange).toHaveBeenCalledWith(1);
62+
});
5863

59-
it("cleans the value when clicking twice at same value", () => {
60-
const onChange = jest.fn();
61-
const rating = mount(<Rating {...defaultProps} onChange={onChange} />);
62-
const options = rating.find(".rating-item");
63-
options.at(1).simulate("click");
64-
expect(onChange).toHaveBeenCalledWith(2);
65-
// As the property is being managed from the outer component, we need to force the property to update to the new value
66-
rating.setProps({ value: 2 });
67-
options.at(1).simulate("click");
68-
expect(onChange).toHaveBeenCalledWith(0);
64+
it("cleans the value when clicking twice at same value", () => {
65+
let value = 0;
66+
const onChange = jest.fn(v => {
67+
value = v;
6968
});
69+
const { rerender } = renderRating({ onChange, value });
70+
const radios = screen.getAllByRole("radio");
71+
fireEvent.click(radios[1]);
72+
expect(onChange).toHaveBeenCalledWith(2);
73+
rerender(<Rating {...defaultProps} onChange={onChange} value={2} />);
74+
fireEvent.click(radios[1]);
75+
expect(onChange).toHaveBeenCalledWith(0);
76+
});
7077

71-
it("triggers the event with correct value on space key down", () => {
72-
const onChange = jest.fn();
73-
const rating = mount(<Rating {...defaultProps} onChange={onChange} />);
74-
const options = rating.find(".rating-item");
75-
options.at(0).simulate("keydown", { key: " " });
76-
expect(onChange).toHaveBeenCalled();
77-
expect(onChange).toHaveBeenCalledWith(1);
78-
});
78+
it("triggers the event with correct value on space key down", () => {
79+
const onChange = jest.fn();
80+
renderRating({ onChange });
81+
const radios = screen.getAllByRole("radio");
82+
fireEvent.keyDown(radios[0], { key: " " });
83+
expect(onChange).toHaveBeenCalledWith(1);
84+
});
7985

80-
it("triggers the event with correct value on enter key down", () => {
81-
const onChange = jest.fn();
82-
const rating = mount(<Rating {...defaultProps} onChange={onChange} />);
83-
const options = rating.find(".rating-item");
84-
options.at(2).simulate("keydown", { key: "Enter" });
85-
expect(onChange).toHaveBeenCalled();
86-
expect(onChange).toHaveBeenCalledWith(3);
87-
});
86+
it("triggers the event with correct value on enter key down", () => {
87+
const onChange = jest.fn();
88+
renderRating({ onChange });
89+
const radios = screen.getAllByRole("radio");
90+
fireEvent.keyDown(radios[2], { key: "Enter" });
91+
expect(onChange).toHaveBeenCalledWith(3);
92+
});
8893

89-
it("doesn't trigger any event when disabled", () => {
90-
const onChange = jest.fn();
91-
const rating = mount(<Rating {...defaultProps} disabled onChange={onChange} />);
92-
const options = rating.find(".rating-item");
93-
options.at(1).simulate("keydown", { key: "Enter" });
94-
expect(onChange).toHaveBeenCalledTimes(0);
95-
options.at(2).simulate("keydown", { key: " " });
96-
expect(onChange).toHaveBeenCalledTimes(0);
97-
options.at(3).simulate("click");
98-
expect(onChange).toHaveBeenCalledTimes(0);
99-
});
94+
it("doesn't trigger any event when disabled", () => {
95+
const onChange = jest.fn();
96+
renderRating({ disabled: true, onChange });
97+
const radios = screen.getAllByRole("radio");
98+
fireEvent.keyDown(radios[1], { key: "Enter" });
99+
fireEvent.keyDown(radios[2], { key: " " });
100+
fireEvent.click(radios[3]);
101+
expect(onChange).not.toHaveBeenCalled();
100102
});
101103
});

packages/pluggableWidgets/rating-web/src/components/__tests__/StarRating.spec.tsx

Lines changed: 54 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -2,85 +2,75 @@ import { createElement } from "react";
22
import { actionValue, EditableValueBuilder } from "@mendix/widget-plugin-test-utils";
33
import { StarRatingContainerProps } from "../../../typings/StarRatingProps";
44
import { Big } from "big.js";
5-
import { mount, shallow } from "enzyme";
5+
import { render, screen, fireEvent } from "@testing-library/react";
66
import { StarRating } from "../../StarRating";
7-
import { Rating } from "../Rating";
7+
import "@testing-library/jest-dom";
88

9-
describe("Rating Container", () => {
10-
const defaultProps: StarRatingContainerProps = {
11-
class: "",
12-
name: "rating",
13-
tabIndex: 0,
14-
rateAttribute: new EditableValueBuilder<Big>().withValue(new Big(5)).build(),
15-
animation: true,
16-
maximumStars: 5
17-
};
9+
const defaultProps: StarRatingContainerProps = {
10+
class: "",
11+
name: "rating",
12+
tabIndex: 0,
13+
rateAttribute: new EditableValueBuilder<Big>().withValue(new Big(5)).build(),
14+
animation: true,
15+
maximumStars: 5
16+
};
1817

18+
function renderStarRating(props?: Partial<StarRatingContainerProps>): ReturnType<typeof render> {
19+
return render(<StarRating {...defaultProps} {...props} />);
20+
}
21+
22+
describe("StarRating rendering", () => {
1923
it("renders correctly the structure", () => {
20-
const rating = shallow(<StarRating {...defaultProps} />);
21-
expect(rating).toMatchSnapshot();
24+
const { asFragment } = renderStarRating();
25+
expect(asFragment()).toMatchSnapshot();
2226
});
2327

2428
it("renders correctly the structure without animation", () => {
25-
const rating = shallow(<StarRating {...defaultProps} animation={false} />);
26-
expect(rating).toMatchSnapshot();
29+
const { asFragment } = renderStarRating({ animation: false });
30+
expect(asFragment()).toMatchSnapshot();
2731
});
2832

2933
it("renders correctly the structure when disabled", () => {
30-
const rating = shallow(
31-
<StarRating
32-
{...defaultProps}
33-
rateAttribute={new EditableValueBuilder<Big>().withValue(new Big(1)).isReadOnly().build()}
34-
/>
35-
);
36-
expect(rating).toMatchSnapshot();
37-
});
38-
39-
describe("with events", () => {
40-
it("triggers correctly on change action", () => {
41-
const onChange = actionValue();
42-
const ratingWrapper = mount(<StarRating {...defaultProps} onChange={onChange} />);
43-
const rating = ratingWrapper.find(Rating);
44-
const options = rating.find("div.rating-item");
45-
options.at(0).simulate("click");
46-
47-
expect(onChange.execute).toHaveBeenCalled();
48-
});
49-
50-
it("defines correct values to attribute on change action", () => {
51-
const ratingAttribute = new EditableValueBuilder<Big>().withValue(new Big(0)).build();
52-
const ratingWrapper = mount(<StarRating {...defaultProps} rateAttribute={ratingAttribute} />);
53-
const rating = ratingWrapper.find(Rating);
54-
const options = rating.find("div.rating-item");
55-
options.at(0).simulate("click");
56-
57-
expect(ratingAttribute.setValue).toHaveBeenCalled();
58-
expect(ratingAttribute.setValue).toHaveBeenCalledWith(new Big(1));
34+
const { asFragment } = renderStarRating({
35+
rateAttribute: new EditableValueBuilder<Big>().withValue(new Big(1)).isReadOnly().build()
5936
});
37+
expect(asFragment()).toMatchSnapshot();
38+
});
39+
});
6040

61-
it("doesnt call setValue when value is read only", () => {
62-
const ratingAttribute = new EditableValueBuilder<Big>().withValue(new Big(1)).isReadOnly().build();
63-
const ratingWrapper = mount(<StarRating {...defaultProps} rateAttribute={ratingAttribute} />);
64-
const rating = ratingWrapper.find(Rating);
65-
const options = rating.find("div.rating-item");
66-
options.at(0).simulate("click");
41+
describe("StarRating events", () => {
42+
it("triggers correctly on change action", () => {
43+
const onChange = actionValue();
44+
renderStarRating({ onChange });
45+
const radios = screen.getAllByRole("radio");
46+
fireEvent.click(radios[0]);
47+
expect(onChange.execute).toHaveBeenCalled();
48+
});
6749

68-
expect(ratingAttribute.setValue).toHaveBeenCalledTimes(0);
69-
});
50+
it("defines correct values to attribute on change action", () => {
51+
const ratingAttribute = new EditableValueBuilder<Big>().withValue(new Big(0)).build();
52+
renderStarRating({ rateAttribute: ratingAttribute });
53+
const radios = screen.getAllByRole("radio");
54+
fireEvent.click(radios[0]);
55+
expect(ratingAttribute.setValue).toHaveBeenCalledWith(new Big(1));
56+
});
7057

71-
it("doesnt trigger on change action when attribute is read only", () => {
72-
const onChange = actionValue();
73-
const ratingWrapper = mount(
74-
<StarRating
75-
{...defaultProps}
76-
rateAttribute={new EditableValueBuilder<Big>().withValue(new Big(1)).isReadOnly().build()}
77-
/>
78-
);
79-
const rating = ratingWrapper.find(Rating);
80-
const options = rating.find("div.rating-item");
81-
options.at(0).simulate("click");
58+
it("doesnt call setValue when value is read only", () => {
59+
const ratingAttribute = new EditableValueBuilder<Big>().withValue(new Big(1)).isReadOnly().build();
60+
renderStarRating({ rateAttribute: ratingAttribute });
61+
const radios = screen.getAllByRole("radio");
62+
fireEvent.click(radios[0]);
63+
expect(ratingAttribute.setValue).not.toHaveBeenCalled();
64+
});
8265

83-
expect(onChange.execute).toHaveBeenCalledTimes(0);
66+
it("doesnt trigger on change action when attribute is read only", () => {
67+
const onChange = actionValue();
68+
renderStarRating({
69+
rateAttribute: new EditableValueBuilder<Big>().withValue(new Big(1)).isReadOnly().build(),
70+
onChange
8471
});
72+
const radios = screen.getAllByRole("radio");
73+
fireEvent.click(radios[0]);
74+
expect(onChange.execute).not.toHaveBeenCalled();
8575
});
8676
});

0 commit comments

Comments
 (0)