diff --git a/packages/components/molecules/f-rating/CHANGELOG.md b/packages/components/molecules/f-rating/CHANGELOG.md
index 5d1baf6355..f815c412a9 100644
--- a/packages/components/molecules/f-rating/CHANGELOG.md
+++ b/packages/components/molecules/f-rating/CHANGELOG.md
@@ -3,6 +3,19 @@
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+v0.4.0
+------------------------------
+*October 19, 2022*
+
+### Added
+- Test coverage for code changes.
+- `starRatingSize` to allow component sizing.
+- Prop validation.
+
+### Changed
+- Refactored markup to allow fractional rating sizes.
+
+
v0.3.0
------------------------------
*October 17, 2022*
diff --git a/packages/components/molecules/f-rating/README.md b/packages/components/molecules/f-rating/README.md
index 46085d5a80..25d08f4f94 100644
--- a/packages/components/molecules/f-rating/README.md
+++ b/packages/components/molecules/f-rating/README.md
@@ -73,6 +73,7 @@ The props that can be defined are as follows (if any):
| :--- |:--------:|:--------:|:-------:|:-----------------------------------------------------------------------------------------------------------------------|
| `starRating` | `Number` | Yes | - | Sets the displayed rating (filled stars). i.e. for `2 out of x`, 2 would be the `starRating` |
| `maxStarRating` | `Number` | No | 5 | Sets the maximum number of stars that the rating is set against. i.e. for `x out of 5`, 5 would be the `maxStarRating` |
+| `starRatingSize` | `String` | No | 'small' | Sets the component size. By default the component will use `small` the other options are `medium` & `large` |
### Events
diff --git a/packages/components/molecules/f-rating/package.json b/packages/components/molecules/f-rating/package.json
index ec7afcd7e9..60495f6f22 100644
--- a/packages/components/molecules/f-rating/package.json
+++ b/packages/components/molecules/f-rating/package.json
@@ -1,7 +1,7 @@
{
"name": "@justeat/f-rating",
"description": "Fozzie Rating - Global Rating component",
- "version": "0.3.0",
+ "version": "0.4.0",
"main": "dist/f-rating.umd.min.js",
"maxBundleSize": "20kB",
"files": [
diff --git a/packages/components/molecules/f-rating/src/components/Rating.vue b/packages/components/molecules/f-rating/src/components/Rating.vue
index 524f1d40ac..15f1827464 100644
--- a/packages/components/molecules/f-rating/src/components/Rating.vue
+++ b/packages/components/molecules/f-rating/src/components/Rating.vue
@@ -2,25 +2,39 @@
-
- -
-
+
+
-
-
-
- {{ getRatingDescription }}
-
+ v-for="star in maxStarRating"
+ :key="star"
+ :class="[
+ $style['c-rating-star-empty'],
+ $style[`c-rating-star--${starRatingSize}`]
+ ]" />
+
+
+
+
+
+
+
+ {{ getRatingDescription }}
+
+
@@ -31,6 +45,7 @@ import {
} from '@justeattakeaway/pie-icons-vue';
import { VueGlobalisationMixin } from '@justeat/f-globalisation';
import tenantConfigs from '../tenants';
+import { VALID_STAR_RATING_SIZES } from '../constants';
export default {
name: 'VRating',
@@ -48,11 +63,17 @@ export default {
},
starRating: {
type: Number,
- required: true
+ required: true,
+ validator: value => value >= 0 && value <= 5
},
maxStarRating: {
type: Number,
default: 5
+ },
+ starRatingSize: {
+ type: String,
+ default: 'small',
+ validator: value => !!VALID_STAR_RATING_SIZES[value]
}
},
@@ -80,18 +101,15 @@ export default {
rating: this.starRating,
total: this.maxStarRating
});
- }
- },
+ },
- methods: {
/**
- * Check `star` against value passed by consumer to allow empty stars to render.
+ * Calculate a percentage from the `starRating` value passed in by the consuming application.
*
- * @param star {Number}
- * @returns {boolean}
+ * @returns {string}
*/
- isRatingStarFilled (star) {
- return star <= this.starRating;
+ getRatingStarPercentage () {
+ return `${(this.starRating / this.maxStarRating) * 100}%`;
}
}
};
@@ -103,12 +121,25 @@ export default {
.c-rating-starWrapper {
margin: 0;
padding: 0;
- list-style-type: none;
+ position: relative;
+ display: inline-block;
}
+ .c-rating-container {
+ display: flex;
+ }
.c-rating-star {
- display: inline-block;
- width: 15px; // Todo - decide on how to size these. Will create a ticket around this.
+ &--small {
+ width: 12px;
+ }
+
+ &--medium {
+ width: 16px;
+ }
+
+ &--large {
+ width: 28px;
+ }
}
.c-rating-star-filled {
@@ -122,4 +153,16 @@ export default {
fill: f.$color-mozzarella-50;
}
}
+
+ .c-rating-mask {
+ position: absolute;
+ top: 0;
+ left: 0;
+ overflow: hidden;
+ width: var(--starRatingPercentage);
+
+ svg {
+ flex-shrink: 0;
+ }
+ }
diff --git a/packages/components/molecules/f-rating/src/components/_tests/Rating.test.js b/packages/components/molecules/f-rating/src/components/_tests/Rating.test.js
index 70cfac5168..bb697b61ba 100644
--- a/packages/components/molecules/f-rating/src/components/_tests/Rating.test.js
+++ b/packages/components/molecules/f-rating/src/components/_tests/Rating.test.js
@@ -30,74 +30,39 @@ describe('Rating', () => {
expect(wrapper.exists()).toBe(true);
});
- describe('methods', () => {
- describe('`isRatingStarFilled`', () => {
+ describe('computed', () => {
+ describe('`getRatingStarPercentage`', () => {
it('should exist', () => {
- expect(wrapper.vm.isRatingStarFilled).toBeDefined();
- });
-
- it('should contain a description `c-rating-description`', () => {
- // Act
- const result = wrapper.find('[data-test-id="c-rating-description"]');
+ // Arrange
+ propsData.starRating = 2;
+ wrapper = shallowMount(VRating, {
+ propsData,
+ localVue,
+ i18n
+ });
- // Assert
- expect(result).toMatchSnapshot();
+ // Act & Assert
+ expect(wrapper.vm.getRatingStarPercentage).toBeDefined();
});
describe('when invoked', () => {
- it('should return truthy when the argument `star` is less than or equal to `starRating`', () => {
- // Act
- const star = 1;
- const result = wrapper.vm.isRatingStarFilled(star);
-
- // Assert
- expect(result).toBe(true);
- });
-
- it.each([1, 2])('should return truthy when the argument star is %s', value => {
+ it('should return a percentage from a combination of `starRating` and `maxStarRating`', () => {
// Arrange
propsData = {
- starRating: value,
- maxStarRating: 5
+ starRating: 2
};
-
- // Act
wrapper = shallowMount(VRating, {
propsData,
localVue,
- i18n,
- mocks: {
- $tc
- }
+ i18n
});
- const result = wrapper.vm.isRatingStarFilled(value);
-
- // Assert
- expect(result).toBe(true);
- });
-
- it('should return truthy when the argument `star` is equal to `starRating`', () => {
- // Act
- const star = 2;
- const result = wrapper.vm.isRatingStarFilled(star);
- // Assert
- expect(result).toBe(true);
- });
-
- it('should return falsey when argument `star` is greater than `starRating`', () => {
- // Act
- const star = 3;
- const result = wrapper.vm.isRatingStarFilled(star);
-
- // Assert
- expect(result).toBe(false);
+ // Act & Assert
+ expect(wrapper.vm.getRatingStarPercentage).toBe('40%');
});
});
});
- });
- describe('computed', () => {
describe('`getRatingDescription`', () => {
it('should exist', () => {
// Arrange
@@ -145,4 +110,52 @@ describe('Rating', () => {
});
});
});
+
+ describe('props', () => {
+ describe('`starRatingSize`', () => {
+ it('should set a default value of `small`', () => {
+ // Act & Assert
+ expect(VRating.props.starRatingSize.default).toBe('small');
+ });
+
+ it('should return a true when type prop of exists', () => {
+ // Act
+ const { validator } = VRating.props.starRatingSize;
+
+ // Arrange
+ expect(validator('small')).toBe(true);
+ });
+
+ it('should NOT allow invalid props', () => {
+ // Arrange
+ const { validator } = VRating.props.starRatingSize;
+
+ // Act & Assert
+ expect(validator('supernova')).toBe(false);
+ });
+ });
+
+ describe('`starRating`', () => {
+ it('should be required', () => {
+ // Act & Assert
+ expect(VRating.props.starRating.required).toBe(true);
+ });
+
+ it.each([0, 1, 2, 3, 4, 5])('should allow value `%s`', rating => {
+ // Act
+ const { validator } = VRating.props.starRating;
+
+ // Assert
+ expect(validator(rating)).toBe(true);
+ });
+
+ it('should NOT only allow values outside `0 - 5`', () => {
+ // Arrange
+ const { validator } = VRating.props.starRating;
+
+ // Act & Assert
+ expect(validator(6)).toBe(false);
+ });
+ });
+ });
});
diff --git a/packages/components/molecules/f-rating/src/components/_tests/__snapshots__/Rating.test.js.snap b/packages/components/molecules/f-rating/src/components/_tests/__snapshots__/Rating.test.js.snap
index ef953d7f7c..312ca3e643 100644
--- a/packages/components/molecules/f-rating/src/components/_tests/__snapshots__/Rating.test.js.snap
+++ b/packages/components/molecules/f-rating/src/components/_tests/__snapshots__/Rating.test.js.snap
@@ -3,9 +3,3 @@
exports[`Rating computed \`getRatingDescription\` when invoked should return a plural description if the rating is greater than 1 1`] = `"2 stars out of 5"`;
exports[`Rating computed \`getRatingDescription\` when invoked should return a singular description if the rating is less than 2 1`] = `"1 star out of 5"`;
-
-exports[`Rating methods \`isRatingStarFilled\` should contain a description \`c-rating-description\` 1`] = `
-
-
-
-`;
diff --git a/packages/components/molecules/f-rating/src/constants.js b/packages/components/molecules/f-rating/src/constants.js
new file mode 100644
index 0000000000..abac44c400
--- /dev/null
+++ b/packages/components/molecules/f-rating/src/constants.js
@@ -0,0 +1,6 @@
+// eslint-disable-next-line import/prefer-default-export
+export const VALID_STAR_RATING_SIZES = {
+ small: true,
+ medium: true,
+ large: true
+};
diff --git a/packages/components/molecules/f-rating/src/tests/constants.test.js b/packages/components/molecules/f-rating/src/tests/constants.test.js
new file mode 100644
index 0000000000..242fa6b1b9
--- /dev/null
+++ b/packages/components/molecules/f-rating/src/tests/constants.test.js
@@ -0,0 +1,17 @@
+import { VALID_STAR_RATING_SIZES } from '../constants';
+
+describe('`constants`', () => {
+ describe('VALID_STAR_RATING_SIZES', () => {
+ it('should contain the correct sizes', () => {
+ // Arrange
+ const values = {
+ small: true,
+ medium: true,
+ large: true
+ };
+
+ // Act & Assert
+ expect(VALID_STAR_RATING_SIZES).toEqual(values);
+ });
+ });
+});
diff --git a/packages/components/molecules/f-rating/stories/Rating.stories.js b/packages/components/molecules/f-rating/stories/Rating.stories.js
index c14e834a9d..e60b1d6d27 100644
--- a/packages/components/molecules/f-rating/stories/Rating.stories.js
+++ b/packages/components/molecules/f-rating/stories/Rating.stories.js
@@ -14,7 +14,8 @@ export const RatingComponent = (args, { argTypes }) => ({
template: ``
+ :starRatingSize="'medium'"
+ :starRating="2.5" />`
});
RatingComponent.storyName = 'f-rating';