Skip to content

Commit

Permalink
feat(ffe-buttons-react): Inline expand button
Browse files Browse the repository at this point in the history
This version introduces a React implementation of the inline expand
button. The component is meant to be used at the end of a paragraph
where other related paragraphs start off hidden. Clicking the button
should expand the hidden paragraphs. Composing this functionality is
left to the consumer. See InlineExpandButton.md for an example
implementation.
  • Loading branch information
wkillerud committed Feb 16, 2018
1 parent 70491dd commit c22ce20
Show file tree
Hide file tree
Showing 16 changed files with 228 additions and 134 deletions.
4 changes: 2 additions & 2 deletions packages/ffe-buttons-react/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"overrides": [
{
"files": [ "src/*.test.js"],
"rules": {
"no-unused-expressions": 0
"env": {
"jest": true
}
}
]
Expand Down
43 changes: 22 additions & 21 deletions packages/ffe-buttons-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@
"name": "ffe-buttons-react",
"version": "8.1.7",
"description": "React implementation of ffe-buttons",
"keywords": [
"ffe"
],
"license": "UNLICENSED",
"author": "SpareBank 1",
"main": "lib/index.js",
"scripts": {
"build": "babel -d lib/. --ignore=*.test.js src/.",
"lint": "eslint src/.",
"test": "npm run test:spec && npm run test:nsp",
"test:nsp": "nsp check",
"test:spec": "mocha --require src/util/test-setup.js --compilers js:babel-core/register src/**/*.test.js",
"tdd": "mocha --require src/util/test-setup.js --compilers js:babel-core/register src/**/*.test.js -w"
},
"files": [
"lib",
"*.js"
Expand All @@ -19,26 +16,30 @@
"type": "git",
"url": "***REMOVED***"
},
"scripts": {
"build": "babel -d lib/. --ignore=*.test.js src/.",
"lint": "eslint src/.",
"test:nsp": "nsp check",
"test:watch": "jest --watch",
"test": "jest && npm run test:nsp"
},
"dependencies": {
"classnames": "^2.2.5",
"ffe-icons-react": "^4.0.5",
"prop-types": "^15.6.0"
},
"devDependencies": {
"chai": "^4.1.2",
"chai-enzyme": "^1.0.0-beta.0",
"cheerio": "^0.22.0",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"eslint": "^4.13.1",
"ffe-buttons": "^5.1.9",
"ffe-core": "^11.0.0",
"mocha": "^4.1.0",
"mocha-tap13": "^1.0.2",
"jest": "^22.0.6",
"nsp": "^3.1.0",
"react": "^16.1.1",
"react-dom": "^16.1.1",
"sinon": "^4.1.3"
},
"dependencies": {
"classnames": "^2.2.5",
"ffe-icons-react": "^4.0.5",
"prop-types": "^15.6.0"
"react-dom": "^16.1.1"
},
"license": "UNLICENSED"
"jest": {
"setupTestFrameworkScriptFile": "./test-setup.js"
}
}
16 changes: 8 additions & 8 deletions packages/ffe-buttons-react/src/ActionButton.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/*eslint-env mocha */
import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';

import { ActionButton } from './index';
Expand All @@ -16,38 +14,40 @@ const getWrapper = props =>
describe('ActionButton', () => {
it('renders an action button', () => {
const button = getWrapper();
expect(button).to.have.prop('buttonType', 'action');
expect(button.props()).toHaveProperty('buttonType', 'action');
});

it('passes any prop on to Button', () => {
const button = getWrapper({
'data-analytics-track': 'logMe',
});
expect(button).to.have.attr('data-analytics-track', 'logMe');
expect(button
.dive()
.props()).toHaveProperty('data-analytics-track', 'logMe');
});

describe('👻 ghost modifier 👻', () => {
it('renders without the --ghost modifier if ghost is false', () => {
const button = getWrapper({
ghost: false,
});
expect(button.hasClass('ffe-action-button--ghost')).to.be.false;
expect(button.hasClass('ffe-action-button--ghost')).toBe(false);
});

it('renders the --ghost modifier if ghost is true', () => {
const button = getWrapper({
ghost: true,
});
expect(button.hasClass('ffe-action-button--ghost')).to.be.true;
expect(button.hasClass('ffe-action-button--ghost')).toBe(true);
});

it('renders the --ghost modifier alongside the className value', () => {
const button = getWrapper({
className: 'working-class',
ghost: true,
});
expect(button.hasClass('working-class')).to.be.true;
expect(button.hasClass('ffe-action-button--ghost')).to.be.true;
expect(button.hasClass('working-class')).toBe(true);
expect(button.hasClass('ffe-action-button--ghost')).toBe(true);
});
});
});
10 changes: 3 additions & 7 deletions packages/ffe-buttons-react/src/BackButton.test.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
/*eslint-env mocha */
import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';

