Add testing identifier to elements

This commit is contained in:
lethemanh
2024-12-09 21:14:46 +07:00
parent df5c472d7b
commit 217e683269
43 changed files with 201 additions and 102 deletions
@@ -12,6 +12,7 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
loading?: boolean; loading?: boolean;
disabled?: boolean; disabled?: boolean;
children?: React.ReactNode; children?: React.ReactNode;
testClassId?: string;
} }
export const Button = (props: ButtonProps) => { export const Button = (props: ButtonProps) => {
@@ -65,10 +66,12 @@ export const Button = (props: ButtonProps) => {
' inline-flex items-center px-4 py-2 border font-medium rounded-md focus:outline-none ' + ' inline-flex items-center px-4 py-2 border font-medium rounded-md focus:outline-none ' +
className + className +
' ' + ' ' +
props.className props.className +
' ' +
`testid:${props.testClassId}`
} }
disabled={disabled} disabled={disabled}
{..._.omit(props, 'loading', 'children', 'className', 'icon', 'iconSize')} {..._.omit(props, 'loading', 'children', 'className', 'icon', 'iconSize', 'testClassId')}
> >
{props.loading && ( {props.loading && (
<> <>
@@ -1,9 +1,11 @@
import _ from "lodash";
import { isUndefined } from "lodash"; import { isUndefined } from "lodash";
interface CheckboxSliderProps extends React.InputHTMLAttributes<HTMLInputElement> { interface CheckboxSliderProps extends React.InputHTMLAttributes<HTMLInputElement> {
checked?: boolean; checked?: boolean;
disabled?: boolean; disabled?: boolean;
noFocusBorder?: boolean; noFocusBorder?: boolean;
testClassId?: string;
} }
/** Just classes up a checkbox to look like a slider. Deviates from onChange etc for /** Just classes up a checkbox to look like a slider. Deviates from onChange etc for
* compatibility with `InputHTMLAttributes<HTMLInputElement>`, to expose eg. id to use with htmlFor. * compatibility with `InputHTMLAttributes<HTMLInputElement>`, to expose eg. id to use with htmlFor.
@@ -15,13 +17,17 @@ export const CheckboxSlider = (props: CheckboxSliderProps) => {
return ( return (
<input <input
{...props} {..._.omit(props, 'testClassId')}
type="checkbox" type="checkbox"
role="switch" role="switch"
style={styles} style={styles}
// @author https://tw-elements.com/docs/react/forms/switch/ // @author https://tw-elements.com/docs/react/forms/switch/
className="!bg-none mr-2 mt-[0.3rem] h-7 w-14 appearance-none rounded-[0.9rem] bg-neutral-300 before:pointer-events-none before:absolute before:h-7 before:w-5 before:rounded-full before:bg-transparent before:content-[''] after:absolute after:z-[2] after:mt-[0.2rem] after:ml-[0.2rem] after:h-5 after:w-5 after:rounded-full after:border-none after:bg-neutral-100 after:shadow-[0_0px_3px_0_rgb(0_0_0_/_7%),_0_2px_2px_0_rgb(0_0_0_/_4%)] after:transition-[background-color_0.2s,transform_0.2s] after:content-[''] checked:bg-primary checked:after:absolute checked:after:z-[2] checked:after:ml-[1.9625rem] checked:after:w-5 checked:after:rounded-full checked:after:border-none checked:after:bg-primary checked:after:shadow-[0_3px_1px_-2px_rgba(0,0,0,0.2),_0_2px_2px_0_rgba(0,0,0,0.14),_0_1px_5px_0_rgba(0,0,0,0.12)] checked:after:transition-[background-color_0.2s,transform_0.2s] checked:after:content-[''] hover:cursor-pointer dark:bg-neutral-600 dark:after:bg-white dark:checked:bg-primary dark:checked:after:bg-primary disabled:cursor-default disabled:opacity-25 !focus:shadow-none" className={[
"!bg-none mr-2 mt-[0.3rem] h-7 w-14 appearance-none rounded-[0.9rem] bg-neutral-300 before:pointer-events-none before:absolute before:h-7 before:w-5 before:rounded-full before:bg-transparent before:content-[''] after:absolute after:z-[2] after:mt-[0.2rem] after:ml-[0.2rem] after:h-5 after:w-5 after:rounded-full after:border-none after:bg-neutral-100 after:shadow-[0_0px_3px_0_rgb(0_0_0_/_7%),_0_2px_2px_0_rgb(0_0_0_/_4%)] after:transition-[background-color_0.2s,transform_0.2s] after:content-[''] checked:bg-primary checked:after:absolute checked:after:z-[2] checked:after:ml-[1.9625rem] checked:after:w-5 checked:after:rounded-full checked:after:border-none checked:after:bg-primary checked:after:shadow-[0_3px_1px_-2px_rgba(0,0,0,0.2),_0_2px_2px_0_rgba(0,0,0,0.14),_0_1px_5px_0_rgba(0,0,0,0.12)] checked:after:transition-[background-color_0.2s,transform_0.2s] checked:after:content-[''] hover:cursor-pointer dark:bg-neutral-600 dark:after:bg-white dark:checked:bg-primary dark:checked:after:bg-primary disabled:cursor-default disabled:opacity-25 !focus:shadow-none",
`testid:${props.testClassId}`
].join(' ')}
checked={!!props.checked} checked={!!props.checked}
disabled={props.disabled} disabled={props.disabled}
data-checkbox-id={props.testClassId}
/>) />)
} }
@@ -17,6 +17,7 @@ interface InputProps
inputClassName?: string; inputClassName?: string;
className?: string; className?: string;
inputRef?: React.Ref<HTMLInputElement | HTMLTextAreaElement>; inputRef?: React.Ref<HTMLInputElement | HTMLTextAreaElement>;
testClassId?: string;
} }
export type ThemeName = 'plain' | 'outline' | 'blue' | 'rose'; export type ThemeName = 'plain' | 'outline' | 'blue' | 'rose';
@@ -66,7 +67,8 @@ export const Input = (props: InputProps) => {
<textarea <textarea
ref={props.inputRef as React.Ref<HTMLTextAreaElement>} ref={props.inputRef as React.Ref<HTMLTextAreaElement>}
className={inputClassName + ' ' + props.inputClassName + ' ' + props.className} className={inputClassName + ' ' + props.inputClassName + ' ' + props.className}
{..._.omit(props as any, 'label', 'inputClassName', 'inputRef', 'className', 'value', 'size')} {..._.omit(props as any, 'label', 'inputClassName', 'inputRef', 'className', 'value', 'size', 'testClassId')}
data-input-id={props.testClassId}
> >
{props.value} {props.value}
</textarea> </textarea>
@@ -74,8 +76,8 @@ export const Input = (props: InputProps) => {
<input <input
ref={props.inputRef as React.Ref<HTMLInputElement>} ref={props.inputRef as React.Ref<HTMLInputElement>}
type="text" type="text"
className={inputClassName + ' ' + props.inputClassName + ' ' + props.className} className={`${inputClassName} ${props.inputClassName} ${props.className} testid:${props.testClassId}`}
{..._.omit(props, 'label', 'inputClassName', 'inputRef', 'className', 'size')} {..._.omit(props, 'label', 'inputClassName', 'inputRef', 'className', 'size', 'testClassId')}
/> />
))} ))}
</> </>
+3 -2
View File
@@ -8,6 +8,7 @@ export default function A(
href?: string; href?: string;
children: React.ReactNode; children: React.ReactNode;
noColor?: boolean; noColor?: boolean;
testClassId?: string;
}, },
) { ) {
const colors = props.noColor ? '' : 'hover:text-blue-700 active:text-blue-800 text-blue-500'; const colors = props.noColor ? '' : 'hover:text-blue-700 active:text-blue-800 text-blue-500';
@@ -27,8 +28,8 @@ export default function A(
return ( return (
<a <a
href={(props.href || '#').replace(/^javascript:/, '')} href={(props.href || '#').replace(/^javascript:/, '')}
className={colors + ' ' + (props.className || '')} className={colors + ' ' + (props.className || '') + ' ' + `testid:${props.testClassId}`}
{..._.omit(props, 'children', 'className', 'noColor')} {..._.omit(props, 'children', 'className', 'noColor', 'testClassId')}
> >
{props.children} {props.children}
</a> </a>
@@ -42,13 +42,15 @@ export const ConfirmModal = (props: ConfirmModalProps) => {
className="ml-2" className="ml-2"
theme={props.buttonOkTheme || "danger"} theme={props.buttonOkTheme || "danger"}
onClick={dialogCloseHandler(true)} onClick={dialogCloseHandler(true)}
> testClassId="confirm-modal-button-confirm"
>
{Languages.t(props.buttonOkLabel)} {Languages.t(props.buttonOkLabel)}
</Button> </Button>
<Button <Button
theme='default' theme='default'
onClick={dialogCloseHandler(false)} onClick={dialogCloseHandler(false)}
> testClassId="confirm-modal-button-cancel"
>
{Languages.t(props.buttonCancelLabel || "general.cancel")} {Languages.t(props.buttonCancelLabel || "general.cancel")}
</Button> </Button>
</> </>
@@ -62,6 +62,7 @@ export default class ButtonWithTimeout extends React.Component {
(this.props.className ? this.props.className : '') (this.props.className ? this.props.className : '')
} }
onClick={this.props.onClick} onClick={this.props.onClick}
testClassId={this.props.testClassId}
> >
{this.props.value} {this.props.value}
</Button> </Button>
@@ -27,7 +27,7 @@ export default class Button extends React.Component {
<button <button
ref={this.props.refButton} ref={this.props.refButton}
{...this.props} {...this.props}
className={'button no-tw ' + className} className={'button no-tw ' + className + ` testid:${this.props.testClassId}`}
onClick={evt => { onClick={evt => {
evt.target.blur(); evt.target.blur();
this.props.onClick && this.props.onClick(evt); this.props.onClick && this.props.onClick(evt);
@@ -76,7 +76,7 @@ export default class Input extends Component {
} }
this.onKeyDown(evt); this.onKeyDown(evt);
}} }}
className={'input ' + (className || '')} className={'input ' + (className || '') + ` testid:${this.props.testClassId}`}
onBlur={this.props.onBlur} onBlur={this.props.onBlur}
onChange={this.props.onChange} onChange={this.props.onChange}
/> />
@@ -57,7 +57,8 @@ export default class MenuComponent extends React.Component {
<div <div
ref={node => (this.original_menu = node)} ref={node => (this.original_menu = node)}
className={ className={
'menu-list ' + (this.props.withFrame ? 'as_frame text-black bg-white dark:bg-zinc-900 dark:text-white rounded-lg ' : '') + this.props.animationClass 'menu-list ' + (this.props.withFrame ? 'as_frame text-black bg-white dark:bg-zinc-900 dark:text-white rounded-lg ' : '') + this.props.animationClass + ' ' +
`testid:${this.props.testClassId}`
} }
> >
{(this.props.menu || []) {(this.props.menu || [])
@@ -63,6 +63,8 @@ export default class Menu extends React.Component {
this.props.menu, this.props.menu,
elementRect, elementRect,
this.props.position, this.props.position,
{},
this.props.testClassId
); );
this.setState({ isMenuOpen: true }, () => this.open = true); this.setState({ isMenuOpen: true }, () => this.open = true);
this.open = true; this.open = true;
@@ -210,6 +210,7 @@ export default class MenusBodyLayer extends React.Component {
: 'skew_in_right_nobounce' : 'skew_in_right_nobounce'
: 'fade_in' : 'fade_in'
} }
testClassId={item.dataMenuId}
/> />
</div> </div>
</OutsideClickHandler> </OutsideClickHandler>
@@ -57,7 +57,7 @@ class MenusManager extends Observable {
this.notify(); this.notify();
} }
async openMenu(menu, domRect, positionType, options) { async openMenu(menu, domRect, positionType, options, dataMenuId) {
this.isOpen = 1; this.isOpen = 1;
if(typeof menu === 'function') { if(typeof menu === 'function') {
menu = await menu(); menu = await menu();
@@ -85,6 +85,7 @@ class MenusManager extends Observable {
level: 0, level: 0,
id: Number.unid(), id: Number.unid(),
allowClickOut: options.allowClickOut !== undefined ? options.allowClickOut : true, allowClickOut: options.allowClickOut !== undefined ? options.allowClickOut : true,
dataMenuId,
}); });
this.last_opened_id = Number.unid(); this.last_opened_id = Number.unid();
this.notify(); this.notify();
@@ -191,7 +191,7 @@ export default class UploadZone extends React.Component<PropsType, StateType> {
<div <div
ref={node => node && (this.node = node)} ref={node => node && (this.node = node)}
style={this.props.style} style={this.props.style}
className={classNames('upload_drop_zone', this.props.className)} className={classNames('upload_drop_zone', this.props.className, `testid:${this.props.testClassId}`)}
onClick={() => { onClick={() => {
if (!this.props.disableClick) { if (!this.props.disableClick) {
this.open(); this.open();
@@ -232,10 +232,10 @@ export default memo(
inPublicSharing, inPublicSharing,
}; };
return isMobile ? ( return isMobile ? (
<DocumentRow {...commonProps} /> <DocumentRow {...commonProps} testClassId="browser-document-row" />
) : ( ) : (
<Draggable id={index} key={index}> <Draggable id={index} key={index}>
<DocumentRow {...commonProps} /> <DocumentRow {...commonProps} testClassId="browser-document-row" />
</Draggable> </Draggable>
); );
} }
@@ -339,6 +339,7 @@ export default memo(
onDragOver={handleDragOver} onDragOver={handleDragOver}
onDrop={handleDrop} onDrop={handleDrop}
disabled={inTrash || access === 'read'} disabled={inTrash || access === 'read'}
testClassId="browser-upload-zone"
> >
{role == 'admin' && <UsersModal />} {role == 'admin' && <UsersModal />}
<VersionsModal /> <VersionsModal />
@@ -374,8 +375,11 @@ export default memo(
buildFileTypeContextMenu(), buildFileTypeContextMenu(),
{ x: evt.clientX, y: evt.clientY }, { x: evt.clientX, y: evt.clientY },
'center', 'center',
{},
"browser-share-with-me-menu-file-type"
); );
}} }}
testClassId="browser-share-with-me-button-file-type"
> >
<span> <span>
{filter.mimeType.key && filter.mimeType.key != 'All' {filter.mimeType.key && filter.mimeType.key != 'All'
@@ -394,8 +398,11 @@ export default memo(
buildPeopleContextMen(), buildPeopleContextMen(),
{ x: evt.clientX, y: evt.clientY }, { x: evt.clientX, y: evt.clientY },
'center', 'center',
{},
"browser-share-with-me-menu-people"
); );
}} }}
testClassId="browser-share-with-me-button-people"
> >
<span>{Languages.t('scenes.app.shared_with_me.people')}</span> <span>{Languages.t('scenes.app.shared_with_me.people')}</span>
<ChevronDownIcon className="h-4 w-4 ml-2 -mr-1" /> <ChevronDownIcon className="h-4 w-4 ml-2 -mr-1" />
@@ -411,8 +418,11 @@ export default memo(
buildDateContextMenu(), buildDateContextMenu(),
{ x: evt.clientX, y: evt.clientY }, { x: evt.clientX, y: evt.clientY },
'center', 'center',
{},
"browser-share-with-me-menu-last-modified"
); );
}} }}
testClassId="browser-share-with-me-button-last-modified"
> >
<span> <span>
{filter.date.key && filter.date.key != 'All' {filter.date.key && filter.date.key != 'All'
@@ -440,9 +450,9 @@ export default memo(
</BaseSmall> </BaseSmall>
)} )}
<Menu menu={() => onBuildSortContextMenu()} sortData={sortLabel}> <Menu menu={() => onBuildSortContextMenu()} sortData={sortLabel} testClassId="browser-menu-sorting">
{' '} {' '}
<Button theme="outline" className="ml-4 flex flex-row items-center"> <Button theme="outline" className="ml-4 flex flex-row items-center" testClassId="browser-button-sorting">
<SortIcon <SortIcon
className={`h-4 w-4 mr-2 -ml-1 ${ className={`h-4 w-4 mr-2 -ml-1 ${
sortLabel.order === 'asc' ? 'transform rotate-180' : '' sortLabel.order === 'asc' ? 'transform rotate-180' : ''
@@ -455,9 +465,9 @@ export default memo(
</Button> </Button>
</Menu> </Menu>
{viewId !== 'shared_with_me' && ( {viewId !== 'shared_with_me' && (
<Menu menu={() => onBuildContextMenu(details)}> <Menu menu={() => onBuildContextMenu(details)} testClassId="browser-menu-context">
{' '} {' '}
<Button theme="secondary" className="ml-4 flex flex-row items-center"> <Button theme="secondary" className="ml-4 flex flex-row items-center" testClassId="browser-button-context">
<span> <span>
{selectedCount > 1 {selectedCount > 1
? `${selectedCount} items` ? `${selectedCount} items`
@@ -485,6 +495,7 @@ export default memo(
onClick={() => uploadItemModal()} onClick={() => uploadItemModal()}
theme="primary" theme="primary"
className="mt-4" className="mt-4"
testClassId="browser-button-add-doc"
> >
{Languages.t('scenes.app.drive.add_doc')} {Languages.t('scenes.app.drive.add_doc')}
</Button> </Button>
@@ -514,6 +525,7 @@ export default memo(
setChecked(_.pickBy({ ...checked, [child.id]: v }, _.identity)) setChecked(_.pickBy({ ...checked, [child.id]: v }, _.identity))
} }
onBuildContextMenu={() => onBuildContextMenu(details, child)} onBuildContextMenu={() => onBuildContextMenu(details, child)}
testClassId="browser-folder-row"
/> />
</Droppable> </Droppable>
) : ( ) : (
@@ -26,6 +26,7 @@ export const AccessLevelDropdown = ({
className, className,
size, size,
noRedWhenLevelNone, noRedWhenLevelNone,
testClassId,
}: { }: {
disabled?: boolean; disabled?: boolean;
level: DriveFileAccessLevel | null; level: DriveFileAccessLevel | null;
@@ -35,6 +36,7 @@ export const AccessLevelDropdown = ({
hiddenLevels?: DriveFileAccessLevelOrRemove[] | string[]; hiddenLevels?: DriveFileAccessLevelOrRemove[] | string[];
size?: SelectSize, size?: SelectSize,
noRedWhenLevelNone?: boolean, noRedWhenLevelNone?: boolean,
testClassId?: string,
}) => { }) => {
const createOption = (level: DriveFileAccessLevelOrRemove) => const createOption = (level: DriveFileAccessLevelOrRemove) =>
!hiddenLevels?.includes(level) && <option value={level}>{(labelOverrides || {})[level] || translateAccessLevel(level)}</option>; !hiddenLevels?.includes(level) && <option value={level}>{(labelOverrides || {})[level] || translateAccessLevel(level)}</option>;
@@ -42,7 +44,7 @@ export const AccessLevelDropdown = ({
<Select <Select
disabled={disabled} disabled={disabled}
size={size} size={size}
className={className + ' w-auto'} className={className + ' w-auto' + ` testid:${testClassId}`}
theme={(!noRedWhenLevelNone && level === 'none') ? 'rose' : 'outline'} theme={(!noRedWhenLevelNone && level === 'none') ? 'rose' : 'outline'}
value={level || 'none'} value={level || 'none'}
onChange={e => onChange(e.target.value as DriveFileAccessLevel & 'remove')} onChange={e => onChange(e.target.value as DriveFileAccessLevel & 'remove')}
@@ -9,6 +9,7 @@ export type DriveItemProps = {
checked: boolean; checked: boolean;
onClick?: () => void; onClick?: () => void;
onBuildContextMenu: () => Promise<any[]>; onBuildContextMenu: () => Promise<any[]>;
testClassId?: string;
}; };
export type DriveItemOverlayProps = { export type DriveItemOverlayProps = {
@@ -1,6 +1,5 @@
import { import {
DotsHorizontalIcon, DotsHorizontalIcon,
ShieldCheckIcon,
ShieldExclamationIcon, ShieldExclamationIcon,
BanIcon, BanIcon,
} from '@heroicons/react/outline'; } from '@heroicons/react/outline';
@@ -32,6 +31,7 @@ export const DocumentRow = ({
checked, checked,
onClick, onClick,
onBuildContextMenu, onBuildContextMenu,
testClassId,
}: DriveItemProps) => { }: DriveItemProps) => {
const history = useHistory(); const history = useHistory();
const [hover, setHover] = useState(false); const [hover, setHover] = useState(false);
@@ -52,7 +52,8 @@ export const DocumentRow = ({
(checked (checked
? (notSafe ? 'bg-rose-500' : 'bg-blue-500') + ' bg-opacity-10 hover:bg-opacity-25' ? (notSafe ? 'bg-rose-500' : 'bg-blue-500') + ' bg-opacity-10 hover:bg-opacity-25'
: 'hover:bg-zinc-500 hover:bg-opacity-10 ') + : 'hover:bg-zinc-500 hover:bg-opacity-10 ') +
(className || '') (className || '') +
` testid:${testClassId}`
} }
id={`DR-${item.id}`} id={`DR-${item.id}`}
onMouseEnter={() => setHover(true)} onMouseEnter={() => setHover(true)}
@@ -102,12 +103,13 @@ export const DocumentRow = ({
</div> </div>
)} )}
<div className="shrink-0 ml-auto md:ml-4"> <div className="shrink-0 ml-auto md:ml-4">
<Menu menu={onBuildContextMenu}> <Menu menu={onBuildContextMenu} testClassId="document-row-menu">
<Button <Button
theme={'secondary'} theme={'secondary'}
size="sm" size="sm"
className={'!rounded-full '} className={'!rounded-full '}
icon={DotsHorizontalIcon} icon={DotsHorizontalIcon}
testClassId="document-row-button-open-menu"
/> />
</Menu> </Menu>
</div> </div>
@@ -17,6 +17,7 @@ export const FolderRow = ({
checked, checked,
onClick, onClick,
onBuildContextMenu, onBuildContextMenu,
testClassId,
}: DriveItemProps) => { }: DriveItemProps) => {
const [hover, setHover] = useState(false); const [hover, setHover] = useState(false);
@@ -28,7 +29,8 @@ export const FolderRow = ({
(checked (checked
? 'bg-blue-500 bg-opacity-10 hover:bg-opacity-25 ' ? 'bg-blue-500 bg-opacity-10 hover:bg-opacity-25 '
: 'hover:bg-zinc-500 hover:bg-opacity-10 ') + : 'hover:bg-zinc-500 hover:bg-opacity-10 ') +
(className || '') (className || '') +
` testid:${testClassId}`
} }
onMouseEnter={() => setHover(true)} onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)} onMouseLeave={() => setHover(false)}
@@ -58,12 +60,13 @@ export const FolderRow = ({
<BaseSmall>{formatBytes(item.size)}</BaseSmall> <BaseSmall>{formatBytes(item.size)}</BaseSmall>
</div> </div>
<div className="shrink-0 ml-4"> <div className="shrink-0 ml-4">
<Menu menu={onBuildContextMenu}> <Menu menu={onBuildContextMenu} testClassId="folder-row-menu">
<Button <Button
theme={'secondary'} theme={'secondary'}
size="sm" size="sm"
className={'!rounded-full '} className={'!rounded-full '}
icon={DotsHorizontalIcon} icon={DotsHorizontalIcon}
testClassId="folder-row-button-open-menu"
/> />
</Menu> </Menu>
</div> </div>
@@ -74,7 +74,7 @@ export const PathRender = ({
const pathLength = (pathToRender || []).reduce((acc, curr) => acc + curr.name.length, 0); const pathLength = (pathToRender || []).reduce((acc, curr) => acc + curr.name.length, 0);
return ( return (
<nav className="overflow-hidden whitespace-nowrap mr-2 pl-px inline-flex md:max-w-[50%] sm:max-w-[20%]"> <nav className="overflow-hidden whitespace-nowrap mr-2 pl-px inline-flex md:max-w-[50%] sm:max-w-[20%] testid:header-path">
{pathLength < 70 ? ( {pathLength < 70 ? (
(pathToRender || [])?.map((a, i) => ( (pathToRender || [])?.map((a, i) => (
<PathItem <PathItem
@@ -136,7 +136,7 @@ const PathItem = ({
<div className={`flex items-center ${!first ? 'overflow-hidden' : ''}`}> <div className={`flex items-center ${!first ? 'overflow-hidden' : ''}`}>
<a <a
href="#" href="#"
className={`text-sm font-medium text-gray-700 hover:text-blue-600 dark:text-gray-400 dark:hover:text-white ${!first ? 'overflow-hidden' : ''}`} className={`text-sm font-medium text-gray-700 hover:text-blue-600 dark:text-gray-400 dark:hover:text-white ${!first ? 'overflow-hidden' : ''} testid:header-path-item`}
onClick={evt => { onClick={evt => {
evt.preventDefault(); evt.preventDefault();
@@ -71,6 +71,7 @@ const ConfirmDeleteModalContent = ({ items }: { items: DriveItem[] }) => {
setSelected({}); setSelected({});
setState({ ...state, open: false }); setState({ ...state, open: false });
}} }}
testClassId="confirm-delete-modal-button-delete"
> >
Delete Delete
</Button> </Button>
@@ -52,6 +52,7 @@ const ConfirmModalContent = () => {
theme="primary" theme="primary"
className="float-right" className="float-right"
onClick={handleClose} onClick={handleClose}
testClassId="confirm-modal-button-move"
> >
<>{Languages.t('components.SelectorModalContent_move_to')} '{selected[0]?.name}'</> <>{Languages.t('components.SelectorModalContent_move_to')} '{selected[0]?.name}'</>
</Button> </Button>
@@ -74,6 +74,7 @@ const ConfirmTrashModalContent = ({ items }: { items: DriveItem[] }) => {
await refresh("trash"); await refresh("trash");
setState({ ...state, open: false }); setState({ ...state, open: false });
}} }}
testClassId="cofirm-trash-modal-button-remove"
> >
{Languages.t('components.ConfirmTrashModalContent_move_to_trash')} {Languages.t('components.ConfirmTrashModalContent_move_to_trash')}
</Button> </Button>
@@ -43,6 +43,7 @@ export const CreateFolder = () => {
} }
}} }}
onChange={(e: any) => setName(e.target.value)} onChange={(e: any) => setName(e.target.value)}
testClassId="create-folder-input"
/> />
</div> </div>
<Button <Button
@@ -50,6 +51,7 @@ export const CreateFolder = () => {
loading={loading} loading={loading}
className="mt-4 float-right" className="mt-4 float-right"
onClick={createFolderHandler} onClick={createFolderHandler}
testClassId="create-folder-button"
> >
Create Create
</Button> </Button>
@@ -53,6 +53,7 @@ export const CreateLink = () => {
placeholder={ Languages.t('components.create_link_modal.hint')} placeholder={ Languages.t('components.create_link_modal.hint')}
className="w-full mt-4" className="w-full mt-4"
onChange={e => setName(e.target.value)} onChange={e => setName(e.target.value)}
testClassId="create-link-name-input"
/> />
<Input <Input
@@ -60,6 +61,7 @@ export const CreateLink = () => {
placeholder="https://example.com" placeholder="https://example.com"
className="w-full mt-4" className="w-full mt-4"
onChange={e => setLink(e.target.value)} onChange={e => setLink(e.target.value)}
testClassId="create-link-input"
/> />
<Button <Button
@@ -70,6 +72,7 @@ export const CreateLink = () => {
await createLink(); await createLink();
setState({ ...state, open: false }); setState({ ...state, open: false });
}} }}
testClassId="create-link-button"
> >
{ Languages.t('components.create_link_modal.button')} { Languages.t('components.create_link_modal.button')}
</Button> </Button>
@@ -82,11 +82,13 @@ export const CreateModal = ({
icon={<FolderAddIcon className="w-5 h-5" />} icon={<FolderAddIcon className="w-5 h-5" />}
text={Languages.t('components.create_modal.create_folder')} text={Languages.t('components.create_modal.create_folder')}
onClick={() => setState({ ...state, type: 'folder' })} onClick={() => setState({ ...state, type: 'folder' })}
testClassId="create-folder-option"
/> />
<CreateModalOption <CreateModalOption
icon={<LinkIcon className="w-5 h-5" />} icon={<LinkIcon className="w-5 h-5" />}
text={Languages.t('components.create_modal.create_link')} text={Languages.t('components.create_modal.create_link')}
onClick={() => setState({ ...state, type: 'link' })} onClick={() => setState({ ...state, type: 'link' })}
testClassId="create-link-option"
/> />
{(applications || []) {(applications || [])
@@ -132,6 +134,7 @@ export const CreateModal = ({
onClick={() => onClick={() =>
addFromUrl(app.emptyFile.url, app.emptyFile.filename || app.emptyFile.name) addFromUrl(app.emptyFile.url, app.emptyFile.filename || app.emptyFile.name)
} }
testClassId={app.emptyFile.name}
/> />
); );
})} })}
@@ -167,11 +170,11 @@ export const CreateModal = ({
); );
}; };
const CreateModalOption = (props: { icon: ReactNode; text: string; onClick: () => void }) => { const CreateModalOption = (props: { testClassId?: string; icon: ReactNode; text: string; onClick: () => void }) => {
return ( return (
<div <div
onClick={props.onClick} onClick={props.onClick}
className="flex flex-row p-4 dark:bg-zinc-900 dark:text-white bg-zinc-100 hover:bg-opacity-75 cursor-pointer rounded-md m-2" className={`flex flex-row p-4 dark:bg-zinc-900 dark:text-white bg-zinc-100 hover:bg-opacity-75 cursor-pointer rounded-md m-2 testid:${props.testClassId}`}
> >
<div className="flex items-center justify-center">{props.icon}</div> <div className="flex items-center justify-center">{props.icon}</div>
<div className="grow flex items-center ml-2"> <div className="grow flex items-center ml-2">
@@ -105,6 +105,7 @@ const PropertiesModalContent = ({ id, onClose, inPublicSharing }: { id: string;
} }
}} }}
placeholder={Languages.t('components.PropertiesModalContent_place_holder')} placeholder={Languages.t('components.PropertiesModalContent_place_holder')}
testClassId="properties-modal-input-update-name"
/> />
} }
/> />
@@ -115,6 +116,7 @@ const PropertiesModalContent = ({ id, onClose, inPublicSharing }: { id: string;
theme="primary" theme="primary"
loading={loading} loading={loading}
onClick={doSave} onClick={doSave}
testClassId="properties-modal-button-update-name"
> >
{Languages.t('components.PropertiesModalContent_update_button')} {Languages.t('components.PropertiesModalContent_update_button')}
</Button> </Button>
@@ -26,7 +26,8 @@ export const CopyLinkButton = (props: {
disabled={!haveTextToCopy} disabled={!haveTextToCopy}
theme={didJustCompleteACopy ? "green" : "primary"} theme={didJustCompleteACopy ? "green" : "primary"}
className="justify-center w-64" className="justify-center w-64"
> testClassId="copy-link-button"
>
{ didJustCompleteACopy { didJustCompleteACopy
? <CheckCircleIcon className="w-5 mr-2" /> ? <CheckCircleIcon className="w-5 mr-2" />
: <LinkIcon className="w-5 mr-2" /> : <LinkIcon className="w-5 mr-2" />
@@ -130,6 +130,7 @@ export const ExpiryEditorRow = (props: {
else if (e.key == 'Enter') else if (e.key == 'Enter')
confirmSaveExpiry(currentEditedValue); confirmSaveExpiry(currentEditedValue);
}} }}
testClassId="expiry-editor-row-expired-date"
/> />
<Button <Button
disabled={disabled} disabled={disabled}
@@ -137,7 +138,8 @@ export const ExpiryEditorRow = (props: {
size="sm" size="sm"
className="max-w-xs mr-2 mt-1" className="max-w-xs mr-2 mt-1"
onClick={() => confirmSaveExpiry(currentEditedValue)} onClick={() => confirmSaveExpiry(currentEditedValue)}
> testClassId="expiry-editor-row-button-confirm"
>
{Languages.t('components.public-link-security_field_confirm_edit')} {Languages.t('components.public-link-security_field_confirm_edit')}
</Button> </Button>
</> </>
@@ -153,7 +155,8 @@ export const ExpiryEditorRow = (props: {
} else } else
confirmSaveExpiry(0); confirmSaveExpiry(0);
}} }}
/> testClassId="expiry-editor-row-checkbox"
/>
} }
/> />
<ConfirmModal <ConfirmModal
@@ -78,7 +78,8 @@ const ChangePublicLinkAccessLevelRow = (props: {
level={props.level} level={props.level}
hiddenLevels={['remove']} hiddenLevels={['remove']}
onChange={props.onChange} onChange={props.onChange}
/> testClassId="public-link-access-level-dropdown"
/>
} }
/> />
); );
@@ -101,7 +102,8 @@ const SwitchToAdvancedSettingsRow = (props: {
if (!props.disabled) if (!props.disabled)
props.onShowAdvancedScreen(true); props.onShowAdvancedScreen(true);
}} }}
> testClassId="public-link-access-advance-switcher"
>
{Languages.t("components.public-link-security-change")} {Languages.t("components.public-link-security-change")}
</A> </A>
} }
@@ -126,58 +128,58 @@ const PublicLinkModalContent = (props: {
return ( return (
<ModalContent <ModalContent
title={ title={
<> <>
{Languages.t('components.public-link-security-title') + ' '} {Languages.t('components.public-link-security-title') + ' '}
<strong>{item?.name}</strong> <strong>{item?.name}</strong>
</> </>
} }
> >
<div className="rounded-md border dark:border-zinc-700 my-5 mb-8"> <div className="rounded-md border dark:border-zinc-700 my-5 mb-8">
<ChangePublicLinkAccessLevelRow <ChangePublicLinkAccessLevelRow
disabled={loading} disabled={loading}
level={item?.access_info?.public?.level || 'none'} level={item?.access_info?.public?.level || 'none'}
onChange={level => { onChange={level => {
item && update(changePublicLink(item, { level })); item && update(changePublicLink(item, { level }));
}} }}
/>
<SwitchToAdvancedSettingsRow
disabled={!havePublicLink}
onShowAdvancedScreen={props.onShowAdvancedScreen}
/> />
</div> <SwitchToAdvancedSettingsRow
disabled={!havePublicLink}
onShowAdvancedScreen={props.onShowAdvancedScreen}
/>
</div>
<div className="flex flex-row place-content-end my-4"> <div className="flex flex-row place-content-end my-4">
<CopyLinkButton textToCopy={havePublicLink && publicLink} /> <CopyLinkButton textToCopy={havePublicLink && publicLink} />
</div> </div>
<Modal <Modal
open={props.isOnAdvancedScreen} open={props.isOnAdvancedScreen}
onClose={() => { props.onShowAdvancedScreen(false); }} onClose={() => { props.onShowAdvancedScreen(false); }}
> >
<ModalContent <ModalContent
title={ title={
<> <>
{Languages.t('components.public-link-security-title') + ' '} {Languages.t('components.public-link-security-title') + ' '}
<strong>{item?.name}</strong> <strong>{item?.name}</strong>
</> </>
} }
> >
<div className='my-4'><Subtitle>{Languages.t('components.public-link-security')}</Subtitle></div> <div className='my-4'><Subtitle>{Languages.t('components.public-link-security')}</Subtitle></div>
<div className={Styles.RoundedBorderSection}> <div className={Styles.RoundedBorderSection}>
<PublicLinkAccessOptions <PublicLinkAccessOptions
disabled={loading || access !== 'manage'} disabled={loading || access !== 'manage'}
password={item?.access_info?.public?.password} password={item?.access_info?.public?.password}
expiration={item?.access_info?.public?.expiration} expiration={item?.access_info?.public?.expiration}
onChangePassword={async (password: string) => { onChangePassword={async (password: string) => {
item && await update(changePublicLink(item, { password: password || '' })); item && await update(changePublicLink(item, { password: password || '' }));
}} }}
onChangeExpiration={async (expiration: number) => { onChangeExpiration={async (expiration: number) => {
item && await update(changePublicLink(item, { expiration })); item && await update(changePublicLink(item, { expiration }));
}} }}
/> />
</div> </div>
</ModalContent> </ModalContent>
</Modal> </Modal>
</ModalContent> </ModalContent>
); );
} }
@@ -112,6 +112,7 @@ return <>
else if (e.key == 'Enter') else if (e.key == 'Enter')
confirmSavePassword(currentEditedPassword); confirmSavePassword(currentEditedPassword);
}} }}
testClassId="pasword-editor-row-editting-password"
/> />
<Button <Button
disabled={disabled} disabled={disabled}
@@ -119,7 +120,8 @@ return <>
size="sm" size="sm"
className="max-w-xs mr-2 mt-1" className="max-w-xs mr-2 mt-1"
onClick={() => confirmSavePassword(currentEditedPassword)} onClick={() => confirmSavePassword(currentEditedPassword)}
> testClassId="password-editor-row-button-confirm"
>
{Languages.t('components.public-link-security_field_confirm_edit')} {Languages.t('components.public-link-security_field_confirm_edit')}
</Button> </Button>
</> </>
@@ -135,7 +137,8 @@ return <>
} else } else
confirmSavePassword(""); confirmSavePassword("");
}} }}
/> testClassId="password-editor-row-checkbox"
/>
} }
/> />
@@ -145,9 +148,8 @@ return <>
text={Languages.t("components.public-link-security_password_removal_body")} text={Languages.t("components.public-link-security_password_removal_body")}
buttonOkTheme='primary' buttonOkTheme='primary'
buttonOkLabel='components.public-link-security_password_removal_confirm' buttonOkLabel='components.public-link-security_password_removal_confirm'
onClose={() => setIsConfirmingPasswordRemoval(false)} onClose={() => setIsConfirmingPasswordRemoval(false)}
onOk={() => savePassword("")} onOk={() => savePassword("")}
/> />
</>; </>;
} }
@@ -14,13 +14,13 @@ export const PublicLinkAccessOptions = (props: {
password={props.password} password={props.password}
onChangePassword={props.onChangePassword} onChangePassword={props.onChangePassword}
isLinkExpired={!!props.expiration && props.expiration < Date.now()} isLinkExpired={!!props.expiration && props.expiration < Date.now()}
/> />
<ExpiryEditorRow <ExpiryEditorRow
disabled={props.disabled} disabled={props.disabled}
value={props.expiration ?? 0} value={props.expiration ?? 0}
onChange={props.onChangeExpiration} onChange={props.onChangeExpiration}
isLinkPasswordProtected={!!props.password?.length} isLinkPasswordProtected={!!props.password?.length}
/> />
</> </>
); );
@@ -138,6 +138,7 @@ const SelectorModalContent = (key: any) => {
setState({ ...state, open: false }); setState({ ...state, open: false });
setLoading(false); setLoading(false);
}} }}
testClassId="selector-modal-button"
> >
{selected.length === 0 ? ( {selected.length === 0 ? (
<>{Languages.t('components.SelectorModalContent_no_items')}</> <>{Languages.t('components.SelectorModalContent_no_items')}</>
@@ -113,6 +113,7 @@ export const InternalUsersAccessManager = ({
}} }}
value={searchString} value={searchString}
inputRef={inputElement} inputRef={inputElement}
testClassId="access-management-search-users"
/> />
)} )}
/> />
@@ -125,6 +126,7 @@ export const InternalUsersAccessManager = ({
hiddenLevels={['remove']} hiddenLevels={['remove']}
level={level} level={level}
onChange={level => setLevel(level)} onChange={level => setLevel(level)}
testClassId="access-management-dropdown"
/> />
</div> </div>
</div> </div>
@@ -179,7 +181,8 @@ export const InternalUsersAccessManager = ({
size="sm" size="sm"
className='text-center' className='text-center'
onClick={onCloseModal} onClick={onCloseModal}
> testClassId="access-management-public-link-security-field-confirm-edit"
>
{Languages.t('components.public-link-security_field_confirm_edit')} {Languages.t('components.public-link-security_field_confirm_edit')}
</Button> </Button>
</div> </div>
@@ -209,7 +212,8 @@ const UserAccessLevel = (props: {
? <Button ? <Button
disabled={loading || props.disabled || user?.id === currentUser?.id} disabled={loading || props.disabled || user?.id === currentUser?.id}
size="sm" size="sm"
> testClassId={`user-access-button-${props.isSearchResultAdd}`}
>
{Languages.t('components.user_picker.modal.result_add.' + props.isSearchResultAdd)} {Languages.t('components.user_picker.modal.result_add.' + props.isSearchResultAdd)}
</Button> </Button>
@@ -218,7 +222,8 @@ const UserAccessLevel = (props: {
noRedWhenLevelNone={true} noRedWhenLevelNone={true}
level={(item && getUserAccessLevel(item, props.userId)) || "none"} level={(item && getUserAccessLevel(item, props.userId)) || "none"}
onChange={level => item && update(changeUserAccess(item, props.userId, level === 'remove' ? false : level))} onChange={level => item && update(changeUserAccess(item, props.userId, level === 'remove' ? false : level))}
/> testClassId="user-access-dropdown"
/>
} }
/> />
); );
@@ -74,11 +74,13 @@ export const UploadModal = ({
icon={<DocumentDownloadIcon className="w-5 h-5" />} icon={<DocumentDownloadIcon className="w-5 h-5" />}
text={Languages.t('components.create_modal.upload_files')} text={Languages.t('components.create_modal.upload_files')}
onClick={() => selectFromDevice()} onClick={() => selectFromDevice()}
testClassId="upload-file-from-device"
/> />
<CreateModalOption <CreateModalOption
icon={<FolderDownloadIcon className="w-5 h-5" />} icon={<FolderDownloadIcon className="w-5 h-5" />}
text={Languages.t('components.create_modal.upload_folders')} text={Languages.t('components.create_modal.upload_folders')}
onClick={() => selectFolderFromDevice()} onClick={() => selectFolderFromDevice()}
testClassId="upload-folder-from-device"
/> />
</div> </div>
</Transition> </Transition>
@@ -88,11 +90,11 @@ export const UploadModal = ({
); );
}; };
const CreateModalOption = (props: { icon: ReactNode; text: string; onClick: () => void }) => { const CreateModalOption = (props: { icon: ReactNode; text: string; onClick: () => void; testClassId?: string; }) => {
return ( return (
<div <div
onClick={props.onClick} onClick={props.onClick}
className="flex flex-row p-4 dark:bg-zinc-900 dark:text-white bg-zinc-100 hover:bg-opacity-75 cursor-pointer rounded-md m-2" className={`flex flex-row p-4 dark:bg-zinc-900 dark:text-white bg-zinc-100 hover:bg-opacity-75 cursor-pointer rounded-md m-2 testid:${props.testClassId}`}
> >
<div className="flex items-center justify-center">{props.icon}</div> <div className="flex items-center justify-center">{props.icon}</div>
<div className="grow flex items-center ml-2"> <div className="grow flex items-center ml-2">
@@ -64,6 +64,7 @@ const VersionModalContent = ({ id }: { id: string }) => {
await uploadVersion(file); await uploadVersion(file);
await refresh(id); await refresh(id);
}} }}
testClassId="version-modal-upload-zone"
> >
{access !== 'read' && ( {access !== 'read' && (
<div <div
@@ -80,6 +81,7 @@ const VersionModalContent = ({ id }: { id: string }) => {
theme="primary" theme="primary"
onClick={() => uploadZoneRef.current?.open()} onClick={() => uploadZoneRef.current?.open()}
loading={loading} loading={loading}
testClassId="button-create-version"
> >
{Languages.t('components.VersionModalContent_create')} {Languages.t('components.VersionModalContent_create')}
</Button> </Button>
@@ -113,6 +115,7 @@ const VersionModalContent = ({ id }: { id: string }) => {
<Button <Button
theme="outline" theme="outline"
onClick={() => download(id, item.av_status === 'malicious', version.id)} onClick={() => download(id, item.av_status === 'malicious', version.id)}
testClassId="button-download-version"
> >
{Languages.t('components.VersionModalContent_donwload')} {Languages.t('components.VersionModalContent_donwload')}
</Button> </Button>
@@ -44,6 +44,7 @@ export default (): JSX.Element => {
readOnly readOnly
placeholder={Languages.t('scenes.client.main_view.main_header.search_input')} placeholder={Languages.t('scenes.client.main_view.main_header.search_input')}
onClick={() => setOpen()} onClick={() => setOpen()}
testClassId="header-search-input"
/> />
)} )}
/> />
@@ -33,6 +33,7 @@ export const CreateModalWithUploadZones = ({ initialParentId }: { initialParentI
<UploadZone <UploadZone
overClassName={'!hidden'} overClassName={'!hidden'}
className="hidden" className="hidden"
testClassId="create-modal-upload-file-zone"
disableClick disableClick
parent={''} parent={''}
multiple={true} multiple={true}
@@ -51,6 +52,7 @@ export const CreateModalWithUploadZones = ({ initialParentId }: { initialParentI
<UploadZone <UploadZone
overClassName={'!hidden'} overClassName={'!hidden'}
className="hidden" className="hidden"
testClassId="create-modal-upload-folder-zone"
disableClick disableClick
parent={''} parent={''}
multiple={true} multiple={true}
@@ -135,6 +137,7 @@ export default () => {
theme="danger" theme="danger"
className="w-full mb-2 justify-center" className="w-full mb-2 justify-center"
disabled={!(trashChildren.length > 0)} disabled={!(trashChildren.length > 0)}
testClassId="create-modal-in-trash-button-empty-trash"
> >
<TruckIcon className="w-5 h-5 mr-2" /> { Languages.t('components.side_menu.buttons.empty_trash') } <TruckIcon className="w-5 h-5 mr-2" /> { Languages.t('components.side_menu.buttons.empty_trash') }
</Button> </Button>
@@ -158,6 +161,7 @@ export default () => {
parentId, parentId,
}); });
}} }}
testClassId="sidebar-action-upload-zone"
/> />
<Button <Button
@@ -166,6 +170,7 @@ export default () => {
theme="primary" theme="primary"
className="w-full mb-2 justify-center" className="w-full mb-2 justify-center"
style={{ boxShadow: '0 0 10px 0 rgba(0, 122, 255, 0.5)' }} style={{ boxShadow: '0 0 10px 0 rgba(0, 122, 255, 0.5)' }}
testClassId="sidebar-action-button-empty-trash"
> >
<UploadIcon className="w-5 h-5 mr-2" /> {Languages.t('components.side_menu.buttons.upload')} <UploadIcon className="w-5 h-5 mr-2" /> {Languages.t('components.side_menu.buttons.upload')}
</Button> </Button>
@@ -174,6 +179,7 @@ export default () => {
size="lg" size="lg"
theme="secondary" theme="secondary"
className="w-full mb-2 justify-center" className="w-full mb-2 justify-center"
testClassId="sidebar-action-button-open-modal"
> >
<PlusIcon className="w-5 h-5 mr-2" /> {Languages.t('components.side_menu.buttons.create')} <PlusIcon className="w-5 h-5 mr-2" /> {Languages.t('components.side_menu.buttons.create')}
</Button> </Button>
@@ -161,6 +161,7 @@ export const DrivePreview: React.FC<DrivePreviewProps> = ({ items }) => {
size="lg" size="lg"
icon={ArrowLeftIcon} icon={ArrowLeftIcon}
onClick={ handleSwitchLeft } onClick={ handleSwitchLeft }
testClassId="drive-preview-button-switch-left"
/> />
<Button <Button
iconSize="lg" iconSize="lg"
@@ -169,6 +170,7 @@ export const DrivePreview: React.FC<DrivePreviewProps> = ({ items }) => {
size="lg" size="lg"
icon={ArrowRightIcon} icon={ArrowRightIcon}
onClick={ handleSwitchRight } onClick={ handleSwitchRight }
testClassId="drive-preview-button-switch-right"
/> />
</> </>
} }
@@ -181,6 +183,7 @@ export const DrivePreview: React.FC<DrivePreviewProps> = ({ items }) => {
onClick= {() => { onClick= {() => {
download && (window.location.href = download); download && (window.location.href = download);
}} }}
testClassId="drive-preview-button-download"
/> />
</div> </div>
</div> </div>
@@ -12,6 +12,7 @@ export default () => {
size="lg" size="lg"
icon={ZoomOutIcon} icon={ZoomOutIcon}
onClick={() => getImageControls().zoomOut()} onClick={() => getImageControls().zoomOut()}
testClassId="image-control-button-zoom-out"
/> />
<Button <Button
iconSize="lg" iconSize="lg"
@@ -20,6 +21,7 @@ export default () => {
size="lg" size="lg"
icon={ZoomInIcon} icon={ZoomInIcon}
onClick={() => getImageControls().zoomIn()} onClick={() => getImageControls().zoomIn()}
testClassId="image-control-button-zoom-in"
/> />
<Button <Button
iconSize="lg" iconSize="lg"
@@ -28,6 +30,7 @@ export default () => {
size="lg" size="lg"
icon={RotateCwIcon} icon={RotateCwIcon}
onClick={() => getImageControls().rotateCw()} onClick={() => getImageControls().rotateCw()}
testClassId="image-control-button-rotate"
/> />
</> </>
); );
@@ -43,6 +43,7 @@ export default () => {
); );
} }
}} }}
testClassId="other-control-button-edit"
> >
{Languages.t('scenes.apps.drive.viewer.edit_with_button', [ {Languages.t('scenes.apps.drive.viewer.edit_with_button', [
candidates[0].app?.identity.name, candidates[0].app?.identity.name,
@@ -74,6 +75,7 @@ export default () => {
{ margin: 0 }, { margin: 0 },
); );
}} }}
testClassId="other-control-button-open"
> >
{Languages.t('scenes.apps.drive.viewer.open_with_button')} {Languages.t('scenes.apps.drive.viewer.open_with_button')}
</Button> </Button>
@@ -124,6 +124,7 @@ export default (): JSX.Element => {
loading={busy} loading={busy}
type="primary" type="primary"
onClick={onCreateCompanyBtnClick} onClick={onCreateCompanyBtnClick}
className="testid:button-create-company"
> >
{Languages.t('scenes.join.create_the_company_button')} {Languages.t('scenes.join.create_the_company_button')}
</Button> </Button>
@@ -163,6 +164,7 @@ export default (): JSX.Element => {
loading={busy} loading={busy}
type="primary" type="primary"
onClick={onJoinAccountBtnClick} onClick={onJoinAccountBtnClick}
className="testid:button-login-first"
> >
{Languages.t('scenes.join.login_first_button')} {Languages.t('scenes.join.login_first_button')}
</Button> </Button>
@@ -172,6 +174,7 @@ export default (): JSX.Element => {
loading={busy} loading={busy}
type="primary" type="primary"
onClick={onJoinAccountBtnClick} onClick={onJoinAccountBtnClick}
className="testid:button-join-team"
> >
{Languages.t('scenes.join.join_the_team_button')} {Languages.t('scenes.join.join_the_team_button')}
</Button> </Button>
@@ -80,6 +80,7 @@ export default class LoginView extends Component {
} }
}} }}
onChange={evt => this.setState({ form_login: evt.target.value })} onChange={evt => this.setState({ form_login: evt.target.value })}
testClassId="login-input-username"
/> />
<Input <Input
@@ -100,6 +101,7 @@ export default class LoginView extends Component {
} }
}} }}
onChange={evt => this.setState({ form_password: evt.target.value })} onChange={evt => this.setState({ form_password: evt.target.value })}
testClassId="login-input-password"
/> />
{this.state.login.login_error && ( {this.state.login.login_error && (
@@ -121,6 +123,7 @@ export default class LoginView extends Component {
remember_me: true, remember_me: true,
}) })
} }
testClassId="login-button-submit"
> >
{this.state.i18n.t('scenes.login.home.login_btn')} {this.state.i18n.t('scenes.login.home.login_btn')}
</Button> </Button>
@@ -63,12 +63,12 @@ export default class Signin extends Component {
</div> </div>
{this.state.login.error_subscribe_username && this.state.username && ( {this.state.login.error_subscribe_username && this.state.username && (
<div className={'error text bottom-margin'}> <div className={'error text bottom-margin testid:signin-username-exist-text'}>
{this.state.i18n.t('scenes.login.create_account.username_already_exist')} {this.state.i18n.t('scenes.login.create_account.username_already_exist')}
</div> </div>
)} )}
{this.state.username && this.state.errorUsername && ( {this.state.username && this.state.errorUsername && (
<div className={'text error bottom-margin'}> <div className={'text error bottom-margin testid:signin-fill-in-username'}>
{this.state.i18n.t('scenes.login.create_account.fill_in_username', [])} {this.state.i18n.t('scenes.login.create_account.fill_in_username', [])}
</div> </div>
)} )}
@@ -91,6 +91,7 @@ export default class Signin extends Component {
)} )}
value={this.state.firstName} value={this.state.firstName}
onChange={evt => this.setState({ firstName: evt.target.value })} onChange={evt => this.setState({ firstName: evt.target.value })}
testClassId="signin-input-first-name"
/> />
<Input <Input
id="last_name_create" id="last_name_create"
@@ -107,18 +108,19 @@ export default class Signin extends Component {
)} )}
value={this.state.lastName} value={this.state.lastName}
onChange={evt => this.setState({ lastName: evt.target.value })} onChange={evt => this.setState({ lastName: evt.target.value })}
testClassId="signin-input-last-name"
/> />
<br /> <br />
<br /> <br />
{this.state.login.error_subscribe_mailalreadyused && this.state.email && ( {this.state.login.error_subscribe_mailalreadyused && this.state.email && (
<div className="text error bottom-margin"> <div className="text error bottom-margin testid:signin-email-used-text">
{this.state.i18n.t('scenes.login.create_account.email_used')} {this.state.i18n.t('scenes.login.create_account.email_used')}
</div> </div>
)} )}
{this.state.errorMail && ( {this.state.errorMail && (
<div className={'text error bottom-margin'}> <div className={'text error bottom-margin testid:signin-fill-in-email-text'}>
{this.state.i18n.t('scenes.login.create_account.fill_in_email')} {this.state.i18n.t('scenes.login.create_account.fill_in_email')}
</div> </div>
)} )}
@@ -137,6 +139,7 @@ export default class Signin extends Component {
placeholder={this.state.i18n.t('scenes.login.create_account.email')} placeholder={this.state.i18n.t('scenes.login.create_account.email')}
value={this.state.email} value={this.state.email}
onChange={evt => this.setState({ email: evt.target.value })} onChange={evt => this.setState({ email: evt.target.value })}
testClassId="signin-input-email"
/> />
{this.state.errorPassword && ( {this.state.errorPassword && (
@@ -159,6 +162,7 @@ export default class Signin extends Component {
placeholder={this.state.i18n.t('scenes.login.create_account.password')} placeholder={this.state.i18n.t('scenes.login.create_account.password')}
value={this.state.password} value={this.state.password}
onChange={evt => this.setState({ password: evt.target.value })} onChange={evt => this.setState({ password: evt.target.value })}
testClassId="signin-input-password"
/> />
<div className="bottom"> <div className="bottom">
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
@@ -173,6 +177,7 @@ export default class Signin extends Component {
value={this.state.i18n.t('general.continue')} value={this.state.i18n.t('general.continue')}
loading={this.state.login.login_loading} loading={this.state.login.login_loading}
loadingTimeout={2000} loadingTimeout={2000}
testClassId="signin-button-continue"
/> />
</div> </div>
</div> </div>
@@ -207,6 +212,7 @@ export default class Signin extends Component {
value={'Send again'} value={'Send again'}
loading={this.state.login.login_loading} loading={this.state.login.login_loading}
loadingTimeout={2000} loadingTimeout={2000}
testClassId="signin-button-subscribe-mail"
/> />
</div> </div>
); );