Repository: milosjanda/react-scroll-up Branch: master Commit: 7c70c91b3c93 Files: 11 Total size: 32.8 KB Directory structure: gitextract_339vejfy/ ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── index.d.ts ├── index.js ├── package.json ├── scrollUp.jsx └── test/ └── test.jsx ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Dependency directory # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git node_modules npm-debug.log # IntelliJ project files .idea package-lock.json .DS_Store ================================================ FILE: .npmignore ================================================ .idea node_modules npm-debug.log scrollUp.jsx ================================================ FILE: .travis.yml ================================================ language: node_js node_js: - "12" ================================================ FILE: CHANGELOG.md ================================================ # [1.4.0] * **Compatibility:** update dependecies to react 18 # [1.3.7] * **Internal:** Update node version on test # [1.3.6] * **Internal:** Update react dependency and build # [1.3.5] * **Internal:** Add typescript declaration file # [1.3.4] * **Feature:** Add onShow and onHide react props # [1.3.3] * **Bugfix:** Fix peer dependencies to be compliant with semver ranges # [1.3.2] * **Compatibility:** update dependecies to react 16 # [1.3.1] * **Bugfix:** Merge style property instead of override it # [1.3.0] * **Internal:** Rewrite source to ES6 syntax * **Performance:**: Better performance in handleScroll # [1.2.3] * **Compatibility:** Fix deprecated React.PropTypes # [1.2.2] * **Compatibility:** Fix deprecated React.createClass # [1.2.1] * **Bugfix:** fix require of detect-passive-events # [1.2.0] * **Performance:** use of passive listeners to improve scrolling performance # [1.1.5] * **Compatibility:** update dependecies to react 15 # [1.1.4] * **Compatibility:** update for react 15.0 # [1.1.3] * **Compatibility:** Replace function window.scrollY with window.pageYOffset for better compatibility # [1.1.2] * **Bugfix:** Fix stop scrolling if top position reached and add touch events * **Bugfix:** Show element after browser refresh, if page is under top position # [1.1.1] * **Dependency:** update tween function * **Dependency:** update dev dependency * **NPM:** Update npmignore # [1.1.0] ### Other * **Compatibility:** update for react 0.14 # [1.0.4] ### Bug * **Dependency:** fix wrong dependencies # [1.0.3] ### Bug * **Dependency:** fix wrong dependencies # [1.0.2] ### Bug * **Visibility:** set visibility hidden after hide button * **Dependency:** Update dependency information ### Other * **Default value:** change default value of easing # [1.0.1] ### Feature * **Performance:** animate over requestAnimationFrame ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Miloš Janda Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # react-scroll-up [![npm version](https://badge.fury.io/js/react-scroll-up.svg)](https://badge.fury.io/js/react-scroll-up) [![License](https://img.shields.io/npm/l/react-scroll-up.svg)](https://github.com/milosjanda/react-scroll-up/blob/master/LICENSE) [![Dependency Status](https://img.shields.io/david/milosjanda/react-scroll-up.svg)]() [![peerDependency Status](https://img.shields.io/david/peer/milosjanda/react-scroll-up.svg)]() [![Build status](https://travis-ci.org/milosjanda/react-scroll-up.svg?branch=master)](https://travis-ci.org/milosjanda/react-scroll-up) [![Downloads](https://img.shields.io/npm/dm/react-scroll-up.svg)]() React component to add custom button (it can be something what you want) for scroll to top of page. Library uses [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame), if you want better browser compatibility (IE9 and older), you can use something like [https://gist.github.com/paulirish/1579671]. ## Install ```npm npm install react-scroll-up ``` ## How to use it [Live demo](http://milosjanda.github.io/react-scroll-up/) You have to define children element, for example `UP` ```jsx UP ``` ## Parameters ### showUnder:number in px (required) What position (and below) the button will be displayed. ### topPosition:number in px (optional) default: 0 The position to which the scrollbar be moved after clicked. ### easing:string (optional) default: easeOutCubic Type of scrolling easing. You can specify some of this type of easing: https://github.com/chenglou/tween-functions In graphical representation: http://sole.github.io/tween.js/examples/03_graphs.html ### duration:number in miliseconds (optional) default: 250 Time to reach the `topPosition` ### onShow:function (optional) Callback function to be called when the button is being displayed. ### onHide:function (optional) Callback function to be called when the button is being hidden. ### style:object (optional) default: ```javascript { position: 'fixed', bottom: 50, right: 30, cursor: 'pointer', transitionDuration: '0.2s', transitionTimingFunction: 'linear', transitionDelay: '0s' } ``` You can specify you own style and position of the button. Hide/show button is based on opacity, so this styles `opacity` and `transitionProperty` will be all time overwrite. If you can positioned button to left site, you have to reset css property `right: 'auto'`, and similar. ================================================ FILE: index.d.ts ================================================ declare module 'react-scroll-up' { import React, { ReactNode } from 'react'; export interface ScrollToTopProps { showUnder: number, topPosition?: number, easing?: 'linear' | 'easeInQuad' | 'easeOutQuad' | 'easeInOutQuad' | 'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic' | 'easeInQuart' | 'easeOutQuart' | 'easeInOutQuart' | 'easeInQuint' | 'easeOutQuint' | 'easeInOutQuint' | 'easeInSine' | 'easeOutSine' | 'easeInOutSine' | 'easeInExpo' | 'easeOutExpo' | 'easeInOutExpo' | 'easeInCirc' | 'easeOutCirc' | 'easeInOutCirc' | 'easeInElastic' | 'easeOutElastic' | 'easeInOutElastic' | 'easeInBack' | 'easeOutBack' | 'easeInOutBack' | 'easeInBounce' | 'easeOutBounce' | 'easeInOutBounce', duration?: number, style?: object, onShow?: () => void, onHide?: () => void, children?: ReactNode } export default class ScrollToTop extends React.Component {} } ================================================ FILE: index.js ================================================ /** * @author Milos Janda * @licence MIT */ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _tweenFunctions = require('tween-functions'); var _tweenFunctions2 = _interopRequireDefault(_tweenFunctions); var _detectPassiveEvents = require('detect-passive-events'); var _objectAssign = require('object-assign'); var _objectAssign2 = _interopRequireDefault(_objectAssign); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var ScrollUp = function (_React$Component) { _inherits(ScrollUp, _React$Component); function ScrollUp(props) { _classCallCheck(this, ScrollUp); // set default state var _this = _possibleConstructorReturn(this, (ScrollUp.__proto__ || Object.getPrototypeOf(ScrollUp)).call(this, props)); _this.state = { show: false }; // default property `data` _this.data = { startValue: 0, currentTime: 0, // store current time of animation startTime: null, rafId: null }; // bind _this.handleClick = _this.handleClick.bind(_this); _this.handleScroll = _this.handleScroll.bind(_this); _this.scrollStep = _this.scrollStep.bind(_this); _this.stopScrolling = _this.stopScrolling.bind(_this); return _this; } _createClass(ScrollUp, [{ key: 'shouldComponentUpdate', value: function shouldComponentUpdate(nextProps, nextState) { return nextState.show !== this.state.show; } }, { key: 'componentDidMount', value: function componentDidMount() { this.handleScroll(); // initialize state // Add all listeners which can start scroll window.addEventListener('scroll', this.handleScroll); window.addEventListener("wheel", this.stopScrolling, _detectPassiveEvents.supportsPassiveEvents ? { passive: true } : false); window.addEventListener("touchstart", this.stopScrolling, _detectPassiveEvents.supportsPassiveEvents ? { passive: true } : false); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { // Remove all listeners which was registered window.removeEventListener('scroll', this.handleScroll); window.removeEventListener("wheel", this.stopScrolling, false); window.removeEventListener("touchstart", this.stopScrolling, false); } /** * call onShow callback if passed valid props */ }, { key: 'notifyOnShow', value: function notifyOnShow() { if (this.props.onShow && typeof this.props.onShow === "function") { this.props.onShow(); } } /** * call onHide callback if passed valid props */ }, { key: 'notifyOnHide', value: function notifyOnHide() { if (this.props.onHide && typeof this.props.onHide === "function") { this.props.onHide(); } } /** * Evaluate show/hide this component, depend on new position */ }, { key: 'handleScroll', value: function handleScroll() { if (window.pageYOffset > this.props.showUnder) { if (!this.state.show) { this.setState({ show: true }); this.notifyOnShow(); } } else { if (this.state.show) { this.setState({ show: false }); this.notifyOnHide(); } } } /** * Handle click on the button */ }, { key: 'handleClick', value: function handleClick() { this.stopScrolling(); this.data.startValue = window.pageYOffset; this.data.currentTime = 0; this.data.startTime = null; this.data.rafId = window.requestAnimationFrame(this.scrollStep); } /** * Calculate new position * and scroll screen to new position or stop scrolling * @param timestamp */ }, { key: 'scrollStep', value: function scrollStep(timestamp) { if (!this.data.startTime) { this.data.startTime = timestamp; } this.data.currentTime = timestamp - this.data.startTime; var position = _tweenFunctions2.default[this.props.easing](this.data.currentTime, this.data.startValue, this.props.topPosition, this.props.duration); if (window.pageYOffset <= this.props.topPosition) { this.stopScrolling(); } else { window.scrollTo(window.pageYOffset, position); this.data.rafId = window.requestAnimationFrame(this.scrollStep); } } /** * Stop Animation Frame */ }, { key: 'stopScrolling', value: function stopScrolling() { window.cancelAnimationFrame(this.data.rafId); } /** * Render component */ }, { key: 'render', value: function render() { var propStyle = this.props.style; var element = _react2.default.createElement( 'div', { style: propStyle, onClick: this.handleClick }, this.props.children ); var style = (0, _objectAssign2.default)({}, ScrollUp.defaultProps.style); style = (0, _objectAssign2.default)(style, propStyle); style.opacity = this.state.show ? 1 : 0; style.visibility = this.state.show ? 'visible' : 'hidden'; style.transitionProperty = 'opacity, visibility'; return _react2.default.cloneElement(element, { style: style }); } }]); return ScrollUp; }(_react2.default.Component); // Set default props exports.default = ScrollUp; ScrollUp.defaultProps = { duration: 250, easing: 'easeOutCubic', style: { position: 'fixed', bottom: 50, right: 30, cursor: 'pointer', transitionDuration: '0.2s', transitionTimingFunction: 'linear', transitionDelay: '0s' }, topPosition: 0 }; // Set validation property types ScrollUp.propTypes = { topPosition: _propTypes2.default.number, showUnder: _propTypes2.default.number.isRequired, // show button under this position, easing: _propTypes2.default.oneOf(['linear', 'easeInQuad', 'easeOutQuad', 'easeInOutQuad', 'easeInCubic', 'easeOutCubic', 'easeInOutCubic', 'easeInQuart', 'easeOutQuart', 'easeInOutQuart', 'easeInQuint', 'easeOutQuint', 'easeInOutQuint', 'easeInSine', 'easeOutSine', 'easeInOutSine', 'easeInExpo', 'easeOutExpo', 'easeInOutExpo', 'easeInCirc', 'easeOutCirc', 'easeInOutCirc', 'easeInElastic', 'easeOutElastic', 'easeInOutElastic', 'easeInBack', 'easeOutBack', 'easeInOutBack', 'easeInBounce', 'easeOutBounce', 'easeInOutBounce']), duration: _propTypes2.default.number, // seconds style: _propTypes2.default.object, onShow: _propTypes2.default.func, onHide: _propTypes2.default.func }; ================================================ FILE: package.json ================================================ { "name": "react-scroll-up", "version": "1.4.0", "description": "React component to render element for scroll to top of page", "author": "Milos Janda ", "scripts": { "test": "mocha --require babel-core/register test/test.jsx", "build": "babel scrollUp.jsx --out-file index.js", "prepublish": "npm run test && npm run build" }, "main": "index.js", "repository": { "type": "git", "url": "https://github.com/milosjanda/react-scroll-up.git" }, "bug": { "url": "https://github.com/milosjanda/react-scroll-up/issues" }, "keywords": [ "scroll", "scrollUp", "scrollToTop", "animation", "effects", "react", "react-component" ], "babel": { "presets": [ "es2015", "react" ] }, "dependencies": { "detect-passive-events": "^2.0.2", "object-assign": "^4.0.1", "prop-types": "^15.5.8", "tween-functions": "^1.1.0" }, "peerDependencies": { "react": "0.13 - 18" }, "devDependencies": { "babel-cli": "^6.26.0", "babel-core": "^6.26.3", "babel-preset-es2015": "6.24.1", "babel-preset-react": "6.24.1", "chai": "^4.2.0", "chai-enzyme": "^1.0.0-beta.1", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", "jsdom": "^16.4.0", "mocha": "^8.2.1", "raf": "^3.4.1", "react": "^18.0.0", "react-dom": "^18.0.0", "react-test-renderer": "^18.0.0", "sinon": "^9.2.1" }, "readmeFilename": "README.md", "license": "MIT" } ================================================ FILE: scrollUp.jsx ================================================ /** * @author Milos Janda * @licence MIT */ 'use strict'; import React from 'react'; import PropTypes from 'prop-types'; import TweenFunctions from 'tween-functions'; import { supportsPassiveEvents } from 'detect-passive-events'; import objectAssign from 'object-assign'; export default class ScrollUp extends React.Component { constructor(props) { super(props); // set default state this.state = {show: false}; // default property `data` this.data = { startValue: 0, currentTime: 0, // store current time of animation startTime: null, rafId: null }; // bind this.handleClick = this.handleClick.bind(this); this.handleScroll = this.handleScroll.bind(this); this.scrollStep = this.scrollStep.bind(this); this.stopScrolling = this.stopScrolling.bind(this); } shouldComponentUpdate(nextProps, nextState) { return nextState.show !== this.state.show; } componentDidMount() { this.handleScroll(); // initialize state // Add all listeners which can start scroll window.addEventListener('scroll', this.handleScroll); window.addEventListener("wheel", this.stopScrolling, supportsPassiveEvents ? { passive: true } : false); window.addEventListener("touchstart", this.stopScrolling, supportsPassiveEvents ? { passive: true } : false); } componentWillUnmount() { // Remove all listeners which was registered window.removeEventListener('scroll', this.handleScroll); window.removeEventListener("wheel", this.stopScrolling, false); window.removeEventListener("touchstart", this.stopScrolling, false); } /** * call onShow callback if passed valid props */ notifyOnShow() { if (this.props.onShow && typeof this.props.onShow === "function") { this.props.onShow(); } } /** * call onHide callback if passed valid props */ notifyOnHide() { if (this.props.onHide && typeof this.props.onHide === "function") { this.props.onHide(); } } /** * Evaluate show/hide this component, depend on new position */ handleScroll() { if (window.pageYOffset > this.props.showUnder) { if (!this.state.show) { this.setState({show: true}); this.notifyOnShow(); } } else { if (this.state.show) { this.setState({show: false}); this.notifyOnHide(); } } } /** * Handle click on the button */ handleClick() { this.stopScrolling(); this.data.startValue = window.pageYOffset; this.data.currentTime = 0; this.data.startTime = null; this.data.rafId = window.requestAnimationFrame(this.scrollStep); } /** * Calculate new position * and scroll screen to new position or stop scrolling * @param timestamp */ scrollStep(timestamp) { if (!this.data.startTime) { this.data.startTime = timestamp; } this.data.currentTime = timestamp - this.data.startTime; let position = TweenFunctions[this.props.easing]( this.data.currentTime, this.data.startValue, this.props.topPosition, this.props.duration ); if (window.pageYOffset <= this.props.topPosition) { this.stopScrolling(); } else { window.scrollTo(window.pageYOffset, position); this.data.rafId = window.requestAnimationFrame(this.scrollStep); } } /** * Stop Animation Frame */ stopScrolling() { window.cancelAnimationFrame(this.data.rafId); } /** * Render component */ render() { let propStyle = this.props.style; let element =
{this.props.children}
; let style = objectAssign({}, ScrollUp.defaultProps.style); style = objectAssign(style, propStyle); style.opacity = (this.state.show ? 1 : 0); style.visibility = (this.state.show ? 'visible' : 'hidden'); style.transitionProperty = 'opacity, visibility'; return React.cloneElement(element, {style: style}); } } // Set default props ScrollUp.defaultProps = { duration: 250, easing: 'easeOutCubic', style: { position: 'fixed', bottom: 50, right: 30, cursor: 'pointer', transitionDuration: '0.2s', transitionTimingFunction: 'linear', transitionDelay: '0s' }, topPosition: 0 }; // Set validation property types ScrollUp.propTypes = { topPosition: PropTypes.number, showUnder: PropTypes.number.isRequired, // show button under this position, easing: PropTypes.oneOf(['linear', 'easeInQuad', 'easeOutQuad', 'easeInOutQuad', 'easeInCubic', 'easeOutCubic', 'easeInOutCubic', 'easeInQuart', 'easeOutQuart', 'easeInOutQuart', 'easeInQuint', 'easeOutQuint', 'easeInOutQuint', 'easeInSine', 'easeOutSine', 'easeInOutSine', 'easeInExpo', 'easeOutExpo', 'easeInOutExpo', 'easeInCirc', 'easeOutCirc', 'easeInOutCirc', 'easeInElastic', 'easeOutElastic', 'easeInOutElastic', 'easeInBack', 'easeOutBack', 'easeInOutBack', 'easeInBounce', 'easeOutBounce', 'easeInOutBounce']), duration: PropTypes.number, // seconds style: PropTypes.object, onShow: PropTypes.func, onHide: PropTypes.func }; ================================================ FILE: test/test.jsx ================================================ // JSDom is used to allow the tests to run right from the command line (no browsers needed) const jsdom = require("jsdom"); const { JSDOM } = jsdom; const dom = new JSDOM(`

