Skip to content

Commit

Permalink
Using decorators for static method and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
wwayne committed Jun 14, 2016
1 parent acd6d17 commit 732b1bc
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 42 deletions.
3 changes: 2 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"presets": ["es2015", "react"]
"presets": ["es2015", "react", "stage-0"],
"plugins": ["transform-decorators-legacy"],
}
16 changes: 11 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ EXAMPLE_SRC = example/src
STANDALONE = standalone
SRC = src
DIST = dist
TEST = test/*.test.js
MOCHA_OPTS = --compilers js:babel-core/register --require test/setup.js -b --timeout 20000 --reporter spec

lint:
@echo linting...
@echo Linting...
@$(NODE_BIN)/standard --verbose | $(NODE_BIN)/snazzy src/index.js

convertCss:
test: lint
@echo Start testing...
@$(NODE_BIN)/mocha $(MOCHA_OPTS) $(TEST)

convertCSS:
@echo Converting css...
@node bin/transferSass.js

Expand All @@ -24,7 +30,7 @@ dev:
@echo starting dev server...
@rm -rf $(EXAMPLE_DIST)
@mkdir -p $(EXAMPLE_DIST)
@make convertCss
@make convertCSS
@$(NODE_BIN)/watchify -t babelify $(EXAMPLE_SRC)/index.js -o $(EXAMPLE_DIST)/index.js -dv
@$(NODE_BIN)/node-sass $(EXAMPLE_SRC)/index.scss $(EXAMPLE_DIST)/index.css
@$(NODE_BIN)/node-sass -w $(EXAMPLE_SRC)/index.scss $(EXAMPLE_DIST)/index.css
Expand All @@ -44,10 +50,10 @@ deployCSS:
deploy: lint
@echo Deploy...
@rm -rf dist && mkdir dist
@make convertCss
@make convertCSS
@make deployCSS
@make deployJS
@make genStand
@echo success!

.PHONY: lint convertCss genStand dev deployJS deployCSS deploy
.PHONY: lint convertCSS genStand dev deployJS deployCSS deploy
13 changes: 12 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "react tooltip component",
"main": "index.js",
"scripts": {
"test": "make lint",
"test": "make test",
"dev": "make start",
"deploy": "make deploy"
},
Expand Down Expand Up @@ -46,15 +46,26 @@
},
"devDependencies": {
"babel-cli": "^6.5.1",
"babel-core": "^6.9.1",
"babel-eslint": "^4.1.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-runtime": "^6.5.0",
"babel-preset-es2015": "^6.5.0",
"babel-preset-react": "^6.5.0",
"babel-preset-stage-0": "^6.5.0",
"babelify": "^7.2.0",
"browserify": "^13.0.0",
"browserify-shim": "^3.8.12",
"chai": "^3.5.0",
"chai-enzyme": "^0.5.0",
"cheerio": "^0.20.0",
"enzyme": "^2.3.0",
"http-server": "^0.8.0",
"jsdom": "^9.2.1",
"mocha": "^2.5.3",
"node-sass": "^3.3.2",
"react-addons-test-utils": "^15.1.0",
"sinon": "^1.17.4",
"snazzy": "^2.0.1",
"standard": "^5.2.2",
"tape": "^4.2.0",
Expand Down
7 changes: 7 additions & 0 deletions src/constant.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default {

GLOBAL: {
HIDE: '__react_tooltip_hide_event',
REBUILD: '__react_tooltip_rebuild_event'
}
}
37 changes: 37 additions & 0 deletions src/decorators/staticMethods.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Static methods for react-tooltip
*/
import CONSTANT from '../constant'

const dispatchGlobalEvent = (eventName) => {
// Compatibale with IE
// @see http://stackoverflow.com/questions/26596123/internet-explorer-9-10-11-event-constructor-doesnt-work
let event

if (typeof window.Event === 'function') {
event = new window.Event(eventName)
} else {
event = document.createEvent('Event')
event.initEvent(eventName, false, true)
}

window.dispatchEvent(event)
}

export default function (target) {
/**
* Hide all tooltip
* @trigger ReactTooltip.hide()
*/
target.hide = () => {
dispatchGlobalEvent(CONSTANT.GLOBAL.HIDE)
}

/**
* Rebuild all tooltip
* @trigger ReactTooltip.rebuild()
*/
target.rebuild = () => {
dispatchGlobalEvent(CONSTANT.GLOBAL.REBUILD)
}
}
26 changes: 26 additions & 0 deletions src/decorators/windowListener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Events that should be bound to the window
*/
import CONSTANT from '../constant'

export default function (target) {
target.prototype.bindWindowEvents = function () {
// ReactTooltip.hide
window.removeEventListener(CONSTANT.GLOBAL.HIDE, this.globalHide)
window.addEventListener(CONSTANT.GLOBAL.HIDE, this.globalHide, false)

// ReactTooltip.rebuild
window.removeEventListener(CONSTANT.GLOBAL.REBUILD, this.globalRebuild)
window.addEventListener(CONSTANT.GLOBAL.REBUILD, this.globalRebuild, false)

// Resize
window.removeEventListener('resize', this.onWindowResize)
window.addEventListener('resize', this.onWindowResize, false)
}

target.prototype.unbindWindowEvents = function () {
window.removeEventListener(CONSTANT.GLOBAL.HIDE, this.globalHide)
window.removeEventListener(CONSTANT.GLOBAL.REBUILD, this.globalRebuild)
window.removeEventListener('resize', this.onWindowResize)
}
}
79 changes: 44 additions & 35 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,43 @@
import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'
import classname from 'classnames'

