Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

Commit

Permalink
MM-6843 Update at-mention sort (#4063)
Browse files Browse the repository at this point in the history
* Update at-mention sort

* Fix existing at-mention provider tests

* Add tests for at-mention provider
  • Loading branch information
pqzx authored and hmhealey committed Nov 8, 2019
1 parent 025938b commit f01270a
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 13 deletions.
25 changes: 21 additions & 4 deletions components/suggestion/at_mention_provider/at_mention_provider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,29 @@ export default class AtMentionProvider extends Provider {

const remoteMembers = this.remoteMembers().filter((item) => !localUserIds[item.id]);

// comparator which prioritises users with usernames starting with search term
const orderUsers = (a, b) => {
const aStartsWith = a.username.startsWith(this.latestPrefix);
const bStartsWith = b.username.startsWith(this.latestPrefix);

if (aStartsWith && bStartsWith) {
return a.username.localeCompare(b.username);
}
if (aStartsWith) {
return -1;
}
if (bStartsWith) {
return 1;
}
return a.username.localeCompare(b.username);
};

// Combine the local and remote members, sorting to mix the results together.
const localAndRemoteMembers = localMembers.concat(remoteMembers).sort((a, b) =>
a.username.localeCompare(b.username)
);
const localAndRemoteMembers = localMembers.concat(remoteMembers).sort(orderUsers);

const remoteNonMembers = this.remoteNonMembers().filter((item) => !localUserIds[item.id]);
const remoteNonMembers = this.remoteNonMembers().
filter((item) => !localUserIds[item.id]).
sort(orderUsers);

return localAndRemoteMembers.concat(specialMentions).concat(remoteNonMembers);
}
Expand Down
141 changes: 132 additions & 9 deletions components/suggestion/at_mention_provider/at_mention_provider.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ describe('components/suggestion/at_mention_provider/AtMentionProvider', () => {
const userid2 = {id: 'userid2', username: 'user2', first_name: 'd', last_name: 'e', nickname: 'f'};
const userid4 = {id: 'userid4', username: 'user4', first_name: 'X', last_name: 'Y', nickname: 'Z'};
const userid5 = {id: 'userid5', username: 'user5', first_name: 'out', last_name: 'out', nickname: 'out'};
const userid6 = {id: 'userid6', username: 'user.six-split', first_name: 'out Junior', last_name: 'out', nickname: 'out'};
const userid6 = {id: 'userid6', username: 'user6.six-split', first_name: 'out Junior', last_name: 'out', nickname: 'out'};
const userid7 = {id: 'userid7', username: 'xuser7', first_name: '', last_name: '', nickname: 'x'};

const baseParams = {
currentUserId: 'userid1',
Expand Down Expand Up @@ -104,7 +105,7 @@ describe('components/suggestion/at_mention_provider/AtMentionProvider', () => {
'@channel',
'@all',
'@user5',
'@user.six-split',
'@user6.six-split',
],
items: [
{type: Constants.MENTION_MEMBERS, ...userid10},
Expand Down Expand Up @@ -174,7 +175,7 @@ describe('components/suggestion/at_mention_provider/AtMentionProvider', () => {
'@channel',
'@all',
'@user5',
'@user.six-split',
'@user6.six-split',
],
items: [
{type: Constants.MENTION_MEMBERS, ...userid10},
Expand Down Expand Up @@ -298,7 +299,7 @@ describe('components/suggestion/at_mention_provider/AtMentionProvider', () => {
'@user2',
'@user4',
'@user5',
'@user.six-split',
'@user6.six-split',
],
items: [
{type: Constants.MENTION_MEMBERS, ...userid2},
Expand Down Expand Up @@ -352,7 +353,7 @@ describe('components/suggestion/at_mention_provider/AtMentionProvider', () => {
expect(resultCallback).toHaveBeenNthCalledWith(3, {
matchedPretext,
terms: [
'@user.six-split',
'@user6.six-split',
],
items: [
{type: Constants.MENTION_NONMEMBERS, ...userid6},
Expand Down Expand Up @@ -403,7 +404,7 @@ describe('components/suggestion/at_mention_provider/AtMentionProvider', () => {
expect(resultCallback).toHaveBeenNthCalledWith(3, {
matchedPretext,
terms: [
'@user.six-split',
'@user6.six-split',
],
items: [
{type: Constants.MENTION_NONMEMBERS, ...userid6},
Expand Down Expand Up @@ -453,7 +454,7 @@ describe('components/suggestion/at_mention_provider/AtMentionProvider', () => {
expect(resultCallback).toHaveBeenNthCalledWith(3, {
matchedPretext,
terms: [
'@user.six-split',
'@user6.six-split',
],
items: [
{type: Constants.MENTION_NONMEMBERS, ...userid6},
Expand Down Expand Up @@ -504,7 +505,7 @@ describe('components/suggestion/at_mention_provider/AtMentionProvider', () => {
expect(resultCallback).toHaveBeenNthCalledWith(3, {
matchedPretext,
terms: [
'@user.six-split',
'@user6.six-split',
],
items: [
{type: Constants.MENTION_NONMEMBERS, ...userid6},
Expand Down Expand Up @@ -747,7 +748,7 @@ describe('components/suggestion/at_mention_provider/AtMentionProvider', () => {
'@user2',
'@user4',
'@user5',
'@user.six-split',
'@user6.six-split',
],
items: [
{type: Constants.MENTION_MEMBERS, ...userid2},
Expand All @@ -759,4 +760,126 @@ describe('components/suggestion/at_mention_provider/AtMentionProvider', () => {
});
});
});

it('should prioritise username match over other matches for in channel users', async () => {
const pretext = '@x';
const matchedPretext = '@x';
const params = {
...baseParams,
autocompleteUsersInChannel: jest.fn().mockImplementation(() => new Promise((resolve) => {
resolve({data: {
users: [userid4, userid7],
out_of_channel: [],
}});
})),
};

const provider = new AtMentionProvider(params);
const resultCallback = jest.fn();
expect(provider.handlePretextChanged(pretext, resultCallback)).toEqual(true);

expect(resultCallback).toHaveBeenNthCalledWith(1, {
matchedPretext,
terms: [
'@other',
],
items: [
{type: Constants.MENTION_MEMBERS, ...userid3},
],
component: AtMentionSuggestion,
});

jest.runAllTimers();

expect(resultCallback).toHaveBeenNthCalledWith(2, {
matchedPretext,
terms: [
'@other',
'',
],
items: [
{type: Constants.MENTION_MEMBERS, ...userid3},
{type: Constants.MENTION_MORE_MEMBERS, loading: true},
],
component: AtMentionSuggestion,
});

await Promise.resolve().then(() => {
expect(resultCallback).toHaveBeenNthCalledWith(3, {
matchedPretext,
terms: [
'@xuser7',
'@other',
'@user4',
],
items: [
{type: Constants.MENTION_MEMBERS, ...userid7},
{type: Constants.MENTION_MEMBERS, ...userid3},
{type: Constants.MENTION_MEMBERS, ...userid4},
],
component: AtMentionSuggestion,
});
});
});

it('should prioritise username match over other matches for out of channel users', async () => {
const pretext = '@x';
const matchedPretext = '@x';
const params = {
...baseParams,
autocompleteUsersInChannel: jest.fn().mockImplementation(() => new Promise((resolve) => {
resolve({data: {
users: [],
out_of_channel: [userid4, userid7],
}});
})),
};

const provider = new AtMentionProvider(params);
const resultCallback = jest.fn();
expect(provider.handlePretextChanged(pretext, resultCallback)).toEqual(true);

expect(resultCallback).toHaveBeenNthCalledWith(1, {
matchedPretext,
terms: [
'@other',
],
items: [
{type: Constants.MENTION_MEMBERS, ...userid3},
],
component: AtMentionSuggestion,
});

jest.runAllTimers();

expect(resultCallback).toHaveBeenNthCalledWith(2, {
matchedPretext,
terms: [
'@other',
'',
],
items: [
{type: Constants.MENTION_MEMBERS, ...userid3},
{type: Constants.MENTION_MORE_MEMBERS, loading: true},
],
component: AtMentionSuggestion,
});

await Promise.resolve().then(() => {
expect(resultCallback).toHaveBeenNthCalledWith(3, {
matchedPretext,
terms: [
'@other',
'@xuser7',
'@user4',
],
items: [
{type: Constants.MENTION_MEMBERS, ...userid3},
{type: Constants.MENTION_NONMEMBERS, ...userid7},
{type: Constants.MENTION_NONMEMBERS, ...userid4},
],
component: AtMentionSuggestion,
});
});
});
});

0 comments on commit f01270a

Please sign in to comment.