Skip to content

Commit 25c4657

Browse files
committed
VueUiRating add e2e component test
1 parent ad29f0f commit 25c4657

File tree

4 files changed

+278
-19
lines changed

4 files changed

+278
-19
lines changed

cypress/fixtures/rating.json

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
{
2+
"dataset": {
3+
"rating": {
4+
"1": 1,
5+
"2": 1,
6+
"3": 1,
7+
"4": 1,
8+
"5": 30
9+
}
10+
},
11+
"config": {
12+
"type": "star",
13+
"readonly": false,
14+
"from": 1,
15+
"to": 5,
16+
"style": {
17+
"fontFamily": "inherit",
18+
"animated": true,
19+
"itemSize": 32,
20+
"backgroundColor": "#FFFFFF",
21+
"star": {
22+
"activeColor": "#FFD055",
23+
"borderColor": "#FFD055",
24+
"borderWidth": 3,
25+
"apexes": 5,
26+
"inactiveColor": "#e1e5e8",
27+
"useGradient": true
28+
},
29+
"image": {
30+
"src": "../../star.png",
31+
"inactiveOpacity": 0.3,
32+
"alt": "rating image"
33+
},
34+
"title": {
35+
"textAlign": "center",
36+
"fontSize": 20,
37+
"color": "#2D353C",
38+
"bold": true,
39+
"text": "Title",
40+
"offsetY": 6,
41+
"subtitle": {
42+
"fontSize": 14,
43+
"color": "#CCCCCC",
44+
"bold": false,
45+
"text": "Subtitle",
46+
"offsetY": 12
47+
}
48+
},
49+
"rating": {
50+
"show": true,
51+
"fontSize": 28,
52+
"bold": true,
53+
"roundingValue": 1,
54+
"position": "bottom",
55+
"offsetY": 0,
56+
"offsetX": 0
57+
},
58+
"tooltip": {
59+
"show": true,
60+
"fontSize": 14,
61+
"offsetY": 0,
62+
"color": "#2D353C",
63+
"bold": true,
64+
"backgroundColor": "#FFFFFF",
65+
"borderColor": "#e1e5e8",
66+
"borderRadius": 4,
67+
"boxShadow": "0 6px 12px -6px rgba(0,0,0,0.2)"
68+
}
69+
}
70+
}
71+
}