import { BackButton } from './index';

describe('BackButton', () => {
it('renders a back button', () => {
const button = shallow(<BackButton />);

expect(button).to.have.prop('buttonType', 'back');
expect(button).to.have.descendants('.ffe-back-button__label');
expect(button.props()).toHaveProperty('buttonType', 'back');
expect(button.find('.ffe-back-button__label').exists()).toBe(true);
});

it('passes any prop on to Button', () => {
const button = shallow(<BackButton disableButton={true} />);

expect(button).to.have.attr('disabled');
expect(button.dive().props()).toHaveProperty('disabled', true);
});
});
82 changes: 34 additions & 48 deletions packages/ffe-buttons-react/src/Button.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
/*eslint-env mocha */
/*eslint-disable no-unused-expressions */

import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import { spy } from 'sinon';

import Button from './index';

Expand All @@ -17,58 +12,53 @@ describe('Button', () => {
});

it('renders a primary button', () => {
expect(button).to.have.className('ffe-primary-button');
expect(button.hasClass('ffe-primary-button')).toBe(true);
});

it('uses child-text as label', () => {
const label = button.find('.ffe-primary-button__label-text');
expect(label).to.have.text('Hello');
expect(label.text()).toBe('Hello');
});

it('is not disabled', () => {
expect(button).to.not.have.prop('disabled');
expect(button).to.not.have.prop('aria-disabled');
expect(button.props()).not.toHaveProperty('disabled', true);
expect(button.props()).not.toHaveProperty('aria-disabled', true);
});

it('does not have --loading modifier', () => {
expect(button).to.not.have.className('ffe-primary-button--loading');

expect(button.hasClass('ffe-primary-button--loading')).toBe(false);
const label = button.find('.ffe-primary-button__label-text');
expect(label).to.not.have.className(
'ffe-primary-button__label-text--loading',
);
expect(label.hasClass('ffe-primary-button__label-text--loading')).toBe(false);
});

it('has aria-hidden on spinner', () => {
expect(
button
expect(button
.find('.ffe-primary-button__label-spinner')
.prop('aria-hidden'),
).to.be.true;
.prop('aria-hidden')).toBe(true);
});
});

describe('given prop', () => {
describe('of random name', () => {
it('passes it on', () => {
const button = shallow(<Button data-analytics-track="logMe" />);
expect(button).to.have.attr('data-analytics-track', 'logMe');
expect(button.props()).toHaveProperty('data-analytics-track', 'logMe');
});
});

describe('label', () => {
it('uses that as label text', () => {
const wrapper = shallow(<Button label="Hello" />);
expect(
wrapper.find('.ffe-primary-button__label-text').text(),
).to.equal('Hello');
expect(wrapper
.find('.ffe-primary-button__label-text')
.text()).toBe('Hello');
});
});

describe('buttonType', () => {
it('has correct ffe button type class', () => {
const button = shallow(<Button buttonType="someRandomType" />);
expect(button).to.have.className('ffe-someRandomType-button');
const button = shallow(<Button buttonType="action" />);
expect(button.hasClass('ffe-action-button')).toBe(true);
});
});

Expand All @@ -80,91 +70,87 @@ describe('Button', () => {
});

it('adds --loading modifier', () => {
expect(button).to.have.className('ffe-primary-button--loading');
expect(button.hasClass('ffe-primary-button--loading')).toBe(true);

const label = button.find('.ffe-primary-button__label-text');
expect(label).to.have.className(
'ffe-primary-button__label-text--loading',
);
expect(label.hasClass('ffe-primary-button__label-text--loading')).toBe(true);
});

it('sets aria-hidden=false on spinner', () => {
const spinner = button.find(
'.ffe-primary-button__label-spinner',
);
expect(spinner).to.have.prop('aria-hidden', false);
expect(spinner.props()).toHaveProperty('aria-hidden', false);
});

it('disables the button', () => {
expect(button).to.have.prop('disabled', true);
expect(button.props()).toHaveProperty('disabled', true);
});

it('marks button as aria-busy', () => {
expect(button).to.have.prop('aria-busy', true);
expect(button.props()).toHaveProperty('aria-busy', true);
});
});

