feat: Adds id to the notifications and buttons so we can check for them in the integration tests.

This commit is contained in:
damencho 2020-07-10 10:28:57 -05:00 committed by Дамян Минков
parent 0cef706b6a
commit b106e51a10
8 changed files with 44 additions and 4 deletions

View File

@ -58,6 +58,11 @@ export type Props = {
*/ */
status?: ?string, status?: ?string,
/**
* TestId of the element, if any.
*/
testId?: string,
/** /**
* URL of the avatar, if any. * URL of the avatar, if any.
*/ */
@ -122,6 +127,7 @@ class Avatar<P: Props> extends PureComponent<P, State> {
id, id,
size, size,
status, status,
testId,
url url
} = this.props; } = this.props;
const { avatarFailed } = this.state; const { avatarFailed } = this.state;
@ -134,6 +140,7 @@ class Avatar<P: Props> extends PureComponent<P, State> {
onAvatarLoadError: undefined, onAvatarLoadError: undefined,
size, size,
status, status,
testId,
url: undefined url: undefined
}; };

View File

@ -25,7 +25,12 @@ type Props = AbstractProps & {
/** /**
* One of the expected status strings (e.g. 'available') to render a badge on the avatar, if necessary. * One of the expected status strings (e.g. 'available') to render a badge on the avatar, if necessary.
*/ */
status?: ?string status?: ?string,
/**
* TestId of the element, if any.
*/
testId?: string
}; };
/** /**
@ -45,6 +50,7 @@ export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
return ( return (
<div <div
className = { `${this._getAvatarClassName()} ${this._getBadgeClassName()}` } className = { `${this._getAvatarClassName()} ${this._getBadgeClassName()}` }
data-testid = { this.props.testId }
id = { this.props.id } id = { this.props.id }
style = { this._getAvatarStyle(this.props.color) }> style = { this._getAvatarStyle(this.props.color) }>
<Icon <Icon
@ -59,6 +65,7 @@ export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
<div className = { this._getBadgeClassName() }> <div className = { this._getBadgeClassName() }>
<img <img
className = { this._getAvatarClassName() } className = { this._getAvatarClassName() }
data-testid = { this.props.testId }
id = { this.props.id } id = { this.props.id }
onError = { this.props.onAvatarLoadError } onError = { this.props.onAvatarLoadError }
src = { url } src = { url }
@ -71,6 +78,7 @@ export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
return ( return (
<div <div
className = { `${this._getAvatarClassName()} ${this._getBadgeClassName()}` } className = { `${this._getAvatarClassName()} ${this._getBadgeClassName()}` }
data-testid = { this.props.testId }
id = { this.props.id } id = { this.props.id }
style = { this._getAvatarStyle(this.props.color) }> style = { this._getAvatarStyle(this.props.color) }>
<svg <svg
@ -97,6 +105,7 @@ export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
<div className = { this._getBadgeClassName() }> <div className = { this._getBadgeClassName() }>
<img <img
className = { this._getAvatarClassName('defaultAvatar') } className = { this._getAvatarClassName('defaultAvatar') }
data-testid = { this.props.testId }
id = { this.props.id } id = { this.props.id }
src = { this.props.defaultAvatar || 'images/avatar.png' } src = { this.props.defaultAvatar || 'images/avatar.png' }
style = { this._getAvatarStyle() } /> style = { this._getAvatarStyle() } />

View File

@ -26,6 +26,11 @@ type Props = {
*/ */
hasOptions?: boolean, hasOptions?: boolean,
/**
* TestId of the button. Can be used to locate element when testing UI.
*/
testId?: string,
/** /**
* The type of th button: primary, secondary, text. * The type of th button: primary, secondary, text.
*/ */
@ -52,6 +57,7 @@ function ActionButton({
className = '', className = '',
disabled, disabled,
hasOptions, hasOptions,
testId,
type = 'primary', type = 'primary',
onClick, onClick,
onOptionsClick onOptionsClick
@ -59,6 +65,7 @@ function ActionButton({
return ( return (
<div <div
className = { `action-btn ${className} ${type} ${disabled ? 'disabled' : ''}` } className = { `action-btn ${className} ${type} ${disabled ? 'disabled' : ''}` }
data-testid = { testId ? testId : undefined }
onClick = { disabled ? undefined : onClick }> onClick = { disabled ? undefined : onClick }>
{children} {children}
{hasOptions && <div {hasOptions && <div

View File

@ -11,6 +11,11 @@ type Props = {
*/ */
className?: string, className?: string,
/**
* TestId of the button. Can be used to locate element when testing UI.
*/
testId?: string,
/** /**
* Callback for the onChange event of the field. * Callback for the onChange event of the field.
*/ */
@ -105,6 +110,7 @@ export default class InputField extends PureComponent<Props, State> {
return ( return (
<input <input
className = { `field ${this.state.focused ? 'focused' : ''} ${this.props.className || ''}` } className = { `field ${this.state.focused ? 'focused' : ''} ${this.props.className || ''}` }
data-testid = { this.props.testId ? this.props.testId : undefined }
onBlur = { this._onBlur } onBlur = { this._onBlur }
onChange = { this._onChange } onChange = { this._onChange }
onFocus = { this._onFocus } onFocus = { this._onFocus }

View File

@ -48,25 +48,28 @@ class KnockingParticipantList extends AbstractKnockingParticipantList<Props> {
<Avatar <Avatar
displayName = { p.name } displayName = { p.name }
size = { 48 } size = { 48 }
testId = 'knockingParticipant.avatar'
url = { p.loadableAvatarUrl } /> url = { p.loadableAvatarUrl } />
<div className = 'details'> <div className = 'details'>
<span> <span data-testid = 'knockingParticipant.name'>
{ p.name } { p.name }
</span> </span>
{ p.email && ( { p.email && (
<span> <span data-testid = 'knockingParticipant.email'>
{ p.email } { p.email }
</span> </span>
) } ) }
</div> </div>
<button <button
className = 'primary' className = 'primary'
data-testid = 'lobby.allow'
onClick = { this._onRespondToParticipant(p.id, true) } onClick = { this._onRespondToParticipant(p.id, true) }
type = 'button'> type = 'button'>
{ t('lobby.allow') } { t('lobby.allow') }
</button> </button>
<button <button
className = 'borderLess' className = 'borderLess'
data-testid = 'lobby.reject'
onClick = { this._onRespondToParticipant(p.id, false) } onClick = { this._onRespondToParticipant(p.id, false) }
type = 'button'> type = 'button'>
{ t('lobby.reject') } { t('lobby.reject') }

View File

@ -97,6 +97,7 @@ class LobbyScreen extends AbstractLobbyScreen {
<InputField <InputField
onChange = { this._onChangeDisplayName } onChange = { this._onChangeDisplayName }
placeHolder = { t('lobby.nameField') } placeHolder = { t('lobby.nameField') }
testId = 'lobby.nameField'
value = { displayName } /> value = { displayName } />
</div> </div>
</div> </div>
@ -117,6 +118,7 @@ class LobbyScreen extends AbstractLobbyScreen {
className = { _passwordJoinFailed ? 'error' : '' } className = { _passwordJoinFailed ? 'error' : '' }
onChange = { this._onChangePassword } onChange = { this._onChangePassword }
placeHolder = { _passwordJoinFailed ? t('lobby.invalidPassword') : t('lobby.passwordField') } placeHolder = { _passwordJoinFailed ? t('lobby.invalidPassword') : t('lobby.passwordField') }
testId = 'lobby.password'
type = 'password' type = 'password'
value = { this.state.password } /> value = { this.state.password } />
</div> </div>
@ -136,11 +138,13 @@ class LobbyScreen extends AbstractLobbyScreen {
<ActionButton <ActionButton
disabled = { !this.state.password } disabled = { !this.state.password }
onClick = { this._onJoinWithPassword } onClick = { this._onJoinWithPassword }
testId = 'lobby.passwordJoinButton'
type = 'primary'> type = 'primary'>
{ t('lobby.passwordJoinButton') } { t('lobby.passwordJoinButton') }
</ActionButton> </ActionButton>
<ActionButton <ActionButton
onClick = { this._onSwitchToKnockMode } onClick = { this._onSwitchToKnockMode }
testId = 'lobby.backToKnockModeButton'
type = 'secondary'> type = 'secondary'>
{ t('lobby.backToKnockModeButton') } { t('lobby.backToKnockModeButton') }
</ActionButton> </ActionButton>
@ -161,11 +165,13 @@ class LobbyScreen extends AbstractLobbyScreen {
{ _knocking || <ActionButton { _knocking || <ActionButton
disabled = { !this.state.displayName } disabled = { !this.state.displayName }
onClick = { this._onAskToJoin } onClick = { this._onAskToJoin }
testId = 'lobby.knockButton'
type = 'primary'> type = 'primary'>
{ t('lobby.knockButton') } { t('lobby.knockButton') }
</ActionButton> } </ActionButton> }
<ActionButton <ActionButton
onClick = { this._onSwitchToPasswordMode } onClick = { this._onSwitchToPasswordMode }
testId = 'lobby.enterPasswordButton'
type = 'secondary'> type = 'secondary'>
{ t('lobby.enterPasswordButton') } { t('lobby.enterPasswordButton') }
</ActionButton> </ActionButton>

View File

@ -62,6 +62,7 @@ class Notification extends AbstractNotification<Props> {
id = { uid } id = { uid }
isDismissAllowed = { isDismissAllowed } isDismissAllowed = { isDismissAllowed }
onDismissed = { onDismissed } onDismissed = { onDismissed }
testId = { titleKey }
title = { title || t(titleKey, titleArguments) } /> title = { title || t(titleKey, titleArguments) } />
); );
} }
@ -84,7 +85,7 @@ class Notification extends AbstractNotification<Props> {
// the id is used for testing the UI // the id is used for testing the UI
return ( return (
<div id = { this._getDescriptionKey() || description || this.props.titleKey || this.props.title } > <div data-testid = { this._getDescriptionKey() } >
{ description } { description }
</div> </div>
); );

View File

@ -313,6 +313,7 @@ class Prejoin extends Component<Props, State> {
hasOptions = { true } hasOptions = { true }
onClick = { joinConference } onClick = { joinConference }
onOptionsClick = { _onOptionsClick } onOptionsClick = { _onOptionsClick }
testId = 'prejoin.joinMeeting'
type = 'primary'> type = 'primary'>
{ t('prejoin.joinMeeting') } { t('prejoin.joinMeeting') }
</ActionButton> </ActionButton>