src/components/vue-ui-rating.cy.js

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import VueUiRating from './vue-ui-rating.vue'
2+
3+
describe('<VueUiDonut />', () => {
4+
beforeEach(function () {
5+
cy.fixture('rating.json').as('fixture');
6+
cy.viewport(800, 160);
7+
});
8+
9+
function updateConfigInFixture(modifiedConfig) {
10+
cy.get('@fixture').then((fixture) => {
11+
const updatedFixture = { ...fixture, config: modifiedConfig };
12+
cy.wrap(updatedFixture).as('fixture');
13+
});
14+
}
15+
16+
it('renders with different config attributes', function () {
17+
cy.get('@fixture').then((fixture) => {
18+
cy.mount(VueUiRating, {
19+
props: {
20+
dataset: fixture.dataset,
21+
config: fixture.config
22+
}
23+
});
24+
25+
function calculateAverageRating(source) {
26+
let totalSum = 0;
27+
let totalCount = 0;
28+
29+
for (const key in source) {
30+
const ratingValue = parseInt(key);
31+
const ratingCount = source[key];
32+
33+
totalSum += ratingValue * ratingCount;
34+
totalCount += ratingCount;
35+
}
36+
37+
if (totalCount === 0) {
38+
return 0;
39+
}
40+
41+
const averageRating = totalSum / totalCount;
42+
return Math.min(fixture.config.to, Math.max(fixture.config.from, averageRating));
43+
}
44+
45+
const staticRating = calculateAverageRating(fixture.dataset.rating).toFixed(fixture.config.style.rating.roundingValue)
46+
47+
cy.get(`[data-cy="rating-title"]`)
48+
.should('exist')
49+
.contains('Title');
50+
51+
cy.get(`[data-cy="rating-subtitle"]`)
52+
.should('exist')
53+
.contains('Subtitle');
54+
55+
cy.get(`[data-cy="rating-position-bottom"]`)
56+
.should('exist')
57+
.contains(staticRating)
58+
59+
let modifiedConfig = {
60+
...fixture.config,
61+
style: {
62+
...fixture.config.style,
63+
rating: {
64+
...fixture.config.style.rating,
65+
position: 'top'
66+
}
67+
}
68+
}
69+
70+
updateConfigInFixture(modifiedConfig);
71+
72+
cy.mount(VueUiRating, {
73+
props: {
74+
dataset: fixture.dataset,
75+
config: modifiedConfig
76+
}
77+
});
78+
79+
cy.get(`[data-cy="rating-position-top"]`)
80+
.should('exist')
81+
.contains(staticRating);
82+
83+
cy.wait(100).then(() => {
84+
modifiedConfig.style.rating.position = "left";
85+
86+
updateConfigInFixture(modifiedConfig);
87+
88+
cy.mount(VueUiRating, {
89+
props: {
90+
dataset: fixture.dataset,
91+
config: modifiedConfig
92+
}
93+
});
94+
95+
cy.get(`[data-cy="rating-position-left"]`)
96+
.should('exist')
97+
.contains(staticRating);
98+
});
99+
100+
cy.wait(100).then(() => {
101+
102+
modifiedConfig.style.rating.position = "right";
103+
104+
105+
updateConfigInFixture(modifiedConfig);
106+
107+
cy.mount(VueUiRating, {
108+
props: {
109+
dataset: fixture.dataset,
110+
config: modifiedConfig
111+
}
112+
});
113+
114+
cy.get(`[data-cy="rating-position-right"]`)
115+
.should('exist')
116+
.contains(staticRating);
117+
});
118+
119+
cy.wait(100).then(() => {
120+
modifiedConfig.style.rating.position = "bottom";
121+
updateConfigInFixture(modifiedConfig);
122+
123+
cy.mount(VueUiRating, {
124+
props: {
125+
dataset: fixture.dataset,
126+
config: modifiedConfig
127+
}
128+
});
129+
});
130+
131+
const items = fixture.config.to - fixture.config.from + 1;
132+
133+
for (let i = 0; i < items; i += 1) {
134+
cy.get(`[data-cy="rating-shape-${i}"]`)
135+
.should('exist')
136+
137+
cy.get(`[data-cy="rating-active-trap-${i}"]`)
138+
.should('exist')
139+
.click();
140+
141+
cy.get(`[data-cy="rating-position-bottom"]`)
142+
.contains(`${i + 1}.0`)
143+
}
144+
145+
cy.wait(100).then(() => {
146+
modifiedConfig.type = "image";
147+
updateConfigInFixture(modifiedConfig);
148+
149+
cy.mount(VueUiRating, {
150+
props: {
151+
dataset: fixture.dataset,
152+
config: modifiedConfig
153+
}
154+
});
155+
156+
for (let i = 0; i < items; i += 1) {
157+
cy.get(`[data-cy="rating-image-${i}"]`).then(($img) => {
158+
cy.wrap($img)
159+
.should('exist')
160+
161+
cy.wrap($img)
162+
.invoke('attr', 'src')
163+
.should('eq', fixture.config.style.image.src)
164+
165+
})
166+
}
167+
168+
});
169+
170+
cy.wait(100).then(() => {
171+
modifiedConfig.readonly = true;
172+
updateConfigInFixture(modifiedConfig);
173+
174+
cy.mount(VueUiRating, {
175+
props: {
176+
dataset: fixture.dataset,
177+
config: modifiedConfig
178+
}
179+
});
180+
181+
for (let i = 0; i < items; i += 1) {
182+
cy.get(`[data-cy="rating-readonly-trap-${i}"]`)
183+
.trigger('mouseenter')
184+
185+
cy.get(`[data-cy="rating-tooltip-${i}"]`)
186+
.should('exist')
187+
.contains(`${Object.keys(fixture.dataset.rating)[i]} : ${fixture.dataset.rating[`${i + 1}`]}`)
188+
}
189+
});
190+
});
191+
});
192+
})