/* Decoraters */
import staticMethods from './decorators/staticMethods'
import windowListener from './decorators/windowListener'

/* CSS */
import cssStyle from './style'

@staticMethods @windowListener
class ReactTooltip extends Component {
/**
* Class method
* @see ReactTooltip.hide() && ReactTooltup.rebuild()
*/
static hide () {
/**
* Check for ie
* @see http://stackoverflow.com/questions/26596123/internet-explorer-9-10-11-event-constructor-doesnt-work
*/
if (typeof window.Event === 'function') {
window.dispatchEvent(new window.Event('__react_tooltip_hide_event'))
} else {
let event = document.createEvent('Event')
event.initEvent('__react_tooltip_hide_event', false, true)
window.dispatchEvent(event)
}
}

static rebuild () {
if (typeof window.Event === 'function') {
window.dispatchEvent(new window.Event('__react_tooltip_rebuild_event'))
} else {
let event = document.createEvent('Event')
event.initEvent('__react_tooltip_rebuild_event', false, true)
window.dispatchEvent(event)
}
}
// static hide () {
// /**
// * Check for ie
// * @see http://stackoverflow.com/questions/26596123/internet-explorer-9-10-11-event-constructor-doesnt-work
// */
// if (typeof window.Event === 'function') {
// window.dispatchEvent(new window.Event('__react_tooltip_hide_event'))
// } else {
// let event = document.createEvent('Event')
// event.initEvent('__react_tooltip_hide_event', false, true)
// window.dispatchEvent(event)
// }
// }

// static rebuild () {
// if (typeof window.Event === 'function') {
// window.dispatchEvent(new window.Event('__react_tooltip_rebuild_event'))
// } else {
// let event = document.createEvent('Event')
// event.initEvent('__react_tooltip_rebuild_event', false, true)
// window.dispatchEvent(event)
// }
// }

globalHide () {
if (this.mount) {
Expand Down Expand Up @@ -83,15 +90,16 @@ class ReactTooltip extends Component {
componentDidMount () {
this.bindListener()
this.setStyleHeader()
/* Add window event listener for hide and rebuild */
window.removeEventListener('__react_tooltip_hide_event', this.globalHide)
window.addEventListener('__react_tooltip_hide_event', this.globalHide, false)

window.removeEventListener('__react_tooltip_rebuild_event', this.globalRebuild)
window.addEventListener('__react_tooltip_rebuild_event', this.globalRebuild, false)
/* Add listener on window resize */
window.removeEventListener('resize', this.onWindowResize)
window.addEventListener('resize', this.onWindowResize, false)
this.bindWindowEvents()
// /* Add window event listener for hide and rebuild */
// window.removeEventListener('__react_tooltip_hide_event', this.globalHide)
// window.addEventListener('__react_tooltip_hide_event', this.globalHide, false)

// window.removeEventListener('__react_tooltip_rebuild_event', this.globalRebuild)
// window.addEventListener('__react_tooltip_rebuild_event', this.globalRebuild, false)
// /* Add listener on window resize */
// window.removeEventListener('resize', this.onWindowResize)
// window.addEventListener('resize', this.onWindowResize, false)
}

componentWillUpdate () {
Expand All @@ -109,9 +117,10 @@ class ReactTooltip extends Component {
this.unbindListener()
this.removeScrollListener()
this.mount = false
window.removeEventListener('__react_tooltip_hide_event', this.globalHide)
window.removeEventListener('__react_tooltip_rebuild_event', this.globalRebuild)
window.removeEventListener('resize', this.onWindowResize)
this.unbindWindowEvents()
// window.removeEventListener('__react_tooltip_hide_event', this.globalHide)
// window.removeEventListener('__react_tooltip_rebuild_event', this.globalRebuild)
// window.removeEventListener('resize', this.onWindowResize)
}

/* TODO: optimize, bind has been trigger too many times */
Expand Down
32 changes: 32 additions & 0 deletions test/globalMethods.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* For Standard.js lint checking */
/* eslint-env mocha */

import React from 'react'
import { mount } from 'enzyme'
import chai, { expect } from 'chai'
import chaiEnzyme from 'chai-enzyme'
import sinon from 'sinon'
import ReactTooltip from '../src'

/* Initial test tools */
chai.use(chaiEnzyme())

describe('Global methods', () => {
it('should be hided by invoking ReactTooltip.hide', () => {
const wrapper = mount(<ReactTooltip />)
wrapper.setState({ show: true })
expect(wrapper).to.have.state('show', true)
ReactTooltip.hide()
setImmediate(() => {
expect(wrapper).to.have.state('show', false)
})
})

it('should be rebuild by invoking ReactTooltip.rebuild', () => {
sinon.spy(ReactTooltip.prototype, 'globalRebuild')
ReactTooltip.rebuild()
setImmediate(() => {
expect(ReactTooltip.prototype.globalRebuild.calledOnce).to.equal(true)
})
})
})
20 changes: 20 additions & 0 deletions test/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Setup jsdom for enzyme mount
* @see https://github.com/airbnb/enzyme/blob/master/docs/guides/jsdom.md#using-enzyme-with-jsdom
*/
import {jsdom} from 'jsdom'

const exposedProperties = ['window', 'navigator', 'document']

global.document = jsdom('')
global.window = document.defaultView
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
exposedProperties.push(property)
global[property] = document.defaultView[property]
}
})

global.navigator = {
userAgent: 'node.js'
}

0 comments on commit 732b1bc

Please sign in to comment.