Skip to content

Commit

Permalink
Merge pull request #348 from TykTechnologies/TUI-11/tests-file-input
Browse files Browse the repository at this point in the history
tests for the FileInput component
  • Loading branch information
ifrim authored Jan 19, 2024
2 parents 6216662 + b588d69 commit 44d6eba
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 108 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ jobs:
-Dsonar.organization=tyktechnologies
-Dsonar.projectKey=TykTechnologies_tyk-ui
-Dsonar.sources=./src
-Dsonar.coverage.exclusions=cypress/**/*.js,**/*.test.js,src/form/components/Combobox/*.js,src/form/redux-form/**/*.js
-Dsonar.cpd.exclusions=**/*.test.js,src/form/redux-form/**/*,src/common/fonts/**/*
-Dsonar.coverage.exclusions=cypress/**/*.js,**/*.test.js,src/form/components/Combobox/*.js,src/form/components/Input/*.js,src/form/redux-form/**/*.js
-Dsonar.cpd.exclusions=**/*.test.js,src/form/redux-form/**/*,src/common/fonts/**/*,src/form/components/Combobox/*.js,src/form/components/Input/*.js
-Dsonar.test.inclusions=**/*.test.js
-Dsonar.tests=./src
-Dsonar.javascript.lcov.reportPaths=coverage/lcov.info
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ jobs:
-Dsonar.organization=tyktechnologies
-Dsonar.projectKey=TykTechnologies_tyk-ui
-Dsonar.sources=./src
-Dsonar.coverage.exclusions=cypress/**/*.js,**/*.test.js,src/form/components/Combobox/*.js,src/form/redux-form/**/*.js
-Dsonar.cpd.exclusions=**/*.test.js,src/form/redux-form/**/*,src/common/fonts/**/*
-Dsonar.coverage.exclusions=cypress/**/*.js,**/*.test.js,src/form/components/Combobox/*.js,src/form/components/Input/*.js,src/form/redux-form/**/*.js
-Dsonar.cpd.exclusions=**/*.test.js,src/form/redux-form/**/*,src/common/fonts/**/*,src/form/components/Combobox/*.js,src/form/components/Input/*.js
-Dsonar.test.inclusions=**/*.test.js
-Dsonar.tests=./src
-Dsonar.javascript.lcov.reportPaths=coverage/lcov.info
Expand Down
86 changes: 84 additions & 2 deletions src/form/components/FileInput/FileInput.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,89 @@
import React, { useState } from 'react';
import FileInput from './index';

