[MM-66375] Allow managing own membership on a channel (#9301)
* [MM-66375] Allow managing own membership on a channel * Add e2e test
This commit is contained in:
parent
3990de8932
commit
51393f13f3
16 changed files with 235 additions and 102 deletions
|
|
@ -12,7 +12,6 @@ import type {AvailableScreens} from '@typings/screens/navigation';
|
|||
import type {SectionListData} from 'react-native';
|
||||
|
||||
type Props = {
|
||||
currentUserId: string;
|
||||
tutorialWatched: boolean;
|
||||
handleSelectProfile: (user: UserProfile) => void;
|
||||
term: string;
|
||||
|
|
@ -26,7 +25,6 @@ type Props = {
|
|||
}
|
||||
|
||||
export default function ServerUserList({
|
||||
currentUserId,
|
||||
tutorialWatched,
|
||||
handleSelectProfile,
|
||||
term,
|
||||
|
|
@ -123,7 +121,6 @@ export default function ServerUserList({
|
|||
|
||||
return (
|
||||
<UserList
|
||||
currentUserId={currentUserId}
|
||||
handleSelectProfile={handleSelectProfile}
|
||||
loading={loading}
|
||||
profiles={data}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,6 @@ describe('components/channel_list_row', () => {
|
|||
return {
|
||||
profiles: [],
|
||||
testID: 'UserListRow',
|
||||
currentUserId: '1',
|
||||
handleSelectProfile: jest.fn(),
|
||||
fetchMore: jest.fn(),
|
||||
loading: true,
|
||||
|
|
|
|||
|
|
@ -172,7 +172,6 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
|
|||
type Props = {
|
||||
profiles: UserProfile[];
|
||||
channelMembers?: ChannelMembership[];
|
||||
currentUserId: string;
|
||||
handleSelectProfile: (user: UserProfile | UserModel) => void;
|
||||
fetchMore?: () => void;
|
||||
loading: boolean;
|
||||
|
|
@ -192,7 +191,6 @@ export default function UserList({
|
|||
profiles,
|
||||
channelMembers,
|
||||
selectedIds,
|
||||
currentUserId,
|
||||
handleSelectProfile,
|
||||
fetchMore,
|
||||
loading,
|
||||
|
|
@ -262,7 +260,6 @@ export default function UserList({
|
|||
highlight={section?.first && index === 0}
|
||||
id={item.id}
|
||||
isChannelAdmin={isChAdmin}
|
||||
isMyUser={currentUserId === item.id}
|
||||
manageMode={manageMode}
|
||||
onPress={handleSelectProfile}
|
||||
onLongPress={openUserProfile}
|
||||
|
|
@ -276,7 +273,7 @@ export default function UserList({
|
|||
includeMargin={includeUserMargin}
|
||||
/>
|
||||
);
|
||||
}, [selectedIds, currentUserId, manageMode, handleSelectProfile, openUserProfile, showManageMode, tutorialWatched, includeUserMargin]);
|
||||
}, [selectedIds, manageMode, handleSelectProfile, openUserProfile, showManageMode, tutorialWatched, includeUserMargin]);
|
||||
|
||||
const renderLoading = useCallback(() => {
|
||||
if (!loading) {
|
||||
|
|
@ -290,7 +287,7 @@ export default function UserList({
|
|||
size='large'
|
||||
/>
|
||||
);
|
||||
}, [loading, theme]);
|
||||
}, [loading, style.loadingContainer, theme.buttonBg]);
|
||||
|
||||
const renderNoResults = useCallback(() => {
|
||||
if (!showNoResults || !term) {
|
||||
|
|
@ -302,7 +299,7 @@ export default function UserList({
|
|||
<NoResultsWithTerm term={term}/>
|
||||
</View>
|
||||
);
|
||||
}, [showNoResults && style, term, noResutsStyle]);
|
||||
}, [showNoResults, term, noResutsStyle]);
|
||||
|
||||
const renderSectionHeader = useCallback(({section}: {section: SectionListData<UserProfile>}) => {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ type Props = {
|
|||
highlight?: boolean;
|
||||
id: string;
|
||||
includeMargin?: boolean;
|
||||
isMyUser: boolean;
|
||||
isChannelAdmin: boolean;
|
||||
manageMode: boolean;
|
||||
onLongPress: (user: UserProfile | UserModel) => void;
|
||||
|
|
@ -82,7 +81,6 @@ const messages = defineMessages({
|
|||
function UserListRow({
|
||||
id,
|
||||
includeMargin,
|
||||
isMyUser,
|
||||
highlight,
|
||||
isChannelAdmin,
|
||||
onPress,
|
||||
|
|
@ -129,7 +127,7 @@ function UserListRow({
|
|||
}, [onPress]);
|
||||
|
||||
const manageModeIcon = useMemo(() => {
|
||||
if (!showManageMode || isMyUser) {
|
||||
if (!showManageMode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -149,7 +147,7 @@ function UserListRow({
|
|||
/>
|
||||
</View>
|
||||
);
|
||||
}, [isChannelAdmin, isMyUser, showManageMode, style.manageText, style.selectorManage, theme.centerChannelColor]);
|
||||
}, [isChannelAdmin, showManageMode, style.manageText, style.selectorManage, theme.centerChannelColor]);
|
||||
|
||||
const onLayout = useCallback(() => {
|
||||
if (highlight && !tutorialWatched) {
|
||||
|
|
|
|||
|
|
@ -54,24 +54,6 @@ describe('SelectUser', () => {
|
|||
const selectUser = getByTestId('select-user');
|
||||
|
||||
// Default values from observables when no data exists
|
||||
expect(selectUser.props.currentUserId).toBe('');
|
||||
expect(selectUser.props.currentTeamId).toBe('');
|
||||
});
|
||||
|
||||
it('should render correctly with current user data', async () => {
|
||||
await operator.handleSystem({
|
||||
systems: [{
|
||||
id: SYSTEM_IDENTIFIERS.CURRENT_USER_ID,
|
||||
value: 'current-user-id',
|
||||
}],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
|
||||
const props = getBaseProps();
|
||||
const {getByTestId} = renderWithEverything(<SelectUser {...props}/>, {database});
|
||||
|
||||
const selectUser = getByTestId('select-user');
|
||||
expect(selectUser.props.currentUserId).toBe('current-user-id');
|
||||
expect(selectUser.props.currentTeamId).toBe('');
|
||||
});
|
||||
|
||||
|
|
@ -89,39 +71,11 @@ describe('SelectUser', () => {
|
|||
|
||||
const selectUser = getByTestId('select-user');
|
||||
expect(selectUser.props.currentTeamId).toBe('current-team-id');
|
||||
expect(selectUser.props.currentUserId).toBe('');
|
||||
});
|
||||
|
||||
it('should render correctly with both current user and team data', async () => {
|
||||
await operator.handleSystem({
|
||||
systems: [
|
||||
{
|
||||
id: SYSTEM_IDENTIFIERS.CURRENT_USER_ID,
|
||||
value: 'current-user-id',
|
||||
},
|
||||
{
|
||||
id: SYSTEM_IDENTIFIERS.CURRENT_TEAM_ID,
|
||||
value: 'current-team-id',
|
||||
},
|
||||
],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
|
||||
const props = getBaseProps();
|
||||
const {getByTestId} = renderWithEverything(<SelectUser {...props}/>, {database});
|
||||
|
||||
const selectUser = getByTestId('select-user');
|
||||
expect(selectUser.props.currentUserId).toBe('current-user-id');
|
||||
expect(selectUser.props.currentTeamId).toBe('current-team-id');
|
||||
});
|
||||
|
||||
it('should update observables when data changes', async () => {
|
||||
await operator.handleSystem({
|
||||
systems: [
|
||||
{
|
||||
id: SYSTEM_IDENTIFIERS.CURRENT_USER_ID,
|
||||
value: 'current-user-id',
|
||||
},
|
||||
{
|
||||
id: SYSTEM_IDENTIFIERS.CURRENT_TEAM_ID,
|
||||
value: 'current-team-id',
|
||||
|
|
@ -134,25 +88,8 @@ describe('SelectUser', () => {
|
|||
const {getByTestId} = renderWithEverything(<SelectUser {...props}/>, {database});
|
||||
|
||||
const selectUser = getByTestId('select-user');
|
||||
expect(selectUser.props.currentUserId).toBe('current-user-id');
|
||||
expect(selectUser.props.currentTeamId).toBe('current-team-id');
|
||||
|
||||
await act(async () => {
|
||||
// Update current user ID
|
||||
await operator.handleSystem({
|
||||
systems: [{
|
||||
id: SYSTEM_IDENTIFIERS.CURRENT_USER_ID,
|
||||
value: 'new-user-id',
|
||||
}],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(selectUser.props.currentUserId).toBe('new-user-id');
|
||||
expect(selectUser.props.currentTeamId).toBe('current-team-id');
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
// Update current team ID
|
||||
await operator.handleSystem({
|
||||
|
|
@ -165,7 +102,6 @@ describe('SelectUser', () => {
|
|||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(selectUser.props.currentUserId).toBe('new-user-id');
|
||||
expect(selectUser.props.currentTeamId).toBe('new-team-id');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@
|
|||
// See LICENSE.txt for license information.
|
||||
import {withDatabase, withObservables} from '@nozbe/watermelondb/react';
|
||||
|
||||
import {observeCurrentTeamId, observeCurrentUserId} from '@queries/servers/system';
|
||||
import {observeCurrentTeamId} from '@queries/servers/system';
|
||||
|
||||
import SelectUser from './select_user';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const withTeamId = withObservables([], ({database}: WithDatabaseArgs) => ({
|
||||
currentUserId: observeCurrentUserId(database),
|
||||
currentTeamId: observeCurrentTeamId(database),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ describe('SelectUser', () => {
|
|||
function getBaseProps(): ComponentProps<typeof SelectUser> {
|
||||
return {
|
||||
currentTeamId: 'team-1',
|
||||
currentUserId: 'current-user',
|
||||
handleSelect: jest.fn(),
|
||||
componentId: 'PlaybookSelectUser',
|
||||
participantIds: ['participant-1', 'participant-2'],
|
||||
|
|
@ -83,7 +82,6 @@ describe('SelectUser', () => {
|
|||
expect(queryByTestId('button')).toBeNull();
|
||||
|
||||
const userList = getByTestId('integration_selector.user_list');
|
||||
expect(userList).toHaveProp('currentUserId', props.currentUserId);
|
||||
expect(userList).toHaveProp('term', '');
|
||||
expect(userList).toHaveProp('tutorialWatched', true);
|
||||
expect(userList).toHaveProp('handleSelectProfile', expect.any(Function));
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ const close = () => {
|
|||
|
||||
export type Props = {
|
||||
currentTeamId: string;
|
||||
currentUserId: string;
|
||||
handleSelect: (opt: UserProfile) => void;
|
||||
handleRemove?: () => void;
|
||||
selected?: string;
|
||||
|
|
@ -93,7 +92,6 @@ function SelectUser({
|
|||
handleSelect,
|
||||
handleRemove,
|
||||
currentTeamId,
|
||||
currentUserId,
|
||||
componentId,
|
||||
participantIds,
|
||||
}: Props) {
|
||||
|
|
@ -251,7 +249,6 @@ function SelectUser({
|
|||
)}
|
||||
</View>
|
||||
<ServerUserList
|
||||
currentUserId={currentUserId}
|
||||
term={term}
|
||||
tutorialWatched={true}
|
||||
handleSelectProfile={handleSelectProfile}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ export const getHeaderOptions = async (theme: Theme, displayName: string, inModa
|
|||
type Props = {
|
||||
componentId: AvailableScreens;
|
||||
channel?: ChannelModel;
|
||||
currentUserId: string;
|
||||
teammateNameDisplay: string;
|
||||
tutorialWatched: boolean;
|
||||
inModal?: boolean;
|
||||
|
|
@ -119,7 +118,6 @@ function removeProfileFromList(list: Set<string>, id: string) {
|
|||
export default function ChannelAddMembers({
|
||||
componentId,
|
||||
channel,
|
||||
currentUserId,
|
||||
teammateNameDisplay,
|
||||
tutorialWatched,
|
||||
inModal,
|
||||
|
|
@ -303,7 +301,6 @@ export default function ChannelAddMembers({
|
|||
/>
|
||||
</View>
|
||||
<ServerUserList
|
||||
currentUserId={currentUserId}
|
||||
handleSelectProfile={handleSelectProfile}
|
||||
selectedIds={selectedIds}
|
||||
term={term}
|
||||
|
|
|
|||
|
|
@ -305,7 +305,6 @@ export default function CreateDirectMessage({
|
|||
/>
|
||||
</View>
|
||||
<ServerUserList
|
||||
currentUserId={currentUserId}
|
||||
handleSelectProfile={handleSelectProfile}
|
||||
selectedIds={selectedIds}
|
||||
term={term}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@
|
|||
// See LICENSE.txt for license information.
|
||||
import {withDatabase, withObservables} from '@nozbe/watermelondb/react';
|
||||
|
||||
import {observeCurrentTeamId, observeCurrentUserId} from '@queries/servers/system';
|
||||
import {observeCurrentTeamId} from '@queries/servers/system';
|
||||
|
||||
import IntegrationSelector from './integration_selector';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const withTeamId = withObservables([], ({database}: WithDatabaseArgs) => ({
|
||||
currentUserId: observeCurrentUserId(database),
|
||||
currentTeamId: observeCurrentTeamId(database),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ export type Props = {
|
|||
getDynamicOptions?: (userInput?: string) => Promise<DialogOption[]>;
|
||||
options?: PostActionOption[];
|
||||
currentTeamId: string;
|
||||
currentUserId: string;
|
||||
data?: DataTypeList;
|
||||
dataSource: string;
|
||||
handleSelect: (opt: Selection) => void;
|
||||
|
|
@ -177,7 +176,7 @@ const messages = defineMessages({
|
|||
|
||||
function IntegrationSelector(
|
||||
{dataSource, data, isMultiselect = false, selected, handleSelect,
|
||||
currentTeamId, currentUserId, componentId, getDynamicOptions, options}: Props) {
|
||||
currentTeamId, componentId, getDynamicOptions, options}: Props) {
|
||||
const serverUrl = useServerUrl();
|
||||
const theme = useTheme();
|
||||
const searchTimeoutId = useRef<NodeJS.Timeout | null>(null);
|
||||
|
|
@ -576,7 +575,6 @@ function IntegrationSelector(
|
|||
case ViewConstants.DATA_SOURCE_USERS:
|
||||
return (
|
||||
<ServerUserList
|
||||
currentUserId={currentUserId}
|
||||
term={term}
|
||||
tutorialWatched={true}
|
||||
handleSelectProfile={handleSelectProfile}
|
||||
|
|
|
|||
|
|
@ -108,6 +108,8 @@ export default function ManageChannelMembers({
|
|||
const [term, setTerm] = useState('');
|
||||
const [searchedTerm, setSearchedTerm] = useState('');
|
||||
|
||||
const hasTerm = Boolean(term);
|
||||
|
||||
const clearSearch = useCallback(() => {
|
||||
setTerm('');
|
||||
setSearchResults(EMPTY);
|
||||
|
|
@ -123,10 +125,6 @@ export default function ManageChannelMembers({
|
|||
useAndroidHardwareBackHandler(componentId, close);
|
||||
|
||||
const handleSelectProfile = useCallback(async (profile: UserProfile) => {
|
||||
if (profile.id === currentUserId && isManageMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (profile.id !== currentUserId) {
|
||||
await fetchUsersByIds(serverUrl, [profile.id]);
|
||||
}
|
||||
|
|
@ -191,7 +189,7 @@ export default function ManageChannelMembers({
|
|||
text: formatMessage(manage ? messages.button_done : messages.button_manage),
|
||||
}],
|
||||
});
|
||||
}, [theme.sidebarHeaderTextColor]);
|
||||
}, [componentId, formatMessage, theme.sidebarHeaderTextColor]);
|
||||
|
||||
const toggleManageEnabled = useCallback(() => {
|
||||
updateNavigationButtons(!isManageMode);
|
||||
|
|
@ -240,11 +238,11 @@ export default function ManageChannelMembers({
|
|||
}, [searchResults, profiles, searchedTerm, sortedProfiles]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!term) {
|
||||
if (!hasTerm) {
|
||||
setSearchResults(EMPTY);
|
||||
setSearchedTerm('');
|
||||
}
|
||||
}, [Boolean(term)]);
|
||||
}, [hasTerm]);
|
||||
|
||||
useNavButtonPressed(MANAGE_BUTTON, componentId, toggleManageEnabled, [toggleManageEnabled]);
|
||||
|
||||
|
|
@ -283,12 +281,19 @@ export default function ManageChannelMembers({
|
|||
return () => {
|
||||
mounted.current = false;
|
||||
};
|
||||
|
||||
// This effect is used only to track the mounted state and the initial fetch
|
||||
// so it should only run once
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (canManageAndRemoveMembers) {
|
||||
updateNavigationButtons(false);
|
||||
}
|
||||
|
||||
// We only want to update the navigation buttons when the permission changes
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [canManageAndRemoveMembers]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -334,7 +339,6 @@ export default function ManageChannelMembers({
|
|||
/>
|
||||
</View>
|
||||
<UserList
|
||||
currentUserId={currentUserId}
|
||||
handleSelectProfile={handleSelectProfile}
|
||||
loading={loading}
|
||||
manageMode={true} // default true to change row select icon to a dropdown
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import GlobalThreadsScreen from './global_threads';
|
|||
import HomeScreen from './home';
|
||||
import Invite from './invite';
|
||||
import LoginScreen from './login';
|
||||
import ManageChannelMembersScreen from './manage_channel_members';
|
||||
import MentionNotificationSettingsScreen from './mention_notification_settings';
|
||||
import NotificationSettingsScreen from './notification_settings';
|
||||
import PermalinkScreen from './permalink';
|
||||
|
|
@ -74,6 +75,7 @@ export {
|
|||
HomeScreen,
|
||||
Invite,
|
||||
LoginScreen,
|
||||
ManageChannelMembersScreen,
|
||||
MentionNotificationSettingsScreen,
|
||||
NotificationSettingsScreen,
|
||||
PermalinkScreen,
|
||||
|
|
|
|||
98
detox/e2e/support/ui/screen/manage_channel_members.ts
Normal file
98
detox/e2e/support/ui/screen/manage_channel_members.ts
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ProfilePicture} from '@support/ui/component';
|
||||
import {ChannelInfoScreen} from '@support/ui/screen';
|
||||
import {isIos, timeouts, wait} from '@support/utils';
|
||||
import {expect, waitFor} from 'detox';
|
||||
|
||||
class ManageChannelMembersScreen {
|
||||
testID = {
|
||||
backButton: 'screen.back.button',
|
||||
manageMembersScreen: 'manage_members.screen',
|
||||
manageDoneButton: 'manage_members.button', // Same button, text changes between "Manage" and "Done"
|
||||
searchBar: 'manage_members.search_bar',
|
||||
userList: 'manage_members.user_list',
|
||||
userItemPrefix: 'create_direct_message.user_list.user_item.',
|
||||
notice: 'manage_members.notice',
|
||||
tutorialHighlight: 'tutorial_highlight',
|
||||
tutorialSwipeLeft: 'tutorial_swipe_left',
|
||||
};
|
||||
|
||||
manageMembersScreen = element(by.id(this.testID.manageMembersScreen));
|
||||
manageButton = element(by.id(this.testID.manageDoneButton));
|
||||
doneButton = element(by.id(this.testID.manageDoneButton)); // Same element as manageButton, different text
|
||||
searchBar = element(by.id(this.testID.searchBar));
|
||||
userList = element(by.id(this.testID.userList));
|
||||
notice = element(by.id(this.testID.notice));
|
||||
tutorialHighlight = element(by.id(this.testID.tutorialHighlight));
|
||||
tutorialSwipeLeft = element(by.id(this.testID.tutorialSwipeLeft));
|
||||
backButton = element(by.id(this.testID.backButton));
|
||||
|
||||
getUserItem = (userId: string) => {
|
||||
return element(by.id(`${this.testID.userItemPrefix}${userId}.${userId}`));
|
||||
};
|
||||
|
||||
getUserItemProfilePicture = (userId: string) => {
|
||||
return element(ProfilePicture.getProfilePictureItemMatcher(this.testID.userItemPrefix, userId));
|
||||
};
|
||||
|
||||
getUserItemDisplayName = (userId: string) => {
|
||||
return element(by.id(`${this.testID.userItemPrefix}${userId}.${userId}.display_name`));
|
||||
};
|
||||
|
||||
toBeVisible = async () => {
|
||||
if (isIos()) {
|
||||
await waitFor(this.manageMembersScreen).toExist().withTimeout(timeouts.TEN_SEC);
|
||||
}
|
||||
|
||||
return this.manageMembersScreen;
|
||||
};
|
||||
|
||||
open = async () => {
|
||||
// # Open channel info screen and tap on members option
|
||||
await ChannelInfoScreen.membersOption.tap();
|
||||
await wait(timeouts.ONE_SEC);
|
||||
return this.toBeVisible();
|
||||
};
|
||||
|
||||
close = async () => {
|
||||
await this.backButton.tap();
|
||||
await expect(this.manageMembersScreen).not.toBeVisible();
|
||||
};
|
||||
|
||||
toggleManageMode = async () => {
|
||||
// # Tap on manage/done button to toggle manage mode
|
||||
// The button testID is the same for both states, so we use manageButton
|
||||
await this.manageButton.tap();
|
||||
await wait(timeouts.ONE_SEC);
|
||||
};
|
||||
|
||||
exitManageMode = async () => {
|
||||
// # Tap on done button to exit manage mode
|
||||
// The button testID is the same for both states, so we use doneButton (which is the same element)
|
||||
await this.doneButton.tap();
|
||||
await wait(timeouts.ONE_SEC);
|
||||
};
|
||||
|
||||
closeTutorial = async () => {
|
||||
try {
|
||||
if (isIos()) {
|
||||
await waitFor(this.tutorialHighlight).toExist().withTimeout(timeouts.HALF_MIN);
|
||||
await this.tutorialSwipeLeft.tap();
|
||||
await expect(this.tutorialHighlight).not.toExist();
|
||||
} else {
|
||||
await wait(timeouts.ONE_SEC);
|
||||
await device.pressBack();
|
||||
await wait(timeouts.ONE_SEC);
|
||||
}
|
||||
} catch {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Tutorial element not visible, skipping action:');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const manageChannelMembersScreen = new ManageChannelMembersScreen();
|
||||
export default manageChannelMembersScreen;
|
||||
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// *******************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a screen)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element testID when selecting an element. Create one if none.
|
||||
// *******************************************************************
|
||||
|
||||
import {
|
||||
Channel,
|
||||
Setup,
|
||||
} from '@support/server_api';
|
||||
import {
|
||||
serverOneUrl,
|
||||
siteOneUrl,
|
||||
} from '@support/test_config';
|
||||
import {
|
||||
ChannelScreen,
|
||||
ChannelListScreen,
|
||||
ChannelInfoScreen,
|
||||
HomeScreen,
|
||||
LoginScreen,
|
||||
ManageChannelMembersScreen,
|
||||
ServerScreen,
|
||||
UserProfileScreen,
|
||||
} from '@support/ui/screen';
|
||||
import {timeouts, wait} from '@support/utils';
|
||||
import {expect} from 'detox';
|
||||
|
||||
describe('Channels - Manage Own Channel Membership', () => {
|
||||
const serverOneDisplayName = 'Server 1';
|
||||
const channelsCategory = 'channels';
|
||||
let testTeam: any;
|
||||
let testUser: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
const {team, user} = await Setup.apiInit(siteOneUrl);
|
||||
testTeam = team;
|
||||
testUser = user;
|
||||
|
||||
// # Log in to server
|
||||
await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName);
|
||||
await LoginScreen.login(testUser);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
// * Verify on channel list screen
|
||||
await ChannelListScreen.toBeVisible();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// # Log out
|
||||
await HomeScreen.logout();
|
||||
});
|
||||
|
||||
it('MM-66375 - should be able to see and manage own membership in channel members list', async () => {
|
||||
// # Create a channel and add the test user to it
|
||||
const {channel} = await Channel.apiCreateChannel(siteOneUrl, {teamId: testTeam.id});
|
||||
await Channel.apiAddUserToChannel(siteOneUrl, testUser.id, channel.id);
|
||||
await device.reloadReactNative();
|
||||
|
||||
// # Open the channel screen
|
||||
await ChannelScreen.open(channelsCategory, channel.name);
|
||||
|
||||
// # Open channel info screen
|
||||
await ChannelInfoScreen.open();
|
||||
|
||||
// # Open manage channel members screen
|
||||
await ChannelInfoScreen.scrollView.scrollTo('bottom');
|
||||
await wait(timeouts.ONE_SEC);
|
||||
await ManageChannelMembersScreen.open();
|
||||
|
||||
// # Close tutorial
|
||||
await ManageChannelMembersScreen.closeTutorial();
|
||||
|
||||
// * Verify manage channel members screen is visible
|
||||
await ManageChannelMembersScreen.toBeVisible();
|
||||
|
||||
// * Verify the current user appears in the members list
|
||||
await expect(ManageChannelMembersScreen.getUserItemDisplayName(testUser.id)).toBeVisible();
|
||||
|
||||
// # Enable manage mode
|
||||
await ManageChannelMembersScreen.toggleManageMode();
|
||||
|
||||
// * Verify manage mode is enabled (done button should be visible)
|
||||
await expect(ManageChannelMembersScreen.doneButton).toBeVisible();
|
||||
|
||||
// * Verify the current user can be selected in manage mode (they should have the manage mode icon visible)
|
||||
// The manage mode icon (chevron-down) should be visible for the current user
|
||||
await expect(ManageChannelMembersScreen.getUserItem(testUser.id)).toBeVisible();
|
||||
|
||||
// # Tap on the current user in manage mode
|
||||
await ManageChannelMembersScreen.getUserItem(testUser.id).tap();
|
||||
|
||||
// * Verify that tapping on own user in manage mode opens the user profile or shows manage options
|
||||
// This verifies that the restriction preventing users from managing their own membership has been removed
|
||||
await UserProfileScreen.toBeVisible();
|
||||
|
||||
// # Close user profile screen
|
||||
await UserProfileScreen.close();
|
||||
|
||||
// # Exit manage mode
|
||||
await ManageChannelMembersScreen.exitManageMode();
|
||||
|
||||
// * Verify manage mode is disabled (manage button should be visible)
|
||||
await expect(ManageChannelMembersScreen.manageButton).toBeVisible();
|
||||
|
||||
// # Go back to channel list screen
|
||||
await ManageChannelMembersScreen.close();
|
||||
await ChannelInfoScreen.close();
|
||||
await ChannelScreen.back();
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in a new issue