2019-03-11 20:41:08 +00:00
import { parseStatus , parseUser , parseNotification , addEmojis } from '../../../../../src/services/entity_normalizer/entity_normalizer.service.js'
2019-01-17 17:44:37 +00:00
import mastoapidata from '../../../../fixtures/mastoapi.json'
import qvitterapidata from '../../../../fixtures/statuses.json'
2019-01-15 15:39:24 +00:00
const makeMockStatusQvitter = ( overrides = { } ) => {
return Object . assign ( {
activity _type : 'post' ,
attachments : [ ] ,
attentions : [ ] ,
created _at : 'Tue Jan 15 13:57:56 +0000 2019' ,
external _url : 'https://ap.example/whatever' ,
fave _num : 1 ,
favorited : false ,
2019-01-17 16:27:57 +00:00
id : '10335970' ,
2019-01-15 15:39:24 +00:00
in _reply _to _ostatus _uri : null ,
in _reply _to _profileurl : null ,
in _reply _to _screen _name : null ,
in _reply _to _status _id : null ,
in _reply _to _user _id : null ,
is _local : false ,
is _post _verb : true ,
possibly _sensitive : false ,
repeat _num : 0 ,
repeated : false ,
2019-01-17 16:27:57 +00:00
statusnet _conversation _id : '16300488' ,
2019-01-15 15:39:24 +00:00
statusnet _html : '<p>haha benis</p>' ,
summary : null ,
tags : [ ] ,
text : 'haha benis' ,
uri : 'https://ap.example/whatever' ,
user : makeMockUserQvitter ( ) ,
visibility : 'public'
} , overrides )
}
const makeMockUserQvitter = ( overrides = { } ) => {
return Object . assign ( {
background _image : null ,
cover _photo : '' ,
created _at : 'Mon Jan 14 13:56:51 +0000 2019' ,
default _scope : 'public' ,
description : 'ebin' ,
description _html : '<p>ebin</p>' ,
favourites _count : 0 ,
fields : [ ] ,
followers _count : 1 ,
following : true ,
follows _you : true ,
friends _count : 1 ,
2019-01-17 16:27:57 +00:00
id : '60717' ,
2019-01-15 15:39:24 +00:00
is _local : false ,
locked : false ,
name : 'Spurdo :ebin:' ,
name _html : 'Spurdo <img src="whatever">' ,
no _rich _text : false ,
pleroma : { confirmation _pending : false , tags : [ ] } ,
profile _image _url : 'https://ap.example/whatever' ,
profile _image _url _https : 'https://ap.example/whatever' ,
profile _image _url _original : 'https://ap.example/whatever' ,
profile _image _url _profile _size : 'https://ap.example/whatever' ,
rights : { delete _others _notice : false } ,
screen _name : 'spurdo@ap.example' ,
statuses _count : 46 ,
statusnet _blocking : false ,
statusnet _profile _url : ''
} , overrides )
}
2019-01-17 17:44:37 +00:00
const makeMockUserMasto = ( overrides = { } ) => {
return Object . assign ( {
acct : 'hj' ,
avatar :
'https://shigusegubu.club/media/1657b945-8d5b-4ce6-aafb-4c3fc5772120/8ce851029af84d55de9164e30cc7f46d60cbf12eee7e96c5c0d35d9038ddade1.png' ,
avatar _static :
'https://shigusegubu.club/media/1657b945-8d5b-4ce6-aafb-4c3fc5772120/8ce851029af84d55de9164e30cc7f46d60cbf12eee7e96c5c0d35d9038ddade1.png' ,
bot : false ,
created _at : '2017-12-17T21:54:14.000Z' ,
display _name : 'whatever whatever whatever witch' ,
emojis : [ ] ,
fields : [ ] ,
followers _count : 705 ,
following _count : 326 ,
header :
'https://shigusegubu.club/media/7ab024d9-2a8a-4fbc-9ce8-da06756ae2db/6aadefe4e264133bc377ab450e6b045b6f5458542a5c59e6c741f86107f0388b.png' ,
header _static :
'https://shigusegubu.club/media/7ab024d9-2a8a-4fbc-9ce8-da06756ae2db/6aadefe4e264133bc377ab450e6b045b6f5458542a5c59e6c741f86107f0388b.png' ,
id : '1' ,
locked : false ,
note :
'Volatile Internet Weirdo. Name pronounced as Hee Jay. JS and Java dark arts mage, Elixir trainee. I love sampo and lain. Matrix is <span><a data-user="1" href="https://shigusegubu.club/users/hj">@<span>hj</span></a></span>:matrix.heldscal.la Pronouns are whatever. Do not DM me unless it\'s truly private matter and you\'re instance\'s admin or you risk your DM to be reposted publicly.Wish i was Finnish girl.' ,
pleroma : { confirmation _pending : false , tags : null } ,
source : { note : '' , privacy : 'public' , sensitive : false } ,
statuses _count : 41775 ,
url : 'https://shigusegubu.club/users/hj' ,
username : 'hj'
} , overrides )
}
const makeMockStatusMasto = ( overrides = { } ) => {
return Object . assign ( {
account : makeMockUserMasto ( ) ,
application : { name : 'Web' , website : null } ,
content :
'<span><a data-user="14660" href="https://pleroma.soykaf.com/users/sampo">@<span>sampo</span></a></span> god i wish i was there' ,
created _at : '2019-01-17T16:29:23.000Z' ,
emojis : [ ] ,
favourited : false ,
favourites _count : 1 ,
id : '10423476' ,
in _reply _to _account _id : '14660' ,
in _reply _to _id : '10423197' ,
language : null ,
media _attachments : [ ] ,
mentions : [
{
acct : 'sampo@pleroma.soykaf.com' ,
id : '14660' ,
url : 'https://pleroma.soykaf.com/users/sampo' ,
username : 'sampo'
}
] ,
muted : false ,
reblog : null ,
reblogged : false ,
reblogs _count : 0 ,
replies _count : 0 ,
sensitive : false ,
spoiler _text : '' ,
tags : [ ] ,
uri : 'https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639' ,
url : 'https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639' ,
2019-03-15 02:36:11 +00:00
visibility : 'public' ,
pleroma : {
local : true
}
2019-01-17 17:44:37 +00:00
} , overrides )
}
const makeMockNotificationQvitter = ( overrides = { } ) => {
return Object . assign ( {
notice : makeMockStatusQvitter ( ) ,
ntype : 'follow' ,
from _profile : makeMockUserQvitter ( ) ,
is _seen : 0 ,
id : 123
} , overrides )
}
2019-03-11 20:41:08 +00:00
const makeMockEmojiMasto = ( overrides = [ { } ] ) => {
return [
Object . assign ( {
shortcode : 'image' ,
static _url : 'https://example.com/image.png' ,
url : 'https://example.com/image.png' ,
visible _in _picker : false
} , overrides [ 0 ] ) ,
Object . assign ( {
shortcode : 'thinking' ,
static _url : 'https://example.com/think.png' ,
url : 'https://example.com/think.png' ,
visible _in _picker : false
} , overrides [ 1 ] )
]
}
2019-01-22 16:58:59 +00:00
describe ( 'API Entities normalizer' , ( ) => {
describe ( 'parseStatus' , ( ) => {
2019-01-17 17:44:37 +00:00
describe ( 'QVitter preprocessing' , ( ) => {
it ( 'doesn\'t blow up' , ( ) => {
const parsed = qvitterapidata . map ( parseStatus )
expect ( parsed . length ) . to . eq ( qvitterapidata . length )
} )
2019-01-15 15:39:24 +00:00
2019-01-17 17:44:37 +00:00
it ( 'identifies favorites' , ( ) => {
const fav = {
uri : 'tag:soykaf.com,2016-08-21:fave:2558:note:339495:2016-08-21T16:54:04+00:00' ,
is _post _verb : false
}
2019-01-15 15:39:24 +00:00
2019-01-17 17:44:37 +00:00
const mastoFav = {
uri : 'tag:mastodon.social,2016-11-27:objectId=73903:objectType=Favourite' ,
is _post _verb : false
}
expect ( parseStatus ( makeMockStatusQvitter ( fav ) ) ) . to . have . property ( 'type' , 'favorite' )
expect ( parseStatus ( makeMockStatusQvitter ( mastoFav ) ) ) . to . have . property ( 'type' , 'favorite' )
} )
it ( 'processes repeats correctly' , ( ) => {
const post = makeMockStatusQvitter ( { retweeted _status : null , id : 'deadbeef' } )
const repeat = makeMockStatusQvitter ( { retweeted _status : post , is _post _verb : false , id : 'foobar' } )
const parsedPost = parseStatus ( post )
const parsedRepeat = parseStatus ( repeat )
expect ( parsedPost ) . to . have . property ( 'type' , 'status' )
expect ( parsedRepeat ) . to . have . property ( 'type' , 'retweet' )
expect ( parsedRepeat ) . to . have . property ( 'retweeted_status' )
expect ( parsedRepeat ) . to . have . deep . property ( 'retweeted_status.id' , 'deadbeef' )
} )
it ( 'sets nsfw for statuses with the #nsfw tag' , ( ) => {
2019-07-05 07:02:14 +00:00
const safe = makeMockStatusQvitter ( { id : '1' , text : 'Hello oniichan' } )
const nsfw = makeMockStatusQvitter ( { id : '1' , text : 'Hello oniichan #nsfw' } )
2019-01-15 15:39:24 +00:00
2019-01-17 17:44:37 +00:00
expect ( parseStatus ( safe ) . nsfw ) . to . eq ( false )
expect ( parseStatus ( nsfw ) . nsfw ) . to . eq ( true )
} )
it ( 'leaves existing nsfw settings alone' , ( ) => {
2019-07-05 07:02:14 +00:00
const nsfw = makeMockStatusQvitter ( { id : '1' , text : 'Hello oniichan #nsfw' , nsfw : false } )
2019-01-17 17:44:37 +00:00
expect ( parseStatus ( nsfw ) . nsfw ) . to . eq ( false )
} )
} )
describe ( 'Mastoapi preprocessing and converting' , ( ) => {
it ( 'doesn\'t blow up' , ( ) => {
const parsed = mastoapidata . map ( parseStatus )
expect ( parsed . length ) . to . eq ( mastoapidata . length )
} )
it ( 'processes repeats correctly' , ( ) => {
const post = makeMockStatusMasto ( { reblog : null , id : 'deadbeef' } )
const repeat = makeMockStatusMasto ( { reblog : post , id : 'foobar' } )
const parsedPost = parseStatus ( post )
const parsedRepeat = parseStatus ( repeat )
expect ( parsedPost ) . to . have . property ( 'type' , 'status' )
expect ( parsedRepeat ) . to . have . property ( 'type' , 'retweet' )
expect ( parsedRepeat ) . to . have . property ( 'retweeted_status' )
expect ( parsedRepeat ) . to . have . deep . property ( 'retweeted_status.id' , 'deadbeef' )
} )
2019-03-11 20:41:08 +00:00
it ( 'adds emojis to post content' , ( ) => {
const post = makeMockStatusMasto ( { emojis : makeMockEmojiMasto ( ) , content : 'Makes you think :thinking:' } )
const parsedPost = parseStatus ( post )
expect ( parsedPost ) . to . have . property ( 'statusnet_html' ) . that . contains ( '<img' )
} )
it ( 'adds emojis to subject line' , ( ) => {
const post = makeMockStatusMasto ( { emojis : makeMockEmojiMasto ( ) , spoiler _text : 'CW: 300 IQ :thinking:' } )
const parsedPost = parseStatus ( post )
expect ( parsedPost ) . to . have . property ( 'summary_html' ) . that . contains ( '<img' )
} )
2019-01-17 17:44:37 +00:00
} )
} )
2019-01-22 16:58:59 +00:00
2019-01-17 17:44:37 +00:00
// Statuses generally already contain some info regarding users and there's nearly 1:1 mapping, so very little to test
2019-01-22 16:58:59 +00:00
describe ( 'parseUsers (MastoAPI)' , ( ) => {
2019-01-17 17:44:37 +00:00
it ( 'sets correct is_local for users depending on their screen_name' , ( ) => {
const local = makeMockUserMasto ( { acct : 'foo' } )
const remote = makeMockUserMasto ( { acct : 'foo@bar.baz' } )
2019-01-15 15:39:24 +00:00
2019-01-17 17:44:37 +00:00
expect ( parseUser ( local ) ) . to . have . property ( 'is_local' , true )
expect ( parseUser ( remote ) ) . to . have . property ( 'is_local' , false )
} )
2019-03-11 20:41:08 +00:00
it ( 'adds emojis to user name' , ( ) => {
const user = makeMockUserMasto ( { emojis : makeMockEmojiMasto ( ) , display _name : 'The :thinking: thinker' } )
const parsedUser = parseUser ( user )
expect ( parsedUser ) . to . have . property ( 'name_html' ) . that . contains ( '<img' )
} )
it ( 'adds emojis to user bio' , ( ) => {
const user = makeMockUserMasto ( { emojis : makeMockEmojiMasto ( ) , note : 'Hello i like to :thinking: a lot' } )
const parsedUser = parseUser ( user )
expect ( parsedUser ) . to . have . property ( 'description_html' ) . that . contains ( '<img' )
} )
2019-07-07 10:20:55 +00:00
it ( 'adds hide_follows and hide_followers user settings' , ( ) => {
2019-09-13 13:15:19 +00:00
const user = makeMockUserMasto ( { pleroma : { hide _followers : true , hide _follows : false , hide _followers _count : false , hide _follows _count : true } } )
2019-07-07 10:20:55 +00:00
expect ( parseUser ( user ) ) . to . have . property ( 'hide_followers' , true )
expect ( parseUser ( user ) ) . to . have . property ( 'hide_follows' , false )
2019-09-13 13:15:19 +00:00
expect ( parseUser ( user ) ) . to . have . property ( 'hide_followers_count' , false )
expect ( parseUser ( user ) ) . to . have . property ( 'hide_follows_count' , true )
2019-07-07 10:20:55 +00:00
} )
2019-01-15 15:39:24 +00:00
} )
2019-01-17 17:44:37 +00:00
// We currently use QvitterAPI notifications only, and especially due to MastoAPI lacking is_seen, support for MastoAPI
// is more of an afterthought
2019-01-22 16:58:59 +00:00
describe ( 'parseNotifications (QvitterAPI)' , ( ) => {
2019-01-17 17:44:37 +00:00
it ( 'correctly normalizes data to FE\'s format' , ( ) => {
const notif = makeMockNotificationQvitter ( {
id : 123 ,
notice : makeMockStatusQvitter ( { id : 444 } ) ,
from _profile : makeMockUserQvitter ( { id : 'spurdo' } )
} )
2019-02-11 02:32:01 +00:00
expect ( parseNotification ( notif ) ) . to . have . property ( 'id' , 123 )
2019-01-17 17:44:37 +00:00
expect ( parseNotification ( notif ) ) . to . have . property ( 'seen' , false )
expect ( parseNotification ( notif ) ) . to . have . deep . property ( 'status.id' , '444' )
expect ( parseNotification ( notif ) ) . to . have . deep . property ( 'action.id' , '444' )
expect ( parseNotification ( notif ) ) . to . have . deep . property ( 'from_profile.id' , 'spurdo' )
} )
2019-01-15 15:39:24 +00:00
2019-01-17 17:44:37 +00:00
it ( 'correctly normalizes favorite notifications' , ( ) => {
const notif = makeMockNotificationQvitter ( {
id : 123 ,
ntype : 'like' ,
notice : makeMockStatusQvitter ( {
id : 444 ,
favorited _status : makeMockStatusQvitter ( { id : 4412 } )
} ) ,
is _seen : 1 ,
from _profile : makeMockUserQvitter ( { id : 'spurdo' } )
} )
2019-02-11 02:32:01 +00:00
expect ( parseNotification ( notif ) ) . to . have . property ( 'id' , 123 )
2019-01-17 17:44:37 +00:00
expect ( parseNotification ( notif ) ) . to . have . property ( 'type' , 'like' )
expect ( parseNotification ( notif ) ) . to . have . property ( 'seen' , true )
expect ( parseNotification ( notif ) ) . to . have . deep . property ( 'status.id' , '4412' )
expect ( parseNotification ( notif ) ) . to . have . deep . property ( 'action.id' , '444' )
expect ( parseNotification ( notif ) ) . to . have . deep . property ( 'from_profile.id' , 'spurdo' )
} )
2019-01-15 15:39:24 +00:00
} )
2019-03-11 20:41:08 +00:00
describe ( 'MastoAPI emoji adder' , ( ) => {
const emojis = makeMockEmojiMasto ( )
2019-05-21 18:22:00 +00:00
const imageHtml = '<img src="https://example.com/image.png" alt="image" title="image" class="emoji" />'
2019-07-05 07:02:14 +00:00
. replace ( /"/g , '\'' )
2019-05-21 18:22:00 +00:00
const thinkHtml = '<img src="https://example.com/think.png" alt="thinking" title="thinking" class="emoji" />'
2019-07-05 07:02:14 +00:00
. replace ( /"/g , '\'' )
2019-03-11 20:41:08 +00:00
it ( 'correctly replaces shortcodes in supplied string' , ( ) => {
const result = addEmojis ( 'This post has :image: emoji and :thinking: emoji' , emojis )
expect ( result ) . to . include ( thinkHtml )
expect ( result ) . to . include ( imageHtml )
} )
it ( 'handles consecutive emojis correctly' , ( ) => {
const result = addEmojis ( 'Lelel emoji spam :thinking::thinking::thinking::thinking:' , emojis )
expect ( result ) . to . include ( thinkHtml + thinkHtml + thinkHtml + thinkHtml )
} )
it ( 'Doesn\'t replace nonexistent emojis' , ( ) => {
const result = addEmojis ( 'Admin add the :tenshi: emoji' , emojis )
expect ( result ) . to . equal ( 'Admin add the :tenshi: emoji' )
} )
2019-09-30 20:45:03 +00:00
it ( 'Doesn\'t blow up on regex special characters' , ( ) => {
const emojis = makeMockEmojiMasto ( [ {
shortcode : 'c++'
} , {
shortcode : '[a-z] {|}*'
} ] )
const result = addEmojis ( 'This post has :c++: emoji and :[a-z] {|}*: emoji' , emojis )
expect ( result ) . to . include ( 'title=\'c++\'' )
expect ( result ) . to . include ( 'title=\'[a-z] {|}*\'' )
} )
2019-03-11 20:41:08 +00:00
} )
2019-01-15 15:39:24 +00:00
} )