describe('disableButton', () => {
it('disables the button', () => {
const button = shallow(<Button disableButton={true} />);
expect(button).to.have.prop('disabled', true);
expect(button).to.have.prop('aria-disabled', true);
expect(button.props()).toHaveProperty('disabled', true);
expect(button.props()).toHaveProperty('aria-disabled', true);
});
});

describe('onClick', () => {
it('runs the passed function when clicked', () => {
const onClick = spy();
const onClick = jest.fn();
const button = shallow(<Button onClick={onClick} />);
button.simulate('click');
expect(onClick.calledOnce).to.be.true;
expect(onClick).toHaveBeenCalledTimes(1);
});
});

describe('isTabbable', () => {
it('should not set tabIndex', () => {
const button = shallow(<Button isTabbable={true} />);
expect(button).to.not.have.prop('tabIndex');
expect(button.props()).not.toHaveProperty('tabIndex');
});
});

describe('className', () => {
it('has given class', () => {
const button = shallow(<Button className="testClass" />);
expect(button).to.have.className('testClass');
expect(button.hasClass('testClass')).toBe(true);
});
});

describe('autoFocus', () => {
it('can be autoFocused', () => {
const wrapper = shallow(<Button autoFocus={true} />);
expect(wrapper.find('button').prop('autoFocus')).to.be.true;
expect(wrapper
.find('button')
.prop('autoFocus')).toBe(true);
});
});

describe('condensed', () => {
it('has condensed class', () => {
const button = shallow(<Button condensed={true} />);
expect(button).to.have.className(
'ffe-primary-button--condensed',
);
expect(button.hasClass('ffe-primary-button--condensed')).toBe(true);
});
});

describe('element', () => {
it('sets the rendered element', () => {
const link = shallow(
<Button element="a" href="/path">
const link = shallow(<Button element="a" href="/path">
Link
</Button>,
);
expect(link.is('a')).to.be.true;
</Button>);
expect(link.is('a')).toBe(true);
});

it('allows you to pass a component', () => {
const Link = ({ to, ...props }) => <a href={to} {...props} />; // eslint-disable-line react/prop-types
const link = shallow(<Button element={Link} to="/path" />);

expect(link.is('Link')).to.be.true;
expect(link.is('Link')).toBe(true);
});
});
});
Expand Down
15 changes: 6 additions & 9 deletions packages/ffe-buttons-react/src/ExpandButton.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
/*eslint-env mocha */
import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import sinon from 'sinon';

import { ExpandButton } from './index';

Expand All @@ -24,12 +21,12 @@ describe('ExpandButton', () => {
wrapper
.find('.ffe-expand-button')
.hasClass('ffe-expand-button--expanded'),
).to.be.true;
).toBe(true);
expect(
wrapper
.find('.ffe-expand-button__label')
.hasClass('ffe-expand-button__label--expanded'),
).to.be.true;
).toBe(true);
});

it('renders a button and label without the modifiers if isExpanded is false', () => {
Expand All @@ -40,20 +37,20 @@ describe('ExpandButton', () => {
wrapper
.find('.ffe-expand-button')
.hasClass('ffe-expand-button--expanded'),
).to.be.false;
).toBe(false);
expect(
wrapper
.find('.ffe-expand-button__label')
.hasClass('ffe-expand-button__label--expanded'),
).to.be.false;
).toBe(false);
});

it('clicking the button calls onClick', () => {
const onClick = sinon.spy();
const onClick = jest.fn();
const wrapper = getWrapper({
onClick,
});
wrapper.find('button').simulate('click');
expect(onClick.calledOnce).to.be.true;
expect(onClick).toHaveBeenCalledTimes(1);
});
});
Loading

0 comments on commit c22ce20

Please sign in to comment.