describe('FileInput', () => {
it('TODO', () => {
expect(true).to.equal(true);
it('sets classes', () => {
cy.mount(
<FileInput
theme="default rounded-corners"
value={null}
wrapperClassName="myclass"
/>,
);

cy.get('.myclass')
.should('exist')
.and('have.class', 'tyk-form-group--default')
.and('have.class', 'tyk-form-group--rounded-corners');
});

it('displays the label with the correct width', () => {
cy.mount(
<FileInput
theme="default inline rounded-corners"
label="my label"
labelwidth="200px"
/>,
);

cy.get('label')
.should('have.text', 'my label')
.and('have.css', 'width', '200px');
});

it('displays errors and notes', () => {
cy.mount(
<FileInput
theme="default rounded-corners"
error="Something wrong"
note="This is important to know."
/>,
);

cy.get('.tyk-form-group')
.should('have.class', 'has-error');
cy.get('.tyk-form-control__help-block')
.should('have.text', 'This is important to know.');
cy.get('.tyk-form-control__error-message')
.should('have.text', 'Something wrong');
});

it('calls onChange callback with the current value and clears the value when clicking the clear value button', () => {
const onChange = cy.stub().as('onChange');
const file = {
contents: Cypress.Buffer.from('file contents'),
fileName: 'file.txt',
mimeType: 'text/plain',
lastModified: Date.now(),
};

// eslint-disable-next-line react/prop-types
function Component({ onChangeCallback }) {
const [, setFiles] = useState(null);

function onComponentChange(value) {
setFiles(value);
if (onChangeCallback) onChangeCallback(value);
}
return (
<FileInput
// eslint-disable-next-line react/jsx-no-bind
onChange={onComponentChange}
/>
);
}

cy.mount(<Component onChangeCallback={onChange} />);

cy.get('input')
.selectFile(file, { force: true });

cy.get('@onChange')
.should('be.calledWithMatch', Cypress.sinon.match((x) => x instanceof FileList && x[0].name === 'file.txt'));

cy.get('button')
.click();
cy.get('@onChange')
.should('be.calledWith', '');
});
});
174 changes: 77 additions & 97 deletions src/form/components/FileInput/index.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,28 @@
import React, { Component, Fragment, createRef } from 'react';
import React, { useRef } from 'react';
import PropTypes from 'prop-types';

import Icon from '../../../components/Icon';

export default class FileInput extends Component {
static propTypes = {
accept: PropTypes.string,
disabled: PropTypes.bool,
id: PropTypes.string,
error: PropTypes.oneOfType([
PropTypes.string,
PropTypes.bool,
]),
label: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
PropTypes.element,
PropTypes.func,
PropTypes.string,
]),
labelwidth: PropTypes.string,
name: PropTypes.string,
note: PropTypes.string,
onChange: PropTypes.func,
placeholder: PropTypes.string,
theme: PropTypes.string,
value: PropTypes.instanceOf(Object),
wrapperClassName: PropTypes.string,
}

constructor(props) {
super(props);

this.handleOnChange = this.handleOnChange.bind(this);
this.clearValue = this.clearValue.bind(this);
this.fileInputRef = createRef();
function FileInput({
error,
theme,
labelwidth,
wrapperClassName = '',
id,
label,
note,
accept,
value,
onChange,
...rest
}) {
const fileInputRef = useRef();

function handleOnChange(e) {
onChange(e.target.files);
}

getCssClasses() {
const {
error, theme, labelwidth, wrapperClassName = '',
} = this.props;
function getCssClasses() {
const cssClasses = [wrapperClassName, 'tyk-form-group'];
const themes = theme ? theme.split(' ') : [];

Expand All @@ -61,8 +43,7 @@ export default class FileInput extends Component {
return cssClasses.join(' ');
}

getLabelStyles() {
const { labelwidth } = this.props;
function getLabelStyles() {
const styles = {};

if (labelwidth) {
Expand All @@ -72,8 +53,7 @@ export default class FileInput extends Component {
return styles;
}

getNonLabelWidth() {
const { labelwidth } = this.props;
function getNonLabelWidth() {
const styles = {};

if (labelwidth) {
Expand All @@ -83,44 +63,37 @@ export default class FileInput extends Component {
return styles;
}

getFileInputError() {
const { error } = this.props;

function getFileInputError() {
return (error && error !== 'true' && error !== 'false')
? (
<p
className="tyk-form-control__error-message"
>
<p className="tyk-form-control__error-message">
{ error }
</p>
)
: null;
}

getFileInputComponent() {
const {
accept, value: omitValue, onChange, ...rest
} = this.props;

function getFileInputComponent() {
return (
<div
className="tyk-file-input__wrapper"
style={this.getNonLabelWidth()}
style={getNonLabelWidth()}
>
<input
accept={accept}
className="tyk-form-control"
{...rest}
onChange={this.handleOnChange}
ref={this.fileInputRef}
onChange={handleOnChange}
ref={fileInputRef}
type="file"
/>
{
this.fileInputRef.current && this.fileInputRef.current.files.length > 0
fileInputRef.current && fileInputRef.current.files.length > 0
? (
<button
onClick={this.clearValue}
onClick={clearValue}
type="button"
aria-label="clear value"
>
<Icon type="times" />
</button>
Expand All @@ -131,47 +104,54 @@ export default class FileInput extends Component {
);
}

clearValue() {
const { onChange } = this.props;
this.fileInputRef.current.value = '';
function clearValue() {
fileInputRef.current.value = '';
onChange('');
}

handleOnChange(e) {
const { onChange } = this.props;

onChange(e.target.files);
}

// eslint-disable-next-line class-methods-use-this
reset() {}

render() {
const {
id,
label,
note,
} = this.props;

return (
<Fragment>
<div className={this.getCssClasses()}>
{
label
? <label htmlFor={id} style={this.getLabelStyles()}>{ label }</label>
: null
}
<div className="tyk-form-control__wrapper">
{ this.getFileInputComponent() }
{
note
? <p className="tyk-form-control__help-block">{ note }</p>
: null
}
</div>
{ this.getFileInputError() }
</div>
</Fragment>
);
}
return (
<div className={getCssClasses()}>
{
label
? <label htmlFor={id} style={getLabelStyles()}>{ label }</label>
: null
}
<div className="tyk-form-control__wrapper">
{ getFileInputComponent() }
{
note
? <p className="tyk-form-control__help-block">{ note }</p>
: null
}
</div>
{ getFileInputError() }
</div>
);
}

FileInput.propTypes = {
accept: PropTypes.string,
disabled: PropTypes.bool,
id: PropTypes.string,
error: PropTypes.oneOfType([
PropTypes.string,
PropTypes.bool,
]),
label: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
PropTypes.element,
PropTypes.func,
PropTypes.string,
]),
labelwidth: PropTypes.string,
name: PropTypes.string,
note: PropTypes.string,
onChange: PropTypes.func,
placeholder: PropTypes.string,
theme: PropTypes.string,
value: PropTypes.instanceOf(Object),
wrapperClassName: PropTypes.string,
};

export default FileInput;
9 changes: 4 additions & 5 deletions src/form/components/Input2/Input2.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe('Input2', () => {
});

it('calls onChange callback with the current value', () => {
const onChange = cy.stub();
const onChange = cy.stub().as('onChange');

cy.mount(
<Input2
Expand All @@ -85,10 +85,9 @@ describe('Input2', () => {
);

cy.get('input')
.type('foo')
.then(() => {
expect(onChange).to.be.calledWith(Cypress.sinon.match.any, 'foo');
});
.type('foo');
cy.get('@onChange')
.should('be.calledWith', Cypress.sinon.match.any, 'foo');
});

it('renders no input in readonly mode', () => {
Expand Down

0 comments on commit 44d6eba

Please sign in to comment.