Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
e8b1c089
Commit
e8b1c089
authored
Sep 18, 2020
by
Ethan Reesor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve GFM emoji auto-complete
- Match against description and unicode value
parent
def87658
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
342 additions
and
111 deletions
+342
-111
app/assets/javascripts/awards_handler.js
app/assets/javascripts/awards_handler.js
+1
-1
app/assets/javascripts/emoji/index.js
app/assets/javascripts/emoji/index.js
+93
-38
app/assets/javascripts/gfm_auto_complete.js
app/assets/javascripts/gfm_auto_complete.js
+22
-12
changelogs/unreleased/improve-gfm-ac-emoji.yml
changelogs/unreleased/improve-gfm-ac-emoji.yml
+5
-0
spec/frontend/emoji/emoji_spec.js
spec/frontend/emoji/emoji_spec.js
+96
-60
spec/frontend/gfm_auto_complete_spec.js
spec/frontend/gfm_auto_complete_spec.js
+59
-0
spec/frontend/helpers/emoji.js
spec/frontend/helpers/emoji.js
+66
-0
No files found.
app/assets/javascripts/awards_handler.js
View file @
e8b1c089
...
...
@@ -572,7 +572,7 @@ export class AwardsHandler {
}
findMatchingEmojiElements
(
query
)
{
const
emojiMatches
=
this
.
emoji
.
searchEmoji
(
query
).
map
(({
name
})
=>
name
);
const
emojiMatches
=
this
.
emoji
.
searchEmoji
(
query
,
{
match
:
'
fuzzy
'
}
).
map
(({
name
})
=>
name
);
const
$emojiElements
=
$
(
'
.emoji-menu-list:not(.frequent-emojis) [data-name]
'
);
const
$matchingElements
=
$emojiElements
.
filter
(
(
i
,
elm
)
=>
emojiMatches
.
indexOf
(
elm
.
dataset
.
name
)
>=
0
,
...
...
app/assets/javascripts/emoji/index.js
View file @
e8b1c089
import
{
uniq
}
from
'
lodash
'
;
import
fuzzaldrinPlus
from
'
fuzzaldrin-plus
'
;
import
emojiAliases
from
'
emojis/aliases.json
'
;
import
axios
from
'
../lib/utils/axios_utils
'
;
...
...
@@ -67,49 +66,111 @@ export function isEmojiNameValid(name) {
return
validEmojiNames
.
indexOf
(
name
)
>=
0
;
}
export
function
getValidEmojiUnicodeValues
()
{
return
Object
.
values
(
emojiMap
).
map
(({
e
})
=>
e
);
}
export
function
getValidEmojiDescriptions
()
{
return
Object
.
values
(
emojiMap
).
map
(({
d
})
=>
d
);
}
/**
* Search emoji by name or alias. Returns a normalized, deduplicated list of
* names.
* Retrieves an emoji by name or alias.
*
* Calling with an empty filter returns an empty array.
* Note: `initEmojiMap` must have been called and completed before this method
* can safely be called.
*
* @param {String}
* @returns {Array}
* @param {String} query The emoji name
* @param {Boolean} fallback If true, a fallback emoji will be returned if the
* named emoji does not exist. Defaults to false.
* @returns {Object} The matching emoji.
*/
export
function
queryEmojiNames
(
filter
)
{
const
matches
=
fuzzaldrinPlus
.
filter
(
validEmojiNames
,
filter
);
return
uniq
(
matches
.
map
(
name
=>
normalizeEmojiName
(
name
)));
export
function
getEmoji
(
query
,
fallback
=
false
)
{
if
(
!
emojiMap
)
{
// eslint-disable-next-line @gitlab/require-i18n-strings
throw
new
Error
(
'
The emoji map is uninitialized or initialization has not completed
'
);
}
const
lowercaseQuery
=
query
.
toLowerCase
();
const
name
=
normalizeEmojiName
(
lowercaseQuery
);
if
(
name
in
emojiMap
)
{
return
emojiMap
[
name
];
}
if
(
fallback
)
{
return
emojiMap
.
grey_question
;
}
return
null
;
}
const
searchMatchers
=
{
fuzzy
:
(
value
,
query
)
=>
fuzzaldrinPlus
.
score
(
value
,
query
)
>
0
,
// Fuzzy matching compares using a fuzzy matching library
contains
:
(
value
,
query
)
=>
value
.
indexOf
(
query
.
toLowerCase
())
>=
0
,
// Contains matching compares by indexOf
exact
:
(
value
,
query
)
=>
value
===
query
.
toLowerCase
(),
// Exact matching compares by equality
};
const
searchPredicates
=
{
name
:
(
matcher
,
query
)
=>
emoji
=>
matcher
(
emoji
.
name
,
query
),
// Search by name
alias
:
(
matcher
,
query
)
=>
emoji
=>
emoji
.
aliases
.
some
(
v
=>
matcher
(
v
,
query
)),
// Search by alias
description
:
(
matcher
,
query
)
=>
emoji
=>
matcher
(
emoji
.
d
,
query
),
// Search by description
unicode
:
(
matcher
,
query
)
=>
emoji
=>
emoji
.
e
===
query
,
// Search by unicode value (always exact)
};
/**
* Searches emoji by name, alias, description, and unicode value and returns an
* array of matches.
* Searches emoji by name, aliases, description, and unicode value and returns
* an array of matches.
*
* Behavior is undefined if `opts.fields` is empty or if `opts.match` is fuzzy
* and the query is empty.
*
* Note: `initEmojiMap` must have been called and completed before this method
* can safely be called.
*
* @param {String} query The search query
* @returns {Object[]} A list of emoji that match the query
* @param {String} query Search query.
* @param {Object} opts Search options (optional).
* @param {String[]} opts.fields Fields to search. Choices are 'name', 'alias',
* 'description', and 'unicode' (value). Default is all (four) fields.
* @param {String} opts.match Search method to use. Choices are 'exact',
* 'contains', or 'fuzzy'. All methods are case-insensitive. Exact matching (the
* default) compares by equality. Contains matching compares by indexOf. Fuzzy
* matching compares using a fuzzy matching library.
* @param {Boolean} opts.fallback If true, a fallback emoji will be returned if
* the result set is empty. Defaults to false.
* @returns {Object[]} A list of emoji that match the query.
*/
export
function
searchEmoji
(
query
)
{
if
(
!
emojiMap
)
export
function
searchEmoji
(
query
,
opts
)
{
if
(
!
emojiMap
)
{
// eslint-disable-next-line @gitlab/require-i18n-strings
throw
new
Error
(
'
The emoji map is uninitialized or initialization has not completed
'
);
}
const
{
fields
=
[
'
name
'
,
'
alias
'
,
'
description
'
,
'
unicode
'
],
match
=
'
exact
'
,
fallback
=
false
,
}
=
opts
||
{};
const
matches
=
s
=>
fuzzaldrinPlus
.
score
(
s
,
query
)
>
0
;
// Search emoji
return
Object
.
values
(
emojiMap
).
filter
(
emoji
=>
// by name
matches
(
emoji
.
name
)
||
// by alias
emoji
.
aliases
.
some
(
matches
)
||
// by description
matches
(
emoji
.
d
)
||
// by unicode value
query
===
emoji
.
e
,
// optimization for an exact match in name and alias
if
(
match
===
'
exact
'
&&
new
Set
([...
fields
,
'
name
'
,
'
alias
'
]).
size
===
2
)
{
const
emoji
=
getEmoji
(
query
,
fallback
);
return
emoji
?
[
emoji
]
:
[];
}
const
matcher
=
searchMatchers
[
match
]
||
searchMatchers
.
exact
;
const
predicates
=
fields
.
map
(
f
=>
searchPredicates
[
f
](
matcher
,
query
));
const
results
=
Object
.
values
(
emojiMap
).
filter
(
emoji
=>
predicates
.
some
(
predicate
=>
predicate
(
emoji
)),
);
// Fallback to question mark for unknown emojis
if
(
fallback
&&
results
.
length
===
0
)
{
return
[
emojiMap
.
grey_question
];
}
return
results
;
}
let
emojiCategoryMap
;
...
...
@@ -136,16 +197,10 @@ export function getEmojiCategoryMap() {
}
export
function
getEmojiInfo
(
query
)
{
let
name
=
normalizeEmojiName
(
query
);
let
emojiInfo
=
emojiMap
[
name
];
// Fallback to question mark for unknown emojis
if
(
!
emojiInfo
)
{
name
=
'
grey_question
'
;
emojiInfo
=
emojiMap
[
name
];
}
return
{
...
emojiInfo
,
name
};
return
searchEmoji
(
query
,
{
fields
:
[
'
name
'
,
'
alias
'
],
fallback
:
true
,
})[
0
];
}
export
function
emojiFallbackImageSrc
(
inputName
)
{
...
...
app/assets/javascripts/gfm_auto_complete.js
View file @
e8b1c089
...
...
@@ -191,8 +191,7 @@ class GfmAutoComplete {
}
return
tmpl
;
},
// eslint-disable-next-line no-template-curly-in-string
insertTpl
:
'
:${name}:
'
,
insertTpl
:
GfmAutoComplete
.
Emoji
.
insertTemplateFunction
,
skipSpecialCharacterTest
:
true
,
data
:
GfmAutoComplete
.
defaultLoadingData
,
callbacks
:
{
...
...
@@ -612,12 +611,7 @@ class GfmAutoComplete {
}
else
if
(
this
.
cachedData
[
at
])
{
this
.
loadData
(
$input
,
at
,
this
.
cachedData
[
at
]);
}
else
if
(
GfmAutoComplete
.
atTypeMap
[
at
]
===
'
emojis
'
)
{
Emoji
.
initEmojiMap
()
.
then
(()
=>
{
this
.
loadData
(
$input
,
at
,
Emoji
.
getValidEmojiNames
());
GfmAutoComplete
.
glEmojiTag
=
Emoji
.
glEmojiTag
;
})
.
catch
(()
=>
{});
this
.
loadEmojiData
(
$input
,
at
).
catch
(()
=>
{});
}
else
if
(
dataSource
)
{
AjaxCache
.
retrieve
(
dataSource
,
true
)
.
then
(
data
=>
{
...
...
@@ -640,6 +634,18 @@ class GfmAutoComplete {
return
$input
.
trigger
(
'
keyup
'
);
}
async
loadEmojiData
(
$input
,
at
)
{
await
Emoji
.
initEmojiMap
();
this
.
loadData
(
$input
,
at
,
[
...
Emoji
.
getValidEmojiNames
(),
...
Emoji
.
getValidEmojiDescriptions
(),
...
Emoji
.
getValidEmojiUnicodeValues
(),
]);
GfmAutoComplete
.
glEmojiTag
=
Emoji
.
glEmojiTag
;
}
clearCache
()
{
this
.
cachedData
=
{};
}
...
...
@@ -708,12 +714,16 @@ GfmAutoComplete.typesWithBackendFiltering = ['vulnerabilities'];
// Emoji
GfmAutoComplete
.
glEmojiTag
=
null
;
GfmAutoComplete
.
Emoji
=
{
insertTemplateFunction
(
value
)
{
const
{
name
=
value
.
name
}
=
Emoji
.
searchEmoji
(
value
.
name
,
{
match
:
'
contains
'
})[
0
]
||
{};
return
`:
${
name
}
:`
;
},
templateFunction
(
name
)
{
// glEmojiTag helper is loaded on-demand in fetchData()
if
(
GfmAutoComplete
.
glEmojiTag
)
{
return
`<li>
${
name
}
${
GfmAutoComplete
.
glEmojiTag
(
name
)}
</li>`
;
}
return
`<li>
${
name
}
</li>`
;
if
(
!
GfmAutoComplete
.
glEmojiTag
)
return
`<li>
${
name
}
</li>`
;
const
emoji
=
Emoji
.
searchEmoji
(
name
,
{
match
:
'
contains
'
})[
0
];
return
`<li>
${
name
}
${
GfmAutoComplete
.
glEmojiTag
(
emoji
?.
name
||
name
)}
<
/li>`
;
},
};
// Team Members
...
...
changelogs/unreleased/improve-gfm-ac-emoji.yml
0 → 100644
View file @
e8b1c089
---
title
:
Match against description and unicode character when autocompleting GFM emoji
merge_request
:
42669
author
:
Ethan Reesor (@firelizzard)
type
:
added
spec/frontend/emoji/emoji_spec.js
View file @
e8b1c089
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
{
trimText
}
from
'
helpers/text_helper
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
initEmojiMap
,
glEmojiTag
,
searchEmoji
,
EMOJI_VERSION
}
from
'
~/emoji
'
;
import
{
emojiFixtureMap
,
initEmojiMock
,
describeEmojiFields
}
from
'
helpers/emoji
'
;
import
{
glEmojiTag
,
searchEmoji
}
from
'
~/emoji
'
;
import
isEmojiUnicodeSupported
,
{
isFlagEmoji
,
isRainbowFlagEmoji
,
...
...
@@ -30,54 +29,11 @@ const emptySupportMap = {
1.1
:
false
,
};
const
emojiFixtureMap
=
{
atom
:
{
name
:
'
atom
'
,
moji
:
'
⚛
'
,
description
:
'
atom symbol
'
,
unicodeVersion
:
'
4.1
'
,
},
bomb
:
{
name
:
'
bomb
'
,
moji
:
'
💣
'
,
unicodeVersion
:
'
6.0
'
,
description
:
'
bomb
'
,
},
construction_worker_tone5
:
{
name
:
'
construction_worker_tone5
'
,
moji
:
'
👷🏿
'
,
unicodeVersion
:
'
8.0
'
,
description
:
'
construction worker tone 5
'
,
},
five
:
{
name
:
'
five
'
,
moji
:
'
5️⃣
'
,
unicodeVersion
:
'
3.0
'
,
description
:
'
keycap digit five
'
,
},
grey_question
:
{
name
:
'
grey_question
'
,
moji
:
'
❔
'
,
unicodeVersion
:
'
6.0
'
,
description
:
'
white question mark ornament
'
,
},
};
describe
(
'
gl_emoji
'
,
()
=>
{
let
mock
;
beforeEach
(()
=>
{
const
emojiData
=
Object
.
fromEntries
(
Object
.
values
(
emojiFixtureMap
).
map
(
m
=>
{
const
{
name
:
n
,
moji
:
e
,
unicodeVersion
:
u
,
category
:
c
,
description
:
d
}
=
m
;
return
[
n
,
{
c
,
e
,
d
,
u
}];
}),
);
mock
=
new
MockAdapter
(
axios
);
mock
.
onGet
(
`/-/emojis/
${
EMOJI_VERSION
}
/emojis.json`
).
reply
(
200
,
JSON
.
stringify
(
emojiData
));
return
initEmojiMap
().
catch
(()
=>
{});
beforeEach
(
async
()
=>
{
mock
=
await
initEmojiMock
();
});
afterEach
(()
=>
{
...
...
@@ -398,21 +354,101 @@ describe('gl_emoji', () => {
describe
(
'
searchEmoji
'
,
()
=>
{
const
{
atom
,
grey_question
}
=
emojiFixtureMap
;
const
contains
=
(
e
,
term
)
=>
expect
(
searchEmoji
(
term
).
map
(({
name
})
=>
name
)).
toContain
(
e
.
name
);
const
search
=
(
query
,
opts
)
=>
searchEmoji
(
query
,
opts
).
map
(({
name
})
=>
name
);
const
mangle
=
str
=>
str
.
slice
(
0
,
1
)
+
str
.
slice
(
-
1
);
const
partial
=
str
=>
str
.
slice
(
0
,
2
);
describe
(
'
with default options
'
,
()
=>
{
const
subject
=
query
=>
search
(
query
);
describeEmojiFields
(
'
with $field
'
,
({
accessor
})
=>
{
it
(
`should match by lower case:
${
accessor
(
atom
)}
`
,
()
=>
{
expect
(
subject
(
accessor
(
atom
))).
toContain
(
atom
.
name
);
});
it
(
`should match by upper case:
${
accessor
(
atom
).
toUpperCase
()}
`
,
()
=>
{
expect
(
subject
(
accessor
(
atom
).
toUpperCase
())).
toContain
(
atom
.
name
);
});
it
(
`should not match by partial:
${
mangle
(
accessor
(
atom
))}
`
,
()
=>
{
expect
(
subject
(
mangle
(
accessor
(
atom
)))).
not
.
toContain
(
atom
.
name
);
});
});
it
(
`should match by unicode value:
${
atom
.
moji
}
`
,
()
=>
{
expect
(
subject
(
atom
.
moji
)).
toContain
(
atom
.
name
);
});
it
(
'
should not return a fallback value
'
,
()
=>
{
expect
(
subject
(
'
foo bar baz
'
)).
toHaveLength
(
0
);
});
});
describe
(
'
with fuzzy match
'
,
()
=>
{
const
subject
=
query
=>
search
(
query
,
{
match
:
'
fuzzy
'
});
describeEmojiFields
(
'
with $field
'
,
({
accessor
})
=>
{
it
(
`should match by lower case:
${
accessor
(
atom
)}
`
,
()
=>
{
expect
(
subject
(
accessor
(
atom
))).
toContain
(
atom
.
name
);
});
it
(
'
should match by full name
'
,
()
=>
contains
(
grey_question
,
'
grey_question
'
));
it
(
'
should match by full alias
'
,
()
=>
contains
(
atom
,
'
atom_symbol
'
));
it
(
'
should match by full description
'
,
()
=>
contains
(
grey_question
,
'
ornament
'
));
it
(
`should match by upper case:
${
accessor
(
atom
).
toUpperCase
()}
`
,
()
=>
{
expect
(
subject
(
accessor
(
atom
).
toUpperCase
())).
toContain
(
atom
.
name
);
});
it
(
`should match by partial:
${
mangle
(
accessor
(
atom
))}
`
,
()
=>
{
expect
(
subject
(
mangle
(
accessor
(
atom
)))).
toContain
(
atom
.
name
);
});
});
});
describe
(
'
with contains match
'
,
()
=>
{
const
subject
=
query
=>
search
(
query
,
{
match
:
'
contains
'
});
describeEmojiFields
(
'
with $field
'
,
({
accessor
})
=>
{
it
(
`should match by lower case:
${
accessor
(
atom
)}
`
,
()
=>
{
expect
(
subject
(
accessor
(
atom
))).
toContain
(
atom
.
name
);
});
it
(
`should match by upper case:
${
accessor
(
atom
).
toUpperCase
()}
`
,
()
=>
{
expect
(
subject
(
accessor
(
atom
).
toUpperCase
())).
toContain
(
atom
.
name
);
});
it
(
`should match by partial:
${
partial
(
accessor
(
atom
))}
`
,
()
=>
{
expect
(
subject
(
partial
(
accessor
(
atom
)))).
toContain
(
atom
.
name
);
});
it
(
`should not match by mangled:
${
mangle
(
accessor
(
atom
))}
`
,
()
=>
{
expect
(
subject
(
mangle
(
accessor
(
atom
)))).
not
.
toContain
(
atom
.
name
);
});
});
});
it
(
'
should match by partial name
'
,
()
=>
contains
(
grey_question
,
'
question
'
));
it
(
'
should match by partial alias
'
,
()
=>
contains
(
atom
,
'
_symbol
'
));
it
(
'
should match by partial description
'
,
()
=>
contains
(
grey_question
,
'
ment
'
));
describe
(
'
with fallback
'
,
()
=>
{
const
subject
=
query
=>
search
(
query
,
{
fallback
:
true
});
it
(
'
should fuzzy match by name
'
,
()
=>
contains
(
grey_question
,
'
greion
'
));
it
(
'
should fuzzy match by alias
'
,
()
=>
contains
(
atom
,
'
atobol
'
));
it
(
'
should fuzzy match by description
'
,
()
=>
contains
(
grey_question
,
'
ornt
'
));
it
(
'
should return a fallback value
'
,
()
=>
expect
(
subject
(
'
foo bar baz
'
)).
toContain
(
grey_question
.
name
));
});
describe
(
'
with name and alias fields
'
,
()
=>
{
const
subject
=
query
=>
search
(
query
,
{
fields
:
[
'
name
'
,
'
alias
'
]
});
it
(
`should match by name:
${
atom
.
name
}
`
,
()
=>
{
expect
(
subject
(
atom
.
name
)).
toContain
(
atom
.
name
);
});
it
(
'
should match by character
'
,
()
=>
contains
(
grey_question
,
'
❔
'
));
it
(
`should match by alias:
${
atom
.
aliases
[
0
]}
`
,
()
=>
{
expect
(
subject
(
atom
.
aliases
[
0
])).
toContain
(
atom
.
name
);
});
it
(
`should not match by description:
${
atom
.
description
}
`
,
()
=>
{
expect
(
subject
(
atom
.
description
)).
not
.
toContain
(
atom
.
name
);
});
it
(
`should not match by unicode value:
${
atom
.
moji
}
`
,
()
=>
{
expect
(
subject
(
atom
.
moji
)).
not
.
toContain
(
atom
.
name
);
});
});
});
});
spec/frontend/gfm_auto_complete_spec.js
View file @
e8b1c089
/* eslint no-param-reassign: "off" */
import
$
from
'
jquery
'
;
import
{
emojiFixtureMap
,
initEmojiMock
,
describeEmojiFields
}
from
'
helpers/emoji
'
;
import
'
~/lib/utils/jquery_at_who
'
;
import
GfmAutoComplete
,
{
membersBeforeSave
}
from
'
ee_else_ce/gfm_auto_complete
'
;
...
...
@@ -702,4 +703,62 @@ describe('GfmAutoComplete', () => {
`
(
'
$input shows $output.length labels
'
,
expectLabels
);
});
});
describe
(
'
emoji
'
,
()
=>
{
const
{
atom
}
=
emojiFixtureMap
;
const
assertInserted
=
({
input
,
subject
,
emoji
})
=>
expect
(
subject
).
toBe
(
`:
${
emoji
?.
name
||
input
}:
`);
const assertTemplated = ({ input, subject, emoji }) =>
expect(subject.replace(/\s+/g, ' ')).toBe(
`
<
li
>
$
{
input
}
<gl-emoji data-name="
${
emoji
?.
name
||
input
}
"
></gl-emoji> </li>`,
);
let mock;
beforeEach(async () => {
mock = await initEmojiMock();
await new GfmAutoComplete({}).loadEmojiData({ atwho() {}, trigger() {} }, ':');
if (!GfmAutoComplete.glEmojiTag) throw new Error('emoji not loaded');
});
afterEach(() => {
mock.restore();
});
describe.each`
name | inputFormat | assert
${'insertTemplateFunction'} | ${name => ({ name })} | ${assertInserted}
${'templateFunction'} | ${name => name} | ${assertTemplated}
`('Emoji.$name', ({ name, inputFormat, assert }) => {
const execute = (input, emoji) =>
assert({
input,
emoji,
subject: GfmAutoComplete.Emoji[name](inputFormat(input)),
});
describeEmojiFields('for $field', ({ accessor }) => {
it('should work with lowercase', () => {
execute(accessor(atom), atom);
});
it('should work with uppercase', () => {
execute(accessor(atom).toUpperCase(), atom);
});
it('should work with partial value', () => {
execute(accessor(atom).slice(1), atom);
});
});
it('should work with unicode value', () => {
execute(atom.moji, atom);
});
it('should pass through unknown value', () => {
execute('foo bar baz');
});
});
});
});
spec/frontend/helpers/emoji.js
0 → 100644
View file @
e8b1c089
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
initEmojiMap
,
EMOJI_VERSION
}
from
'
~/emoji
'
;
export
const
emojiFixtureMap
=
{
atom
:
{
name
:
'
atom
'
,
moji
:
'
⚛
'
,
description
:
'
atom symbol
'
,
unicodeVersion
:
'
4.1
'
,
aliases
:
[
'
atom_symbol
'
],
},
bomb
:
{
name
:
'
bomb
'
,
moji
:
'
💣
'
,
unicodeVersion
:
'
6.0
'
,
description
:
'
bomb
'
,
aliases
:
[],
},
construction_worker_tone5
:
{
name
:
'
construction_worker_tone5
'
,
moji
:
'
👷🏿
'
,
unicodeVersion
:
'
8.0
'
,
description
:
'
construction worker tone 5
'
,
aliases
:
[],
},
five
:
{
name
:
'
five
'
,
moji
:
'
5️⃣
'
,
unicodeVersion
:
'
3.0
'
,
description
:
'
keycap digit five
'
,
aliases
:
[],
},
grey_question
:
{
name
:
'
grey_question
'
,
moji
:
'
❔
'
,
unicodeVersion
:
'
6.0
'
,
description
:
'
white question mark ornament
'
,
aliases
:
[],
},
};
export
async
function
initEmojiMock
()
{
const
emojiData
=
Object
.
fromEntries
(
Object
.
values
(
emojiFixtureMap
).
map
(
m
=>
{
const
{
name
:
n
,
moji
:
e
,
unicodeVersion
:
u
,
category
:
c
,
description
:
d
}
=
m
;
return
[
n
,
{
c
,
e
,
d
,
u
}];
}),
);
const
mock
=
new
MockAdapter
(
axios
);
mock
.
onGet
(
`/-/emojis/
${
EMOJI_VERSION
}
/emojis.json`
).
reply
(
200
,
JSON
.
stringify
(
emojiData
));
await
initEmojiMap
();
return
mock
;
}
export
function
describeEmojiFields
(
label
,
tests
)
{
describe
.
each
`
field | accessor
${
'
name
'
}
|
${
e
=>
e
.
name
}
${
'
alias
'
}
|
${
e
=>
e
.
aliases
[
0
]}
${
'
description
'
}
|
${
e
=>
e
.
description
}
`
(
label
,
tests
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment