(cherry picked from commit 47d1d83673)
Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
This commit is contained in:
co-authored by
Levente Balogh
parent
b288d6c805
commit
50d614098a
@@ -0,0 +1,60 @@
|
||||
import React, { useState, ChangeEvent } from 'react';
|
||||
import { Story, Meta } from '@storybook/react';
|
||||
import { SecretInput, Props } from './SecretInput';
|
||||
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||
|
||||
export default {
|
||||
title: 'Forms/SecretInput',
|
||||
component: SecretInput,
|
||||
decorators: [withCenteredStory],
|
||||
parameters: {
|
||||
controls: {
|
||||
exclude: [
|
||||
'prefix',
|
||||
'suffix',
|
||||
'addonBefore',
|
||||
'addonAfter',
|
||||
'type',
|
||||
'disabled',
|
||||
'invalid',
|
||||
'loading',
|
||||
'before',
|
||||
'after',
|
||||
],
|
||||
},
|
||||
},
|
||||
args: {
|
||||
width: 50,
|
||||
placeholder: 'Enter your secret...',
|
||||
},
|
||||
argTypes: {
|
||||
width: { control: { type: 'range', min: 10, max: 200, step: 10 } },
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
const Template: Story<Props> = (args) => {
|
||||
const [secret, setSecret] = useState('');
|
||||
|
||||
return (
|
||||
<SecretInput
|
||||
width={args.width}
|
||||
value={secret}
|
||||
isConfigured={args.isConfigured}
|
||||
placeholder={args.placeholder}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => setSecret(event.target.value.trim())}
|
||||
onReset={() => setSecret('')}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const basic = Template.bind({});
|
||||
|
||||
basic.args = {
|
||||
isConfigured: false,
|
||||
};
|
||||
|
||||
export const secretIsConfigured = Template.bind({});
|
||||
|
||||
secretIsConfigured.args = {
|
||||
isConfigured: true,
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { SecretInput, RESET_BUTTON_TEXT, CONFIGURED_TEXT } from './SecretInput';
|
||||
|
||||
const PLACEHOLDER_TEXT = 'Your secret...';
|
||||
|
||||
describe('<SecretInput />', () => {
|
||||
it('should render an input if the secret is not configured', () => {
|
||||
render(<SecretInput isConfigured={false} onChange={() => {}} onReset={() => {}} placeholder={PLACEHOLDER_TEXT} />);
|
||||
|
||||
const input = screen.getByPlaceholderText(PLACEHOLDER_TEXT);
|
||||
|
||||
// Should show an enabled input
|
||||
expect(input).toBeInTheDocument();
|
||||
expect(input).not.toBeDisabled();
|
||||
|
||||
// Should not show a "Reset" button
|
||||
expect(screen.queryByRole('button', { name: RESET_BUTTON_TEXT })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render a disabled input with a reset button if the secret is already configured', () => {
|
||||
render(<SecretInput isConfigured={true} onChange={() => {}} onReset={() => {}} placeholder={PLACEHOLDER_TEXT} />);
|
||||
|
||||
const input = screen.getByPlaceholderText(PLACEHOLDER_TEXT);
|
||||
|
||||
// Should show a disabled input
|
||||
expect(input).toBeInTheDocument();
|
||||
expect(input).toBeDisabled();
|
||||
expect(input).toHaveValue(CONFIGURED_TEXT);
|
||||
|
||||
// Should show a reset button
|
||||
expect(screen.queryByRole('button', { name: RESET_BUTTON_TEXT })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should be possible to reset a configured secret', () => {
|
||||
const onReset = jest.fn();
|
||||
|
||||
render(<SecretInput isConfigured={true} onChange={() => {}} onReset={onReset} placeholder={PLACEHOLDER_TEXT} />);
|
||||
|
||||
// Should show a reset button and a disabled input
|
||||
expect(screen.queryByPlaceholderText(PLACEHOLDER_TEXT)).toBeDisabled();
|
||||
expect(screen.queryByRole('button', { name: RESET_BUTTON_TEXT })).toBeInTheDocument();
|
||||
|
||||
// Click on "Reset"
|
||||
userEvent.click(screen.getByRole('button', { name: RESET_BUTTON_TEXT }));
|
||||
|
||||
expect(onReset).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should be possible to change the value of the secret', () => {
|
||||
const onChange = jest.fn();
|
||||
|
||||
render(<SecretInput isConfigured={false} onChange={onChange} onReset={() => {}} placeholder={PLACEHOLDER_TEXT} />);
|
||||
|
||||
const input = screen.getByPlaceholderText(PLACEHOLDER_TEXT);
|
||||
|
||||
expect(input).toHaveValue('');
|
||||
|
||||
userEvent.type(input, 'Foo');
|
||||
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
expect(input).toHaveValue('Foo');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import * as React from 'react';
|
||||
import { Input } from '../Input/Input';
|
||||
import { HorizontalGroup } from '../Layout/Layout';
|
||||
import { Button } from '../Button';
|
||||
|
||||
export type Props = React.ComponentProps<typeof Input> & {
|
||||
/** TRUE if the secret was already configured. (It is needed as often the backend doesn't send back the actual secret, only the information that it was configured) */
|
||||
isConfigured: boolean;
|
||||
/** Called when the user clicks on the "Reset" button in order to clear the secret */
|
||||
onReset: () => void;
|
||||
};
|
||||
|
||||
export const CONFIGURED_TEXT = 'configured';
|
||||
export const RESET_BUTTON_TEXT = 'Reset';
|
||||
|
||||
export const SecretInput = ({ isConfigured, onReset, ...props }: Props) => (
|
||||
<HorizontalGroup>
|
||||
{!isConfigured && <Input {...props} type="password" />}
|
||||
{isConfigured && <Input {...props} type="text" disabled={true} value={CONFIGURED_TEXT} />}
|
||||
{isConfigured && (
|
||||
<Button onClick={onReset} variant="secondary">
|
||||
{RESET_BUTTON_TEXT}
|
||||
</Button>
|
||||
)}
|
||||
</HorizontalGroup>
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
export { SecretInput } from './SecretInput';
|
||||
Reference in New Issue
Block a user