From 7c4d735c80993fb2950b5d2bba6307da9bc95544 Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Wed, 7 Jun 2017 23:09:11 +0300 Subject: [PATCH] #85: tests for rules page --- .eslintrc.json | 11 ++-- src/pages/rules/RulesPage.jsx | 57 +++++++++++---------- src/pages/rules/RulesPage.test.js | 85 +++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 34 deletions(-) create mode 100644 src/pages/rules/RulesPage.test.js diff --git a/.eslintrc.json b/.eslintrc.json index 1646a0f..c7857e1 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -35,10 +35,6 @@ "es6": true }, - "globals": { - "sinon": false // needed for tests. Apply it globaly till eslint/selint#3611 - }, - "extends": "eslint:recommended", // @see: http://eslint.org/docs/rules/ @@ -191,7 +187,8 @@ "require-yield": "error", // react - "react/display-name": "warn", + "react/display-name": "off", + "react/react-in-jsx-scope": "warn", "react/forbid-prop-types": "warn", "react/jsx-boolean-value": "warn", "react/jsx-closing-bracket-location": "off", // can not configure for our code style @@ -202,7 +199,7 @@ "react/jsx-max-props-per-line": ["warn", {"maximum": 3}], "react/jsx-no-bind": "off", "react/jsx-no-duplicate-props": "warn", - "react/jsx-no-literals": "warn", + "react/jsx-no-literals": "off", "react/jsx-no-undef": "error", "react/jsx-pascal-case": "warn", "react/jsx-uses-react": "warn", @@ -221,6 +218,6 @@ "react/prefer-es6-class": "warn", "react/prop-types": "warn", "react/self-closing-comp": "warn", - "react/sort-comp": ["warn", {"order": ["lifecycle", "render", "everything-else"]}] + "react/sort-comp": ["off", {"order": ["lifecycle", "render", "everything-else"]}] } } diff --git a/src/pages/rules/RulesPage.jsx b/src/pages/rules/RulesPage.jsx index b20d6c8..c29a61f 100644 --- a/src/pages/rules/RulesPage.jsx +++ b/src/pages/rules/RulesPage.jsx @@ -1,4 +1,5 @@ -import React, { Component, PropTypes } from 'react'; +// @flow +import React, { Component } from 'react'; import { Link } from 'react-router-dom'; import { FormattedMessage as Message } from 'react-intl'; @@ -19,12 +20,12 @@ const rules = [ { title: , items: [ - {projectName}) }} />, - , - , - , + , + https://account.ely.by/register) }} /> ] @@ -32,13 +33,13 @@ const rules = [ { title: , items: [ - , - , - , - , - , - , - + , + , + , + , + , + , + ] }, { @@ -52,22 +53,23 @@ const rules = [

), items: [ - , - + , + ] } ]; export default class RulesPage extends Component { - static propTypes = { - location: PropTypes.shape({ - pathname: PropTypes.string, - search: PropTypes.string, - hash: PropTypes.string - }).isRequired, - history: PropTypes.shape({ - replace: PropTypes.func - }).isRequired + props: { + location: { + pathname: string, + search: string, + hash: string + }, + + history: { + replace: Function + } }; render() { @@ -128,8 +130,11 @@ export default class RulesPage extends Component { ); } - onRuleClick(event) { - if (event.defaultPrevented || event.target.tagName.toLowerCase() === 'a') { + onRuleClick(event: MouseEvent & {target: HTMLElement, currentTarget: HTMLElement}) { + if (event.defaultPrevented + || !event.currentTarget.id + || event.target.tagName.toLowerCase() === 'a' + ) { // some-one have already processed this event or it is a link return; } @@ -148,5 +153,3 @@ export default class RulesPage extends Component { return `${RulesPage.getTitleHash(sectionIndex)}-${ruleIndex + 1}`; } } - -RulesPage.displayName = 'RulesPage'; diff --git a/src/pages/rules/RulesPage.test.js b/src/pages/rules/RulesPage.test.js new file mode 100644 index 0000000..0ae12ad --- /dev/null +++ b/src/pages/rules/RulesPage.test.js @@ -0,0 +1,85 @@ +import React from 'react'; + +import sinon from 'sinon'; +import expect from 'unexpected'; +import {shallow} from 'enzyme'; + +import RulesPage from './RulesPage'; + +describe('RulesPage', () => { + describe('#onRuleClick()', () => { + const id = 'rule-1-2'; + const pathname = '/foo'; + const search = '?bar'; + let page; + let replace; + + beforeEach(() => { + replace = sinon.stub().named('history.replace'); + + page = shallow(); + }); + + it('should update location on rule click', () => { + const expectedUrl = `/foo?bar#${id}`; + + page.find(`#${id}`).simulate('click', { + target: { + tagName: 'li' + }, + + currentTarget: { + id + } + }); + + expect(replace, 'to have a call satisfying', [expectedUrl]); + }); + + it('should not update location if link was clicked', () => { + page.find(`#${id}`).simulate('click', { + target: { + tagName: 'a' + }, + + currentTarget: { + id + } + }); + + expect(replace, 'was not called'); + }); + + it('should not update location if defaultPrevented', () => { + page.find(`#${id}`).simulate('click', { + defaultPrevented: true, + + target: { + tagName: 'li' + }, + + currentTarget: { + id + } + }); + + expect(replace, 'was not called'); + }); + + it('should not update location if no id', () => { + page.find(`#${id}`).simulate('click', { + target: { + tagName: 'li' + }, + + currentTarget: { + } + }); + + expect(replace, 'was not called'); + }); + }); +});