Skip to content

Commit

Permalink
Merge pull request #336 from TykTechnologies/tests-textarea
Browse files Browse the repository at this point in the history
tests for the Textarea component
  • Loading branch information
ifrim authored Nov 24, 2023
2 parents 90d64d2 + 4c7b54d commit c7fc4fd
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 115 deletions.
120 changes: 118 additions & 2 deletions src/form/components/Textarea/Textarea.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,123 @@
import React from 'react';
import Textarea from './index';

// eslint-disable-next-line react/prop-types
function Component({ children, ...rest }) {
return (
<Textarea {...rest}>
{children}
</Textarea>
);
}

const classes = {
error: 'has-error',
};

const selectors = {
component: '.tyk-form-group',
label: '.tyk-form-group > label',
readonly: '.tyk-form-control--readonly',
error: '.tyk-form-control__error-message',
note: '.tyk-form-control__help-block',
textarea: '.tyk-form-group textarea',
};

describe('Textarea', () => {
it('TODO', () => {
expect(true).to.equal(true);
it('renders the component', () => {
cy.mount(<Component />)
.get(selectors.component)
.should('exist');
});

it('can set theme classes', () => {
const theme1 = 'theme1';
const theme2 = 'theme2';
cy.mount(<Component theme={`${theme1} ${theme2}`} />)
.get(selectors.component)
.should('have.class', `tyk-form-group--${theme1}`)
.and('have.class', `tyk-form-group--${theme2}`);
});

it('can have a custom css class', () => {
const wrapperClassName = 'datepicker-1';
cy.mount(<Component wrapperClassName={wrapperClassName} />)
.get(selectors.component)
.should('have.class', wrapperClassName);
});

it('can renders with a label', () => {
const label = 'my label';
cy.mount(<Component label={label} />)
.get(selectors.label)
.should('exist')
.and('have.text', label);
});

it('can customize the label width', () => {
const labelWidth = '100px';
cy.mount(
<>
<style>
{'.tyk-form-group { display: flex; }'}
</style>
<Component label="my label" labelwidth={labelWidth} />
</>,
)
.get(selectors.label)
.should('have.css', 'width', labelWidth);
});

it('can render with error', () => {
const error = 'my error';
cy.mount(<Component error={error} />)
.get(selectors.component)
.should('have.class', classes.error)
.get(selectors.error)
.should('have.text', error);
});

it('can display a note', () => {
const note = 'please read this';
cy.mount(<Component label="my label" note={note} />)
.get(selectors.note)
.should('exist')
.and('have.text', note);
});

it('in readOnly mode text is displayed, the value or "-" if no value', () => {
cy.mount(<Component readOnly />)
.get(selectors.input)
.should('not.exist')
.get(selectors.readonly)
.should('exist')
.and('have.text', '-');

const value = 'my value';
cy.mount(<Component readOnly value={value} />)
.get(selectors.readonly)
.should('exist')
.and('have.text', value);
});

it('calls the onChange callback when the value changes', () => {
const onChange = cy.stub().as('onChange');
cy.mount(<Component onChange={onChange} />)
.get(selectors.textarea)
.type('something')
.get('@onChange')
.should('be.called');
});

it('the input can be in the disabled state', () => {
cy.mount(<Component disabled />)
.get(selectors.textarea)
.should('have.attr', 'disabled');
});

it('can pass additional attributes to the textarea element using the "input" prop', () => {
cy.mount(<Component input={{ 'data-custom-attribute': 'foo' }} />)
.get(selectors.textarea)
.should('have.attr', 'data-custom-attribute', 'foo');
});
});
205 changes: 92 additions & 113 deletions src/form/components/Textarea/index.js
Original file line number Diff line number Diff line change
@@ -1,131 +1,110 @@
import React, { Component, Fragment } from 'react';
import React from 'react';
import PropTypes from 'prop-types';

export default class Textarea extends Component {
static propTypes = {
disabled: PropTypes.bool,
readOnly: PropTypes.bool,
input: PropTypes.instanceOf(Object),
error: PropTypes.string,
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,
id: PropTypes.string,
theme: PropTypes.string,
value: PropTypes.string,
wrapperClassName: PropTypes.string,
function Textarea({
id,
input,
label,
note,
error,
theme,
labelwidth,
value,
readOnly,
wrapperClassName,
...rest
}) {
const classes = [
'tyk-form-group',
wrapperClassName,
...(theme ? theme.split(' ').map((t) => `tyk-form-group--${t}`) : []),
labelwidth && 'tyk-form-group--label-has-width',
error && 'has-error',
].filter(Boolean).join(' ');

const getLabelStyles = () => {
if (labelwidth) return { flexBasis: labelwidth };
return {};
};

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

if (themes.length) {
themes.forEach((iTheme) => {
cssClasses.push(`tyk-form-group--${iTheme}`);
});
}

if (labelwidth) {
cssClasses.push('tyk-form-group--label-has-width');
}

if (error) {
cssClasses.push('has-error');
}

return cssClasses.join(' ');
}

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

if (labelwidth) {
styles.flexBasis = labelwidth;
}

return styles;
}

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

if (labelwidth) {
styles.flexBasis = `calc(100% - ${labelwidth} - 20px)`;
}

return styles;
}

getTextareaError() {
const { error } = this.props;
const getNonLabelWidth = () => {
if (labelwidth) return { flexBasis: `calc(100% - ${labelwidth} - 20px)` };
return {};
};

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

render() {
const {
id,
input,
label,
note,
value,
readOnly,
...rest
} = this.props;

return (
<Fragment>
<div className={this.getCssClasses()}>
return (
<div className={classes}>
{
label
? <label htmlFor={id} style={getLabelStyles()}>{ label }</label>
: null
}
{!readOnly && (
<div
className="tyk-form-control__wrapper"
style={getNonLabelWidth()}
>
<textarea
className="tyk-form-control"
{...rest}
{...input}
>
{ value }
</textarea>
{
label
? <label htmlFor={id} style={this.getLabelStyles()}>{ label }</label>
note
? <p className="tyk-form-control__help-block">{ note }</p>
: null
}
{!readOnly && (
<div
className="tyk-form-control__wrapper"
style={this.getNonLabelWidth()}
>
<textarea
className="tyk-form-control"
{...rest}
{...input}
>
{ value }
</textarea>
{
note
? <p className="tyk-form-control__help-block">{ note }</p>
: null
}
{this.getTextareaError()}
</div>
)}
{readOnly && <div className="tyk-form-control--readonly">{value || '-'}</div>}
{getTextareaError()}
</div>
</Fragment>
);
}
)}
{readOnly && <div className="tyk-form-control--readonly">{value || '-'}</div>}
</div>
);
}

Textarea.propTypes = {
/** Disable the component */
disabled: PropTypes.bool,
/** Displays only the text value of the component, or "-" if no value is set */
readOnly: PropTypes.bool,
input: PropTypes.instanceOf(Object),
/** Set an error message for the component and the component is rendered in the error state */
error: PropTypes.string,
/** Adds a label to the component */
label: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
PropTypes.element,
PropTypes.func,
PropTypes.string,
]),
/** Sets the width of the label */
labelwidth: PropTypes.string,
/** Set a name for the component */
name: PropTypes.string,
/** Adds additional information under the component */
note: PropTypes.string,
/** Callback function executed on value change */
onChange: PropTypes.func,
id: PropTypes.string,
/** Set a theme for the component */
theme: PropTypes.string,
/** Set the value of the component */
value: PropTypes.string,
/** CSS classes added to the wrapper of the component */
wrapperClassName: PropTypes.string,
};

export default Textarea;

0 comments on commit c7fc4fd

Please sign in to comment.