Test

`); // noinspection JSConstantReassignment global.window = dom.window; // noinspection JSConstantReassignment global.document = dom.window.document; // Also apply a requestAnimationFrame polyfill require('raf').polyfill(); import React from 'react'; import { after, before, beforeEach, describe, it } from "mocha"; import sinon from 'sinon'; import { expect } from 'chai'; import { shallow } from 'enzyme'; // https://github.com/airbnb/enzyme/issues/465 shallow vs mount vs render import chai from 'chai'; // https://github.com/producthunt/chai-enzyme#setup import chaiEnzyme from 'chai-enzyme'; import Enzyme from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; chai.use(chaiEnzyme()); // Note the invocation at the end import TestUtils from 'react-dom/test-utils'; import ScrollUp from '../scrollUp'; Enzyme.configure({ adapter: new Adapter() }); // describe makes a test group describe(' states', function () { // This will be run before each test to reset the scroll position beforeEach(() => { window.pageYOffset = 0; }); // and each `it` function describes an individual test it('is hidden when first rendered', function () { let renderedComponent = TestUtils.renderIntoDocument( UP ); expect(renderedComponent.state.show).to.be.false; }); it('is shown if the page is scrolled past the `showUnder` point', function () { let renderedComponent = TestUtils.renderIntoDocument( UP ); // Set the scroll position to 200 and trigger the event manually window.pageYOffset = 200; renderedComponent.handleScroll(); expect(renderedComponent.state.show).to.be.true; }); }); // describe makes a test group describe(' move 1', function () { let scrollToSpy; let renderedComponent; before(() => { window.pageYOffset = 0; renderedComponent = TestUtils.renderIntoDocument( UP ); // "stub" the window.scrollTo function (because we want to see how it's called) scrollToSpy = sinon.stub(global.window, 'scrollTo').callsFake( (x, y) => { window.pageXOffset = x; window.pageYOffset = y; renderedComponent.handleScroll(); // And make sure to trigger the handleScroll for each call }); }); after(() => { scrollToSpy.restore(); }); it('scrolls back up to the top when clicked', function (done) { // Ensure topPosition is set correctly expect(renderedComponent.props.topPosition).to.equal(0); // Set the scroll position to 200 and trigger the event manually window.pageYOffset = 200; renderedComponent.handleScroll(); // Now activate the click function renderedComponent.handleClick(); // Give it a bit to scroll back up setTimeout(() => { expect(scrollToSpy.lastCall.args[1]).to.within(-0.1, 0.1); expect(renderedComponent.state.show).to.be.false; done(); }, 500); }); }); // describe makes a test group describe(' move 2', function () { let scrollToSpy; let renderedComponent; before(() => { window.pageYOffset = 0; renderedComponent = TestUtils.renderIntoDocument( UP ); // "stub" the window.scrollTo function (because we want to see how it's called) scrollToSpy = sinon.stub(global.window, 'scrollTo').callsFake( (x, y) => { window.pageXOffset = x; window.pageYOffset = y; renderedComponent.handleScroll(); // And make sure to trigger the handleScroll for each call }); }); after(() => { scrollToSpy.restore(); }); it('scrolls to `topPosition` when clicked', (done) => { // Ensure topPosition is set correctly expect(renderedComponent.props.topPosition).to.equal(100); // Set the scroll position to 200 and trigger the event manually window.pageYOffset = 200; renderedComponent.handleScroll(); // Now activate the click function renderedComponent.handleClick(); // Give it a bit to scroll back up setTimeout(() => { expect(scrollToSpy.lastCall.args[1]).to.be.within(95, 105); expect(renderedComponent.state.show).to.be.false; done(); }, 500); }); }); // describe makes a test group describe(' Styles', function () { it('check rendered styles - default values - hidden', () => { const wrapper = shallow( UP ); wrapper.setState({show: false}); // default styles expect(wrapper).to.have.style("position", 'fixed'); expect(wrapper).to.have.style("bottom", '50px'); expect(wrapper).to.have.style("right", '30px'); expect(wrapper).to.have.style("cursor", 'pointer'); expect(wrapper).to.have.style("transition-duration", '0.2s'); expect(wrapper).to.have.style("transition-timing-function", 'linear'); expect(wrapper).to.have.style("transition-delay", '0s'); expect(wrapper).to.have.style("opacity" , '0'); expect(wrapper).to.have.style("visibility", 'hidden'); expect(wrapper).to.have.style("transition-property", 'opacity, visibility'); }); it('check rendered styles - default values - visible', () => { const wrapper = shallow( UP ); wrapper.setState({show: true}); // default styles expect(wrapper).to.have.style("position", 'fixed'); expect(wrapper).to.have.style("bottom", '50px'); expect(wrapper).to.have.style("right", '30px'); expect(wrapper).to.have.style("cursor", 'pointer'); expect(wrapper).to.have.style("transition-duration", '0.2s'); expect(wrapper).to.have.style("transition-timing-function", 'linear'); expect(wrapper).to.have.style("transition-delay", '0s'); expect(wrapper).to.have.style("opacity" , '1'); expect(wrapper).to.have.style("visibility", 'visible'); expect(wrapper).to.have.style("transition-property", 'opacity, visibility'); }); it('check rendered styles - custom values', () => { const wrapper = shallow( UP ); // to check override opacity wrapper.setState({show: true}); // default styles expect(wrapper).to.have.style("position", 'fixed'); expect(wrapper).to.have.style("bottom", '50px'); expect(wrapper).to.have.style("cursor", 'pointer'); expect(wrapper).to.have.style("transition-duration", '0.2s'); expect(wrapper).to.have.style("transition-timing-function", 'linear'); expect(wrapper).to.have.style("transition-delay", '0s'); // overrides by props, but have to still value respective state expect(wrapper).to.have.style("opacity" , '1'); expect(wrapper).to.have.style("visibility", 'visible'); expect(wrapper).to.have.style("transition-property", 'opacity, visibility'); // overrides default values expect(wrapper).to.have.style("right", '20px'); // props styles expect(wrapper).to.have.style("z-index", '3'); }); }); // describe makes a test group describe(' children', function () { it('check if children is rendered ', () => { window.pageYOffset = 500; const wrapper = shallow( UP ); expect(wrapper.find('span')).to.have.text('UP'); }); }); // describe makes a test group describe(' onShow onHide props', function () { // This will be run before each test to reset the scroll position beforeEach(() => { window.pageYOffset = 0; }); it('check onShow callback is working properly', function () { let calledOnShow = false; let renderedComponent = TestUtils.renderIntoDocument( { calledOnShow = true }}> UP ); // is hidden when first rendered expect(renderedComponent.state.show).to.be.false; // Set the scroll position to 200 and trigger the event manually window.pageYOffset = 200; renderedComponent.handleScroll(); expect(renderedComponent.state.show).to.be.true; // button is now displayed expect(calledOnShow).to.be.true; // and callback was called }); it('check onHide callback is working properly', function () { let calledOnHide = false; let renderedComponent = TestUtils.renderIntoDocument( { calledOnHide = true }}> UP ); // is hidden when first rendered expect(renderedComponent.state.show).to.be.false; // Set the scroll position to 200 and trigger the event manually window.pageYOffset = 200; renderedComponent.handleScroll(); expect(renderedComponent.state.show).to.be.true; // button is now displayed expect(calledOnHide).to.be.false; // and callback was not yet called // Set the scroll position to 50 and trigger the event manually window.pageYOffset = 50; renderedComponent.handleScroll(); expect(renderedComponent.state.show).to.be.false; // button is now hidden expect(calledOnHide).to.be.true; // and callback was called }); });