[MM-22366] Make user autocomplete also match on spaces (#4880)
* [MM-22366] Make user autocomplete also match on spaces * Move template string to fullName variable * Add Detox E2E tests for user autocomplete * Add TM4J IDs Co-authored-by: Joseph Baylon <joseph.baylon@mattermost.com> * Add test for keyword not associated with user Co-authored-by: Joseph Baylon <joseph.baylon@mattermost.com>
This commit is contained in:
parent
fbe2a9e575
commit
cff81f168e
6 changed files with 184 additions and 2 deletions
|
|
@ -222,6 +222,7 @@ export default class AtMention extends PureComponent {
|
|||
renderItem = ({item}) => {
|
||||
return (
|
||||
<AtMentionItem
|
||||
testID={`autocomplete.at_mention.item.${item}`}
|
||||
onPress={this.completeMention}
|
||||
userId={item}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ export default class AtMentionItem extends PureComponent {
|
|||
isLandscape: PropTypes.bool.isRequired,
|
||||
isCurrentUser: PropTypes.bool.isRequired,
|
||||
showFullName: PropTypes.string,
|
||||
testID: PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -66,6 +67,7 @@ export default class AtMentionItem extends PureComponent {
|
|||
isLandscape,
|
||||
isGuest,
|
||||
isCurrentUser,
|
||||
testID,
|
||||
} = this.props;
|
||||
|
||||
const style = getStyleFromTheme(theme);
|
||||
|
|
@ -73,6 +75,7 @@ export default class AtMentionItem extends PureComponent {
|
|||
|
||||
return (
|
||||
<TouchableWithFeedback
|
||||
testID={testID}
|
||||
key={userId}
|
||||
onPress={this.completeMention}
|
||||
style={padding(isLandscape)}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
export const AT_MENTION_REGEX = /\B(@([^@\r\n\s]*))$/i;
|
||||
export const AT_MENTION_REGEX = /\B(@([^@\r\n]*))$/i;
|
||||
|
||||
export const AT_MENTION_REGEX_GLOBAL = /\B(@([^@\r\n\s]*))/gi;
|
||||
export const AT_MENTION_REGEX_GLOBAL = /\B(@([^@\r\n]*))/gi;
|
||||
|
||||
export const AT_MENTION_SEARCH_REGEX = /\bfrom:\s*(\S*)$/i;
|
||||
|
||||
|
|
|
|||
|
|
@ -73,9 +73,11 @@ export const filterMembersInChannel = createSelector(
|
|||
let profiles;
|
||||
if (matchTerm) {
|
||||
profiles = profilesInChannel.filter((p) => {
|
||||
const fullName = `${p.first_name.toLowerCase()} ${p.last_name.toLowerCase()}`;
|
||||
return (p.delete_at === 0 && (
|
||||
p.username.toLowerCase().includes(matchTerm) || p.email.toLowerCase().includes(matchTerm) ||
|
||||
p.first_name.toLowerCase().includes(matchTerm) || p.last_name.toLowerCase().includes(matchTerm) ||
|
||||
fullName.includes(matchTerm) ||
|
||||
p.nickname.toLowerCase().includes(matchTerm)));
|
||||
});
|
||||
} else {
|
||||
|
|
@ -98,10 +100,12 @@ export const filterMembersNotInChannel = createSelector(
|
|||
let profiles;
|
||||
if (matchTerm) {
|
||||
profiles = profilesNotInChannel.filter((p) => {
|
||||
const fullName = `${p.first_name.toLowerCase()} ${p.last_name.toLowerCase()}`;
|
||||
return (
|
||||
p.username.toLowerCase().includes(matchTerm) ||
|
||||
p.email.toLowerCase().includes(matchTerm) ||
|
||||
p.first_name.toLowerCase().includes(matchTerm) ||
|
||||
fullName.includes(matchTerm) ||
|
||||
p.last_name.toLowerCase().includes(matchTerm) ||
|
||||
p.nickname.toLowerCase().includes(matchTerm)
|
||||
) && p.delete_at === 0;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ describe('Selectors.Autocomplete', () => {
|
|||
['@Username', 'username'],
|
||||
['@USERNAME', 'username'],
|
||||
['not a match', null],
|
||||
['@with space', 'with space'],
|
||||
];
|
||||
|
||||
testCases.forEach((testCase) => {
|
||||
|
|
@ -98,6 +99,9 @@ describe('Selectors.Autocomplete', () => {
|
|||
|
||||
profiles = filterMembersNotInChannel(state, 'example');
|
||||
expect(profiles.length).toBe(2);
|
||||
|
||||
profiles = filterMembersNotInChannel(state, 'test u');
|
||||
expect(profiles.length).toBe(1);
|
||||
});
|
||||
|
||||
it('Should return profiles in channel', () => {
|
||||
|
|
@ -136,6 +140,9 @@ describe('Selectors.Autocomplete', () => {
|
|||
|
||||
profiles = filterMembersInChannel(state, 'example');
|
||||
expect(profiles.length).toBe(2);
|
||||
|
||||
profiles = filterMembersInChannel(state, 'test u');
|
||||
expect(profiles.length).toBe(1);
|
||||
});
|
||||
|
||||
it('Should return DMs', () => {
|
||||
|
|
|
|||
167
detox/e2e/test/autocomplete/at_mention.e2e.js
Normal file
167
detox/e2e/test/autocomplete/at_mention.e2e.js
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
// 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 {toChannelScreen} from '@support/ui/screen';
|
||||
|
||||
import {Setup} from '@support/server_api';
|
||||
|
||||
describe('Autocomplete', () => {
|
||||
let user;
|
||||
let postInput;
|
||||
|
||||
beforeAll(async () => {
|
||||
({user} = await Setup.apiInit());
|
||||
await toChannelScreen(user);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await device.reloadReactNative();
|
||||
|
||||
// # Select post draft
|
||||
await expect(element(by.id('channel_screen'))).toBeVisible();
|
||||
postInput = await element(by.id('post_input'));
|
||||
await postInput.tap();
|
||||
});
|
||||
|
||||
it('MM-T3409_1 should suggest user based on username', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
|
||||
// # Type username
|
||||
await postInput.typeText(user.username);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_2 should suggest user based on nickname', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
|
||||
// # Type nickname
|
||||
await postInput.typeText(user.nickname);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_3 should suggest user based on first name', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
|
||||
// # Type first name
|
||||
await postInput.typeText(user.first_name);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_4 should suggest user based on last name', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
|
||||
// # Type last name
|
||||
await postInput.typeText(user.last_name);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_5 should suggest user based on lowercase first name', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
|
||||
// # Type lowercase first name
|
||||
await postInput.typeText(user.first_name.toLowerCase());
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_6 should suggest user based on lowercase last name', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
|
||||
// # Type lowercase last name
|
||||
await postInput.typeText(user.last_name.toLowerCase());
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_7 should suggest user based on full name with space', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
|
||||
// # Type full name
|
||||
await postInput.typeText(`${user.first_name} ${user.last_name}`);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_8 should suggest user based on partial full name with space', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
|
||||
// # Type partial full name
|
||||
await postInput.typeText(`${user.first_name} ${user.last_name.substring(0, user.last_name.length - 6)}`);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_9 should stop suggesting user after full name with trailing space', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
|
||||
// # Type full name
|
||||
await postInput.typeText(`${user.first_name} ${user.last_name}`);
|
||||
|
||||
// * Expect at mention autocomplete to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).toExist();
|
||||
|
||||
// # Type trailing space
|
||||
await postInput.typeText(' ');
|
||||
|
||||
// * Expect at mention autocomplete not to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).not.toExist();
|
||||
});
|
||||
|
||||
it('MM-T3409_10 should stop suggesting user when keyword is not associated with any user', async () => {
|
||||
// # Type "@" to activate at mention autocomplete
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).not.toExist();
|
||||
await postInput.typeText('@');
|
||||
await expect(element(by.id('autocomplete.at_mention.list'))).toExist();
|
||||
|
||||
// # Type keyword not associated with any user
|
||||
await postInput.typeText(Date.now().toString());
|
||||
|
||||
// * Expect at mention autocomplete not to contain associated user suggestion
|
||||
await expect(element(by.id(`autocomplete.at_mention.item.${user.id}`))).not.toExist();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue