diff --git a/test/specs/modules/Rating/Rating-test.js b/test/specs/modules/Rating/Rating-test.js new file mode 100644 index 0000000000..d6dba68e10 --- /dev/null +++ b/test/specs/modules/Rating/Rating-test.js @@ -0,0 +1,233 @@ +import _ from 'lodash' +import React from 'react' + +import Rating from 'src/modules/Rating/Rating' +import * as common from 'test/specs/commonTests' +import sandbox from 'test/utils/Sandbox-util' + +describe('Rating', () => { + common.isConformant(Rating) + common.hasUIClassName(Rating) + + common.propValueOnlyToClassName(Rating, 'size') + common.propValueOnlyToClassName(Rating, 'icon') + common.propKeyOnlyToClassName(Rating, 'disabled') + + describe('clicking on icons', () => { + it('makes icons active up to and including the clicked icon', () => { + const wrapper = mount() + const icons = wrapper.find('.icon') + + icons.at(1).simulate('click') + + icons.at(0).should.have.className('active') + icons.at(1).should.have.className('active') + icons.at(2).should.not.have.className('active') + }) + + it('removes the "selected" class', () => { + const wrapper = mount() + const icons = wrapper.find('.icon') + + icons + .last() + .simulate('mouseEnter') + .simulate('click') + + icons.every('.icon.selected') + .should.equal(false, 'Some icon did not remove its "selected" class') + + wrapper.should.not.have.className('selected') + }) + }) + + describe('hovering on icons', () => { + it('adds the "selected" className to the Rating', () => { + const wrapper = shallow() + + wrapper + .find('.icon') + .first() + .simulate('mouseEnter') + + wrapper.should.have.className('selected') + }) + it('selects icons up to and including the hovered icon', () => { + const wrapper = mount() + const icons = wrapper.find('.icon') + + icons.at(1).simulate('mouseEnter') + + icons.at(0).should.have.className('selected') + icons.at(1).should.have.className('selected') + icons.at(2).should.not.have.className('selected') + }) + it('unselects icons on mouse leave', () => { + const wrapper = mount() + const icons = wrapper.find('.icon') + + icons.last().simulate('mouseEnter') + wrapper.simulate('mouseLeave') + + icons.every('.icon.selected') + .should.equal(false, 'Some icon did not remove its "selected" class') + }) + }) + + describe('clearable', () => { + it('prevents clearing by default with multiple icons', () => { + const icons = mount() + .find('.icon') + + icons.find('.active').last().simulate('click') + + icons.every('.icon.active') + .should.equal(true, 'Some icon did not retain its "active" class') + }) + it('allows toggling when set to "auto" with a single icon', () => { + const icon = mount() + .find('.icon') + .at(0) + + icon + .simulate('click') + .should.have.className('active') + + icon + .simulate('click') + .should.not.have.className('active') + }) + it('allows clearing when true with a single icon', () => { + mount() + .find('.icon') + .at(0) + .simulate('click') + .should.not.have.className('active') + }) + it('allows clearing when true with multiple icons', () => { + const icons = mount() + .find('.icon') + + icons.find('.active').last().simulate('click') + + icons.every('.icon.active') + .should.equal(false, 'Some icon did not remove its "active" class') + }) + it('prevents clearing when false with a single icon', () => { + mount() + .find('.icon') + .at(0) + .simulate('click') + .should.have.className('active') + }) + it('prevents clearing when false with multiple icons', () => { + const icons = mount() + .find('.icon') + + icons.find('.active').last().simulate('click') + + icons.every('.icon.active') + .should.equal(true, 'Some icon did not retain its "active" class') + }) + }) + + describe('disabled', () => { + it('prevents the rating from being toggled', () => { + mount() + .find('.icon') + .at(0) + .simulate('click') + .should.have.className('active') + + mount() + .find('.icon') + .at(0) + .simulate('click') + .should.not.have.className('active') + }) + it('prevents the rating from being cleared', () => { + const wrapper = mount() + const icons = wrapper.find('.icon') + + icons.find('.active').last().simulate('click') + + icons.every('.icon.active') + .should.equal(true, 'Some icon lost its "active" class') + }) + it('prevents icons from becoming selected on mouse enter', () => { + const wrapper = mount() + const icons = wrapper.find('.icon') + + icons.last().simulate('mouseEnter') + + icons.every('.icon.selected') + .should.equal(false, 'Some icon became "selected"') + }) + it('prevents icons from becoming unselected on mouse leave', () => { + const wrapper = mount() + const icons = wrapper.find('.icon') + + icons.last().simulate('mouseEnter') + icons.every('.icon.selected') + .should.equal(true, 'Not every icon was selected on mouseEnter') + + wrapper.setProps({ disabled: true }) + wrapper.simulate('mouseLeave') + + icons.every('.icon.selected') + .should.equal(true, 'Some icon lost its "selected" class') + }) + it('prevents icons from becoming active on click', () => { + const wrapper = mount() + const icons = wrapper.find('.icon') + + icons.last().simulate('click') + + icons.every('.icon.active') + .should.equal(false, 'Some icon became "active"') + }) + }) + + describe('maxRating', () => { + it('controls how many icons are displayed', () => { + _.times(10, (i) => { + const maxRating = i + 1 + shallow() + .should.have.exactly(maxRating).descendants('.icon') + }) + }) + }) + + describe('onRate', () => { + it('is called with (event, { rating, maxRating } on icon click', () => { + const spy = sandbox.spy() + const event = { fake: 'event data' } + + shallow() + .find('.icon') + .last() + .simulate('click', event) + + spy.should.have.been.calledOnce() + spy.should.have.been.calledWithMatch(event, { rating: 3, maxRating: 3 }) + }) + }) + + describe('rating', () => { + it('controls how many icons are active', () => { + const wrapper = shallow() + + // rating 0 + wrapper.should.not.have.descendants('.icon.active') + + // rating 1 - 10 + _.times(10, (i) => { + const rating = i + 1 + + wrapper + .setProps({ rating }) + .should.have.exactly(rating).descendants('.icon.active') + }) + }) + }) +})