src/components/vue-ui-rating.vue

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,7 @@ const props = defineProps({
2121
const uid = ref(`vue-ui-rating-${Math.random()}`);
2222
2323
const defaultConfig = ref(mainConfig.vue_ui_rating);
24-
25-
const isPrinting = ref(false);
26-
const ratingChart = ref(null);
27-
const tooltip = ref(null);
28-
const details = ref(null);
29-
const clientPosition = ref({
30-
x: 0,
31-
y: 0
32-
});
3324
const isTooltip = ref(false);
34-
const tooltipContent = ref("");
3525
3626
const hoveredValue = ref(undefined);
3727
const units = ref([]);
@@ -138,16 +128,16 @@ defineExpose({
138128
<div :style="`background:${ratingConfig.style.backgroundColor};font-family:${ratingConfig.style.fontFamily};width:100%`" class="vue-ui-rating" @mouseover="isTooltip = true" @mouseleave="isTooltip = false; hoveredValue = undefined">
139129
<!-- TITLE -->
140130
<div class="vue-ui-rating-title" v-if="ratingConfig.style.title.text" style="width:100%">
141-
<div :style="`color:${ratingConfig.style.title.color};font-weight:${ratingConfig.style.title.bold ? 'bold' : 'normal'};text-align:${ratingConfig.style.title.textAlign};margin-bottom:${ratingConfig.style.title.offsetY}px;font-size:${ratingConfig.style.title.fontSize}px`">
131+
<div data-cy="rating-title" :style="`color:${ratingConfig.style.title.color};font-weight:${ratingConfig.style.title.bold ? 'bold' : 'normal'};text-align:${ratingConfig.style.title.textAlign};margin-bottom:${ratingConfig.style.title.offsetY}px;font-size:${ratingConfig.style.title.fontSize}px`">
142132
{{ ratingConfig.style.title.text }}
143133
</div>
144-
<div v-if="ratingConfig.style.title.subtitle.text" :style="`color:${ratingConfig.style.title.subtitle.color};font-size:${ratingConfig.style.title.subtitle.fontSize}px;text-align:${ratingConfig.style.title.textAlign};margin-bottom:${ratingConfig.style.title.subtitle.offsetY}px;font-weight:${ratingConfig.style.title.subtitle.bold ? 'bold' : 'normal'}`">
134+
<div data-cy="rating-subtitle" v-if="ratingConfig.style.title.subtitle.text" :style="`color:${ratingConfig.style.title.subtitle.color};font-size:${ratingConfig.style.title.subtitle.fontSize}px;text-align:${ratingConfig.style.title.textAlign};margin-bottom:${ratingConfig.style.title.subtitle.offsetY}px;font-weight:${ratingConfig.style.title.subtitle.bold ? 'bold' : 'normal'}`">
145135
{{ ratingConfig.style.title.subtitle.text }}
146136
</div>
147137
</div>
148138

149139
<!-- RATING POSITION TOP -->
150-
<div v-if="ratingConfig.style.rating.show && ratingConfig.style.rating.position === 'top'" :style="`width:100%;text-align:center;margin-bottom:${ratingConfig.style.rating.offsetY}px;font-size:${ratingConfig.style.rating.fontSize}px;font-weight:${ratingConfig.style.rating.bold ? 'bold' : 'normal'};margin-left:${ratingConfig.style.rating.offsetX}px`">
140+
<div data-cy="rating-position-top" v-if="ratingConfig.style.rating.show && ratingConfig.style.rating.position === 'top'" :style="`width:100%;text-align:center;margin-bottom:${ratingConfig.style.rating.offsetY}px;font-size:${ratingConfig.style.rating.fontSize}px;font-weight:${ratingConfig.style.rating.bold ? 'bold' : 'normal'};margin-left:${ratingConfig.style.rating.offsetX}px`">
151141
{{ isNaN(currentRating) ? '' : currentRating.toFixed(ratingConfig.style.rating.roundingValue) }}
152142
</div>
153143

@@ -158,7 +148,7 @@ defineExpose({
158148
>
159149

160150
<!-- RATING POSITION LEFT -->
161-
<div v-if="ratingConfig.style.rating.show && ratingConfig.style.rating.position === 'left'" :style="`width:fit-content;text-align:center;margin-bottom:${ratingConfig.style.rating.offsetY}px;font-size:${ratingConfig.style.rating.fontSize}px;font-weight:${ratingConfig.style.rating.bold ? 'bold' : 'normal'};padding-right:${ratingConfig.style.rating.offsetX}px`">
151+
<div data-cy="rating-position-left" v-if="ratingConfig.style.rating.show && ratingConfig.style.rating.position === 'left'" :style="`width:fit-content;text-align:center;margin-bottom:${ratingConfig.style.rating.offsetY}px;font-size:${ratingConfig.style.rating.fontSize}px;font-weight:${ratingConfig.style.rating.bold ? 'bold' : 'normal'};padding-right:${ratingConfig.style.rating.offsetX}px`">
162152
{{ isNaN(currentRating) ? '' : currentRating.toFixed(ratingConfig.style.rating.roundingValue) }}
163153
</div>
164154

@@ -169,7 +159,8 @@ defineExpose({
169159
:style="`position:relative;height:${ratingConfig.style.itemSize}px;width:${ratingConfig.style.itemSize}px`"
170160
>
171161
<!-- IMAGE FIRST LAYER -->
172-
<img
162+
<img
163+
:data-cy="`rating-image-${i}`"
173164
v-if="isImage"
174165
:src="ratingConfig.style.image.src"
175166
:height="ratingConfig.style.itemSize"
@@ -196,6 +187,7 @@ defineExpose({
196187
</radialGradient>
197188
</defs>
198189
<polygon
190+
:data-cy="`rating-shape-${i}`"
199191
:points="createStar({
200192
plot: { x: 50, y: 50 },
201193
radius: 30,
@@ -220,7 +212,8 @@ defineExpose({
220212
</svg>
221213

222214
<!-- IMAGE SECOND LAYER -->
223-
<img
215+
<img
216+
:data-cy="`rating-image-overlay-${i}`"
224217
v-if="isImage"
225218
:src="ratingConfig.style.image.src"
226219
:alt="`${ratingConfig.style.image.alt} ${value}`"
@@ -233,6 +226,7 @@ defineExpose({
233226

234227
<!-- STAR SECOND LAYER -->
235228
<svg
229+
:data-cy="`rating-shape-overlay-${i}`"
236230
v-else
237231
:viewBox="`0 0 ${calcShapeFill(i)} 100`"
238232
:height="ratingConfig.style.itemSize"
@@ -269,6 +263,7 @@ defineExpose({
269263
:style="`position:absolute;top:0;left:0;${isReadonly ? '' : 'cursor:pointer'}`"
270264
>
271265
<rect
266+
:data-cy="`rating-active-trap-${i}`"
272267
class="vue-ui-rating-mouse-trap"
273268
v-if="!isReadonly"
274269
:x="0"
@@ -283,6 +278,7 @@ defineExpose({
283278
@keyup.enter="rate(value)"
284279
/>
285280
<rect
281+
:data-cy="`rating-readonly-trap-${i}`"
286282
class="vue-ui-rating-mouse-trap"
287283
v-if="isReadonly"
288284
:x="0"
@@ -296,7 +292,7 @@ defineExpose({
296292
</svg>
297293
<template v-if="ratingConfig.style.tooltip.show && hasBreakdown && isReadonly">
298294
<div class="vue-ui-rating-tooltip" :style="`border:1px solid ${ratingConfig.style.tooltip.borderColor};position:absolute;top:${-48 + ratingConfig.style.tooltip.offsetY}px;left:50%;transform:translateX(-50%);width:fit-content;text-align:center;background:${ratingConfig.style.tooltip.backgroundColor};display:${hoveredValue === value ? 'block' : 'none'};padding:2px 12px;border-radius:${ratingConfig.style.tooltip.borderRadius}px;box-shadow:${ratingConfig.style.tooltip.boxShadow}`">
299-
<div :style="`width:100%;display:flex;flex-direction:row;gap:6px;position:relative;text-align:center;color:${ratingConfig.style.tooltip.color}`">
295+
<div :data-cy="`rating-tooltip-${i}`" :style="`width:100%;display:flex;flex-direction:row;gap:6px;position:relative;text-align:center;color:${ratingConfig.style.tooltip.color}`">
300296
<span :style="`font-size:${ratingConfig.style.tooltip.fontSize}px`">{{ value }}</span> : <span :style="`font-weight:${ratingConfig.style.tooltip.bold ? 'bold' : 'normal'};font-size:${ratingConfig.style.tooltip.fontSize}px`">{{ props.dataset.rating[value] }}</span>
301297
<div :style="`font-family:Arial !important;position:absolute;top:calc(100% - 4px);left:50%;transform:translateX(-50%);color:${ratingConfig.style.tooltip.borderColor}`">
302298
@@ -309,14 +305,14 @@ defineExpose({
309305

310306

311307
<!-- RATING POSITION RIGHT -->
312-
<div v-if="ratingConfig.style.rating.show && ratingConfig.style.rating.position === 'right'" :style="`width:fit-content;text-align:center;margin-bottom:${ratingConfig.style.rating.offsetY}px;font-size:${ratingConfig.style.rating.fontSize}px;font-weight:${ratingConfig.style.rating.bold ? 'bold' : 'normal'};padding-left:${ratingConfig.style.rating.offsetX}px`">
308+
<div data-cy="rating-position-right" v-if="ratingConfig.style.rating.show && ratingConfig.style.rating.position === 'right'" :style="`width:fit-content;text-align:center;margin-bottom:${ratingConfig.style.rating.offsetY}px;font-size:${ratingConfig.style.rating.fontSize}px;font-weight:${ratingConfig.style.rating.bold ? 'bold' : 'normal'};padding-left:${ratingConfig.style.rating.offsetX}px`">
313309
{{ isNaN(currentRating) ? '' : currentRating.toFixed(ratingConfig.style.rating.roundingValue) }}
314310
</div>
315311

316312
</div>
317313

318314
<!-- RATING POSITION BOTTOM -->
319-
<div v-if="ratingConfig.style.rating.show && ratingConfig.style.rating.position === 'bottom'" :style="`width:100%;text-align:center;margin-top:${ratingConfig.style.rating.offsetY}px;font-size:${ratingConfig.style.rating.fontSize}px;font-weight:${ratingConfig.style.rating.bold ? 'bold' : 'normal'};margin-left:${ratingConfig.style.rating.offsetX}px`">
315+
<div data-cy="rating-position-bottom" v-if="ratingConfig.style.rating.show && ratingConfig.style.rating.position === 'bottom'" :style="`width:100%;text-align:center;margin-top:${ratingConfig.style.rating.offsetY}px;font-size:${ratingConfig.style.rating.fontSize}px;font-weight:${ratingConfig.style.rating.bold ? 'bold' : 'normal'};margin-left:${ratingConfig.style.rating.offsetX}px`">
320316
{{ isNaN(currentRating) ? '' : currentRating.toFixed(ratingConfig.style.rating.roundingValue) }}
321317
</div>
322318

star.png

11.8 KB
Loading

0 commit comments

Comments
 (0)