From b18e27c6d4d2b3d681be8dd81dafcdfeaf20fb35 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 11 Jan 2019 03:38:23 +0300 Subject: fix tests, removed one unused function, fix real problem that tests helped to surface --- test/unit/specs/modules/statuses.spec.js | 105 +++++++++------------ test/unit/specs/modules/users.spec.js | 16 ++-- .../notification_utils/notification_utils.spec.js | 16 ++-- 3 files changed, 61 insertions(+), 76 deletions(-) (limited to 'test/unit') diff --git a/test/unit/specs/modules/statuses.spec.js b/test/unit/specs/modules/statuses.spec.js index 7d403312..f4d0ddf4 100644 --- a/test/unit/specs/modules/statuses.spec.js +++ b/test/unit/specs/modules/statuses.spec.js @@ -1,11 +1,11 @@ import { cloneDeep } from 'lodash' -import { defaultState, mutations, findMaxId, prepareStatus, statusType } from '../../../../src/modules/statuses.js' +import { defaultState, mutations, prepareStatus, statusType } from '../../../../src/modules/statuses.js' // eslint-disable-next-line camelcase const makeMockStatus = ({id, text, is_post_verb = true}) => { return { id, - user: {id: 0}, + user: {id: '0'}, name: 'status', text: text || `Text number ${id}`, fave_num: 0, @@ -32,45 +32,30 @@ describe('Statuses.statusType', () => { describe('Statuses.prepareStatus', () => { it('sets nsfw for statuses with the #nsfw tag', () => { - const safe = makeMockStatus({id: 1, text: 'Hello oniichan'}) - const nsfw = makeMockStatus({id: 1, text: 'Hello oniichan #nsfw'}) + const safe = makeMockStatus({id: '1', text: 'Hello oniichan'}) + const nsfw = makeMockStatus({id: '1', text: 'Hello oniichan #nsfw'}) expect(prepareStatus(safe).nsfw).to.eq(false) expect(prepareStatus(nsfw).nsfw).to.eq(true) }) it('leaves existing nsfw settings alone', () => { - const nsfw = makeMockStatus({id: 1, text: 'Hello oniichan #nsfw'}) + const nsfw = makeMockStatus({id: '1', text: 'Hello oniichan #nsfw'}) nsfw.nsfw = false expect(prepareStatus(nsfw).nsfw).to.eq(false) }) it('sets deleted flag to false', () => { - const aStatus = makeMockStatus({id: 1, text: 'Hello oniichan'}) + const aStatus = makeMockStatus({id: '1', text: 'Hello oniichan'}) expect(prepareStatus(aStatus).deleted).to.eq(false) }) }) -describe('Statuses.findMaxId', () => { - it('returns the largest id in any of the given arrays', () => { - const statusesOne = [{ id: 100 }, { id: 2 }] - const statusesTwo = [{ id: 3 }] - - const maxId = findMaxId(statusesOne, statusesTwo) - expect(maxId).to.eq(100) - }) - - it('returns undefined for empty arrays', () => { - const maxId = findMaxId([], []) - expect(maxId).to.eq(undefined) - }) -}) - describe('The Statuses module', () => { it('adds the status to allStatuses and to the given timeline', () => { const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) + const status = makeMockStatus({id: '1'}) mutations.addNewStatuses(state, { statuses: [status], timeline: 'public' }) @@ -82,7 +67,7 @@ describe('The Statuses module', () => { it('counts the status as new if it has not been seen on this timeline', () => { const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) + const status = makeMockStatus({id: '1'}) mutations.addNewStatuses(state, { statuses: [status], timeline: 'public' }) mutations.addNewStatuses(state, { statuses: [status], timeline: 'friends' }) @@ -100,7 +85,7 @@ describe('The Statuses module', () => { it('add the statuses to allStatuses if no timeline is given', () => { const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) + const status = makeMockStatus({id: '1'}) mutations.addNewStatuses(state, { statuses: [status] }) @@ -112,7 +97,7 @@ describe('The Statuses module', () => { it('adds the status to allStatuses and to the given timeline, directly visible', () => { const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) + const status = makeMockStatus({id: '1'}) mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' }) @@ -124,10 +109,10 @@ describe('The Statuses module', () => { it('removes statuses by tag on deletion', () => { const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) - const otherStatus = makeMockStatus({id: 3}) + const status = makeMockStatus({id: '1'}) + const otherStatus = makeMockStatus({id: '3'}) status.uri = 'xxx' - const deletion = makeMockStatus({id: 2, is_post_verb: false}) + const deletion = makeMockStatus({id: '2', is_post_verb: false}) deletion.text = 'Dolus deleted notice {{tag:gs.smuglo.li,2016-11-18:noticeId=1038007:objectType=note}}.' deletion.uri = 'xxx' @@ -137,36 +122,36 @@ describe('The Statuses module', () => { expect(state.allStatuses).to.eql([otherStatus]) expect(state.timelines.public.statuses).to.eql([otherStatus]) expect(state.timelines.public.visibleStatuses).to.eql([otherStatus]) - expect(state.timelines.public.maxId).to.eql(3) + expect(state.timelines.public.maxId).to.eql('3') }) it('does not update the maxId when the noIdUpdate flag is set', () => { const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) - const secondStatus = makeMockStatus({id: 2}) + const status = makeMockStatus({id: '1'}) + const secondStatus = makeMockStatus({id: '2'}) mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' }) - expect(state.timelines.public.maxId).to.eql(1) + expect(state.timelines.public.maxId).to.eql('1') mutations.addNewStatuses(state, { statuses: [secondStatus], showImmediately: true, timeline: 'public', noIdUpdate: true }) expect(state.timelines.public.statuses).to.eql([secondStatus, status]) expect(state.timelines.public.visibleStatuses).to.eql([secondStatus, status]) - expect(state.timelines.public.maxId).to.eql(1) + expect(state.timelines.public.maxId).to.eql('1') }) it('keeps a descending by id order in timeline.visibleStatuses and timeline.statuses', () => { const state = cloneDeep(defaultState) - const nonVisibleStatus = makeMockStatus({id: 1}) - const status = makeMockStatus({id: 3}) - const statusTwo = makeMockStatus({id: 2}) - const statusThree = makeMockStatus({id: 4}) + const nonVisibleStatus = makeMockStatus({id: '1'}) + const status = makeMockStatus({id: '3'}) + const statusTwo = makeMockStatus({id: '2'}) + const statusThree = makeMockStatus({id: '4'}) mutations.addNewStatuses(state, { statuses: [nonVisibleStatus], showImmediately: false, timeline: 'public' }) mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' }) mutations.addNewStatuses(state, { statuses: [statusTwo], showImmediately: true, timeline: 'public' }) - expect(state.timelines.public.minVisibleId).to.equal(2) + expect(state.timelines.public.minVisibleId).to.equal('2') mutations.addNewStatuses(state, { statuses: [statusThree], showImmediately: true, timeline: 'public' }) @@ -176,9 +161,9 @@ describe('The Statuses module', () => { it('splits retweets from their status and links them', () => { const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) - const retweet = makeMockStatus({id: 2, is_post_verb: false}) - const modStatus = makeMockStatus({id: 1, text: 'something else'}) + const status = makeMockStatus({id: '1'}) + const retweet = makeMockStatus({id: '2', is_post_verb: false}) + const modStatus = makeMockStatus({id: '1', text: 'something else'}) retweet.retweeted_status = status @@ -187,22 +172,22 @@ describe('The Statuses module', () => { expect(state.timelines.public.visibleStatuses).to.have.length(1) expect(state.timelines.public.statuses).to.have.length(1) expect(state.allStatuses).to.have.length(2) - expect(state.allStatuses[0].id).to.equal(1) - expect(state.allStatuses[1].id).to.equal(2) + expect(state.allStatuses[0].id).to.equal('1') + expect(state.allStatuses[1].id).to.equal('2') // It refers to the modified status. mutations.addNewStatuses(state, { statuses: [modStatus], timeline: 'public' }) expect(state.allStatuses).to.have.length(2) - expect(state.allStatuses[0].id).to.equal(1) + expect(state.allStatuses[0].id).to.equal('1') expect(state.allStatuses[0].text).to.equal(modStatus.text) - expect(state.allStatuses[1].id).to.equal(2) + expect(state.allStatuses[1].id).to.equal('2') expect(retweet.retweeted_status.text).to.eql(modStatus.text) }) it('replaces existing statuses with the same id', () => { const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) - const modStatus = makeMockStatus({id: 1, text: 'something else'}) + const status = makeMockStatus({id: '1'}) + const modStatus = makeMockStatus({id: '1', text: 'something else'}) // Add original status mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' }) @@ -218,9 +203,9 @@ describe('The Statuses module', () => { it('replaces existing statuses with the same id, coming from a retweet', () => { const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) - const modStatus = makeMockStatus({id: 1, text: 'something else'}) - const retweet = makeMockStatus({id: 2, is_post_verb: false}) + const status = makeMockStatus({id: '1'}) + const modStatus = makeMockStatus({id: '1', text: 'something else'}) + const retweet = makeMockStatus({id: '2', is_post_verb: false}) retweet.retweeted_status = modStatus // Add original status @@ -239,15 +224,15 @@ describe('The Statuses module', () => { it('handles favorite actions', () => { const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) + const status = makeMockStatus({id: '1'}) const favorite = { - id: 2, + id: '2', is_post_verb: false, in_reply_to_status_id: '1', // The API uses strings here... uri: 'tag:shitposter.club,2016-08-21:fave:3895:note:773501:2016-08-21T16:52:15+00:00', text: 'a favorited something by b', - user: { id: 99 } + user: { id: '99' } } mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' }) @@ -266,11 +251,11 @@ describe('The Statuses module', () => { // If something is favorited by the current user, it also sets the 'favorited' property but does not increment counter to avoid over-counting. Counter is incremented (updated, really) via response to the favorite request. const user = { - id: 1 + id: '1' } const ownFavorite = { - id: 3, + id: '3', is_post_verb: false, in_reply_to_status_id: '1', // The API uses strings here... uri: 'tag:shitposter.club,2016-08-21:fave:3895:note:773501:2016-08-21T16:52:15+00:00', @@ -287,16 +272,16 @@ describe('The Statuses module', () => { describe('notifications', () => { it('removes a notification when the notice gets removed', () => { - const user = { id: 1 } + const user = { id: '1' } const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) - const otherStatus = makeMockStatus({id: 3}) - const mentionedStatus = makeMockStatus({id: 2}) + const status = makeMockStatus({id: '1'}) + const otherStatus = makeMockStatus({id: '3'}) + const mentionedStatus = makeMockStatus({id: '2'}) mentionedStatus.attentions = [user] mentionedStatus.uri = 'xxx' otherStatus.attentions = [user] - const deletion = makeMockStatus({id: 4, is_post_verb: false}) + const deletion = makeMockStatus({id: '4', is_post_verb: false}) deletion.text = 'Dolus deleted notice {{tag:gs.smuglo.li,2016-11-18:noticeId=1038007:objectType=note}}.' deletion.uri = 'xxx' diff --git a/test/unit/specs/modules/users.spec.js b/test/unit/specs/modules/users.spec.js index af60c9b3..b0f3c51e 100644 --- a/test/unit/specs/modules/users.spec.js +++ b/test/unit/specs/modules/users.spec.js @@ -6,8 +6,8 @@ describe('The users module', () => { describe('mutations', () => { it('adds new users to the set, merging in new information for old users', () => { const state = cloneDeep(defaultState) - const user = { id: 1, name: 'Guy' } - const modUser = { id: 1, name: 'Dude' } + const user = { id: '1', name: 'Guy' } + const modUser = { id: '1', name: 'Dude' } mutations.addNewUsers(state, [user]) expect(state.users).to.have.length(1) @@ -21,7 +21,7 @@ describe('The users module', () => { it('sets a mute bit on users', () => { const state = cloneDeep(defaultState) - const user = { id: 1, name: 'Guy' } + const user = { id: '1', name: 'Guy' } mutations.addNewUsers(state, [user]) mutations.setMuted(state, {user, muted: true}) @@ -38,11 +38,11 @@ describe('The users module', () => { it('returns user with matching screen_name', () => { const state = { users: [ - { screen_name: 'Guy', id: 1 } + { screen_name: 'Guy', id: '1' } ] } const name = 'Guy' - const expected = { screen_name: 'Guy', id: 1 } + const expected = { screen_name: 'Guy', id: '1' } expect(getters.userByName(state)(name)).to.eql(expected) }) }) @@ -51,11 +51,11 @@ describe('The users module', () => { it('returns user with matching id', () => { const state = { users: [ - { screen_name: 'Guy', id: 1 } + { screen_name: 'Guy', id: '1' } ] } - const id = 1 - const expected = { screen_name: 'Guy', id: 1 } + const id = '1' + const expected = { screen_name: 'Guy', id: '1' } expect(getters.userById(state)(id)).to.eql(expected) }) }) diff --git a/test/unit/specs/services/notification_utils/notification_utils.spec.js b/test/unit/specs/services/notification_utils/notification_utils.spec.js index c44b8c9e..e945459e 100644 --- a/test/unit/specs/services/notification_utils/notification_utils.spec.js +++ b/test/unit/specs/services/notification_utils/notification_utils.spec.js @@ -9,15 +9,15 @@ describe('NotificationUtils', () => { notifications: { data: [ { - action: { id: 1 }, + action: { id: '1' }, type: 'like' }, { - action: { id: 2 }, + action: { id: '2' }, type: 'mention' }, { - action: { id: 3 }, + action: { id: '3' }, type: 'repeat' } ] @@ -34,11 +34,11 @@ describe('NotificationUtils', () => { } const expected = [ { - action: { id: 3 }, + action: { id: '3' }, type: 'repeat' }, { - action: { id: 1 }, + action: { id: '1' }, type: 'like' } ] @@ -54,12 +54,12 @@ describe('NotificationUtils', () => { notifications: { data: [ { - action: { id: 1 }, + action: { id: '1' }, type: 'like', seen: false }, { - action: { id: 2 }, + action: { id: '2' }, type: 'mention', seen: true } @@ -77,7 +77,7 @@ describe('NotificationUtils', () => { } const expected = [ { - action: { id: 1 }, + action: { id: '1' }, type: 'like', seen: false } -- cgit v1.2.3-70-g09d2 From d7bd294666cba08b6f6a8d447fbdf4cd59e66b2b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 15 Jan 2019 18:39:24 +0300 Subject: migrated some tests to normalizer, fixed some potential bug, fixed tests to use normalized naming instead of raw qvitter api objects. needs more tests tho. --- src/modules/statuses.js | 3 + src/services/api/api.service.js | 2 +- .../entity_normalizer/entity_normalizer.service.js | 212 +++++++++++++++++++++ .../status_normalizer/status_normalizer.service.js | 209 -------------------- test/unit/specs/modules/statuses.spec.js | 64 ++----- .../entity_normalizer/entity_normalizer.spec.js | 102 ++++++++++ 6 files changed, 337 insertions(+), 255 deletions(-) create mode 100644 src/services/entity_normalizer/entity_normalizer.service.js delete mode 100644 src/services/status_normalizer/status_normalizer.service.js create mode 100644 test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js (limited to 'test/unit') diff --git a/src/modules/statuses.js b/src/modules/statuses.js index fde019b7..2ece12ba 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -225,6 +225,9 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us remove(timelineObject.visibleStatuses, { uri }) } }, + 'follow': (follow) => { + // NOOP, it is known status but we don't do anything about it for now + }, 'default': (unknown) => { console.log('unknown status type') console.log(unknown) diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index e82f4f81..14a526ef 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -44,7 +44,7 @@ const SUGGESTIONS_URL = '/api/v1/suggestions' const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites' import { each, map } from 'lodash' -import { parseStatus, parseUser, parseNotification } from '../status_normalizer/status_normalizer.service.js' +import { parseStatus, parseUser, parseNotification } from '../entity_normalizer/entity_normalizer.service.js' import 'whatwg-fetch' const oldfetch = window.fetch diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js new file mode 100644 index 00000000..adc7f047 --- /dev/null +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -0,0 +1,212 @@ +const qvitterStatusType = (status) => { + if (status.is_post_verb) { + return 'status' + } + + if (status.retweeted_status) { + return 'retweet' + } + + if ((typeof status.uri === 'string' && status.uri.match(/(fave|objectType=Favourite)/)) || + (typeof status.text === 'string' && status.text.match(/favorited/))) { + return 'favorite' + } + + if (status.text.match(/deleted notice {{tag/) || status.qvitter_delete_notice) { + return 'deletion' + } + + if (status.text.match(/started following/) || status.activity_type === 'follow') { + return 'follow' + } + + return 'unknown' +} + +export const parseUser = (data) => { + const output = {} + const masto = data.hasOwnProperty('acct') + // case for users in "mentions" property for statuses in MastoAPI + const mastoShort = masto && !data.hasOwnProperty('avatar') + + output.id = data.id + + if (masto) { + output.screen_name = data.acct + + // There's nothing else to get + if (mastoShort) { + return output + } + + output.name = null // missing + output.name_html = data.display_name + + output.description = null // missing + output.description_html = data.note + + // Utilize avatar_static for gif avatars? + output.profile_image_url = data.avatar + output.profile_image_url_original = data.avatar + + // Same, utilize header_static? + output.cover_photo = data.header + + output.friends_count = data.following_count + + output.bot = data.bot + + output.statusnet_profile_url = data.url + + // Missing, trying to recover + output.is_local = !output.screen_name.includes('@') + } else { + output.screen_name = data.screen_name + + output.name = data.name + output.name_html = data.name_html + + output.description = data.description + output.description_html = data.description_html + + output.profile_image_url = data.profile_image_url + output.profile_image_url_original = data.profile_image_url_original + + output.cover_photo = data.cover_photo + + output.friends_count = data.friends_count + + output.bot = null // missing + + output.statusnet_profile_url = data.statusnet_profile_url + output.is_local = data.is_local + } + + output.created_at = new Date(data.created_at) + output.locked = data.locked + output.followers_count = data.followers_count + output.statuses_count = data.statuses_count + + return output +} + +const parseAttachment = (data) => { + // TODO A little bit messy ATM but works with both APIs + return { + ...data, + mimetype: data.mimetype || data.type + } +} + +export const parseStatus = (data) => { + const output = {} + const masto = data.hasOwnProperty('account') + + if (masto) { + output.favorited = data.favourited + output.fave_num = data.favourites_count + + output.repeated = data.reblogged + output.repeat_num = data.reblogs_count + + output.type = data.reblog ? 'retweet' : 'status' + output.nsfw = data.sensitive + + output.statusnet_html = data.content + + // Not exactly the same but works? + output.text = data.content + + output.in_reply_to_status_id = data.in_reply_to_id + output.in_reply_to_user_id = data.in_reply_to_user_id + + // Not exactly the same but works + output.statusnet_conversation_id = data.id + } else { + output.favorited = data.favorited + output.fave_num = data.fave_num + + output.repeated = data.repeated + output.repeat_num = data.repeat_num + + // catchall, temporary + // Object.assign(output, data) + + output.type = qvitterStatusType(data) + + if (data.nsfw === undefined) { + output.nsfw = isNsfw(data) + if (data.retweeted_status) { + output.nsfw = data.retweeted_status.nsfw + } + } else { + output.nsfw = data.nsfw + } + + output.statusnet_html = data.statusnet_html + output.text = data.text + + output.in_reply_to_status_id = data.in_reply_to_id + output.in_reply_to_user_id = data.in_reply_to_account_id + + output.statusnet_conversation_id = data.statusnet_conversation_id + } + + output.id = Number(data.id) + output.visibility = data.visibility + output.created_at = new Date(data.created_at) + + output.user = parseUser(masto ? data.account : data.user) + + output.attentions = ((masto ? data.mentions : data.attentions) || []) + .map(_ => ({ + id: _.id, + following: _.following // FIXME: MastoAPI doesn't have this + })) + + output.attachments = ((masto ? data.media_attachments : data.attachments) || []) + .map(parseAttachment) + + const retweetedStatus = masto ? data.reblog : data.retweeted_status + if (retweetedStatus) { + output.retweeted_status = parseStatus(retweetedStatus) + } + + return output +} + +export const parseNotification = (data) => { + const mastoDict = { + 'favourite': 'like', + 'reblog': 'repeat' + } + const masto = !data.hasOwnProperty('ntype') + const output = {} + + if (masto) { + output.type = mastoDict[data.type] || data.type + output.seen = null // missing + output.status = parseStatus(data.status) + output.action = null // missing + output.from_profile = parseUser(data.account) + } else { + const parsedNotice = parseStatus(data.notice) + output.type = data.ntype + output.seen = data.is_seen + output.status = output.type === 'like' + ? parseStatus(data.notice.favorited_status) + : parsedNotice + output.action = parsedNotice + output.from_profile = parseUser(data.from_profile) + } + + output.created_at = new Date(data.created_at) + output.id = data.id + + return output +} + +const isNsfw = (status) => { + const nsfwRegex = /#nsfw/i + return (status.tags || []).includes('nsfw') || !!status.text.match(nsfwRegex) +} diff --git a/src/services/status_normalizer/status_normalizer.service.js b/src/services/status_normalizer/status_normalizer.service.js deleted file mode 100644 index 784c7f20..00000000 --- a/src/services/status_normalizer/status_normalizer.service.js +++ /dev/null @@ -1,209 +0,0 @@ -const qvitterStatusType = (status) => { - if (status.is_post_verb) { - return 'status' - } - - if (status.retweeted_status) { - return 'retweet' - } - - if ((typeof status.uri === 'string' && status.uri.match(/(fave|objectType=Favourite)/)) || - (typeof status.text === 'string' && status.text.match(/favorited/))) { - return 'favorite' - } - - if (status.text.match(/deleted notice {{tag/) || status.qvitter_delete_notice) { - return 'deletion' - } - - if (status.text.match(/started following/) || status.activity_type === 'follow') { - return 'follow' - } - - return 'unknown' -} - -export const parseUser = (data) => { - const output = {} - const masto = data.hasOwnProperty('acct') - // case for users in "mentions" property for statuses in MastoAPI - const mastoShort = masto && !data.hasOwnProperty('avatar') - - output.id = data.id - - if (masto) { - output.screen_name = data.acct - - // There's nothing else to get - if (mastoShort) { - return output - } - - output.name = null // missing - output.name_html = data.display_name - - output.description = null // missing - output.description_html = data.note - - // Utilize avatar_static for gif avatars? - output.profile_image_url = data.avatar - output.profile_image_url_original = data.avatar - - // Same, utilize header_static? - output.cover_photo = data.header - - output.friends_count = data.following_count - - output.bot = data.bot - - output.statusnet_profile_url = data.url - - // Missing, trying to recover - output.is_local = !output.screen_name.includes('@') - } else { - output.screen_name = data.screen_name - - output.name = data.name - output.name_html = data.name_html - - output.description = data.description - output.description_html = data.description_html - - output.profile_image_url = data.profile_image_url - output.profile_image_url_original = data.profile_image_url_original - - output.cover_photo = data.cover_photo - - output.friends_count = data.friends_count - - output.bot = null // missing - - output.statusnet_profile_url = data.statusnet_profile_url - output.is_local = data.is_local - } - - output.created_at = new Date(data.created_at) - output.locked = data.locked - output.followers_count = data.followers_count - output.statuses_count = data.statuses_count - - return output -} - -const parseAttachment = (data) => { - // TODO A little bit messy ATM but works with both APIs - return { - ...data, - mimetype: data.mimetype || data.type - } -} - -export const parseStatus = (data) => { - const output = {} - const masto = data.hasOwnProperty('account') - - if (masto) { - output.favorited = data.favourited - output.fave_num = data.favourites_count - - output.repeated = data.reblogged - output.repeat_num = data.reblogs_count - - output.type = data.reblog ? 'retweet' : 'status' - output.nsfw = data.sensitive - - output.statusnet_html = data.content - - // Not exactly the same but works? - output.text = data.content - - output.in_reply_to_status_id = data.in_reply_to_id - output.in_reply_to_user_id = data.in_reply_to_user_id - - // Not exactly the same but works - output.statusnet_conversation_id = data.id - } else { - output.favorited = data.favorited - output.fave_num = data.fave_num - - output.repeated = data.repeated - output.repeat_num = data.repeat_num - - // catchall, temporary - // Object.assign(output, data) - - output.type = qvitterStatusType(data) - - if (data.nsfw === undefined) { - output.nsfw = isNsfw(data) - if (data.retweeted_status) { - output.nsfw = data.retweeted_status.nsfw - } - } - output.statusnet_html = data.statusnet_html - output.text = data.text - - output.in_reply_to_status_id = data.in_reply_to_id - output.in_reply_to_user_id = data.in_reply_to_account_id - - output.statusnet_conversation_id = data.statusnet_conversation_id - } - - output.id = Number(data.id) - output.visibility = data.visibility - output.created_at = new Date(data.created_at) - - output.user = parseUser(masto ? data.account : data.user) - - output.attentions = ((masto ? data.mentions : data.attentions) || []) - .map(_ => ({ - id: _.id, - following: _.following // FIXME: MastoAPI doesn't have this - })) - - output.attachments = ((masto ? data.media_attachments : data.attachments) || []) - .map(parseAttachment) - - const retweetedStatus = masto ? data.reblog : data.retweeted_status - if (retweetedStatus) { - output.retweeted_status = parseStatus(retweetedStatus) - } - - return output -} - -export const parseNotification = (data) => { - const mastoDict = { - 'favourite': 'like', - 'reblog': 'repeat' - } - const masto = !data.hasOwnProperty('ntype') - const output = {} - - if (masto) { - output.type = mastoDict[data.type] || data.type - output.seen = null // missing - output.status = parseStatus(data.status) - output.action = null // missing - output.from_profile = parseUser(data.account) - } else { - const parsedNotice = parseStatus(data.notice) - output.type = data.ntype - output.seen = data.is_seen - output.status = output.type === 'like' - ? parseStatus(data.notice.favorited_status) - : parsedNotice - output.action = parsedNotice - output.from_profile = parseUser(data.from_profile) - } - - output.created_at = new Date(data.created_at) - output.id = data.id - - return output -} - -const isNsfw = (status) => { - const nsfwRegex = /#nsfw/i - return (status.tags || []).includes('nsfw') || !!status.text.match(nsfwRegex) -} diff --git a/test/unit/specs/modules/statuses.spec.js b/test/unit/specs/modules/statuses.spec.js index 7d403312..0b511b80 100644 --- a/test/unit/specs/modules/statuses.spec.js +++ b/test/unit/specs/modules/statuses.spec.js @@ -1,8 +1,8 @@ import { cloneDeep } from 'lodash' -import { defaultState, mutations, findMaxId, prepareStatus, statusType } from '../../../../src/modules/statuses.js' +import { defaultState, mutations, findMaxId, prepareStatus } from '../../../../src/modules/statuses.js' // eslint-disable-next-line camelcase -const makeMockStatus = ({id, text, is_post_verb = true}) => { +const makeMockStatus = ({id, text, type = 'status'}) => { return { id, user: {id: 0}, @@ -10,42 +10,12 @@ const makeMockStatus = ({id, text, is_post_verb = true}) => { text: text || `Text number ${id}`, fave_num: 0, uri: '', - is_post_verb, + type, attentions: [] } } -describe('Statuses.statusType', () => { - it('identifies favorites', () => { - const fav = { - uri: 'tag:soykaf.com,2016-08-21:fave:2558:note:339495:2016-08-21T16:54:04+00:00' - } - - const mastoFav = { - uri: 'tag:mastodon.social,2016-11-27:objectId=73903:objectType=Favourite' - } - - expect(statusType(fav)).to.eql('favorite') - expect(statusType(mastoFav)).to.eql('favorite') - }) -}) - describe('Statuses.prepareStatus', () => { - it('sets nsfw for statuses with the #nsfw tag', () => { - const safe = makeMockStatus({id: 1, text: 'Hello oniichan'}) - const nsfw = makeMockStatus({id: 1, text: 'Hello oniichan #nsfw'}) - - expect(prepareStatus(safe).nsfw).to.eq(false) - expect(prepareStatus(nsfw).nsfw).to.eq(true) - }) - - it('leaves existing nsfw settings alone', () => { - const nsfw = makeMockStatus({id: 1, text: 'Hello oniichan #nsfw'}) - nsfw.nsfw = false - - expect(prepareStatus(nsfw).nsfw).to.eq(false) - }) - it('sets deleted flag to false', () => { const aStatus = makeMockStatus({id: 1, text: 'Hello oniichan'}) expect(prepareStatus(aStatus).deleted).to.eq(false) @@ -127,7 +97,7 @@ describe('The Statuses module', () => { const status = makeMockStatus({id: 1}) const otherStatus = makeMockStatus({id: 3}) status.uri = 'xxx' - const deletion = makeMockStatus({id: 2, is_post_verb: false}) + const deletion = makeMockStatus({id: 2, type: 'deletion'}) deletion.text = 'Dolus deleted notice {{tag:gs.smuglo.li,2016-11-18:noticeId=1038007:objectType=note}}.' deletion.uri = 'xxx' @@ -177,7 +147,7 @@ describe('The Statuses module', () => { it('splits retweets from their status and links them', () => { const state = cloneDeep(defaultState) const status = makeMockStatus({id: 1}) - const retweet = makeMockStatus({id: 2, is_post_verb: false}) + const retweet = makeMockStatus({id: 2, type: 'retweet'}) const modStatus = makeMockStatus({id: 1, text: 'something else'}) retweet.retweeted_status = status @@ -220,7 +190,7 @@ describe('The Statuses module', () => { const state = cloneDeep(defaultState) const status = makeMockStatus({id: 1}) const modStatus = makeMockStatus({id: 1, text: 'something else'}) - const retweet = makeMockStatus({id: 2, is_post_verb: false}) + const retweet = makeMockStatus({id: 2, type: 'retweet'}) retweet.retweeted_status = modStatus // Add original status @@ -243,7 +213,7 @@ describe('The Statuses module', () => { const favorite = { id: 2, - is_post_verb: false, + type: 'favorite', in_reply_to_status_id: '1', // The API uses strings here... uri: 'tag:shitposter.club,2016-08-21:fave:3895:note:773501:2016-08-21T16:52:15+00:00', text: 'a favorited something by b', @@ -271,7 +241,7 @@ describe('The Statuses module', () => { const ownFavorite = { id: 3, - is_post_verb: false, + type: 'favorite', in_reply_to_status_id: '1', // The API uses strings here... uri: 'tag:shitposter.club,2016-08-21:fave:3895:note:773501:2016-08-21T16:52:15+00:00', text: 'a favorited something by b', @@ -296,7 +266,7 @@ describe('The Statuses module', () => { mentionedStatus.uri = 'xxx' otherStatus.attentions = [user] - const deletion = makeMockStatus({id: 4, is_post_verb: false}) + const deletion = makeMockStatus({id: 4, type: 'deletion'}) deletion.text = 'Dolus deleted notice {{tag:gs.smuglo.li,2016-11-18:noticeId=1038007:objectType=note}}.' deletion.uri = 'xxx' @@ -305,10 +275,12 @@ describe('The Statuses module', () => { state, { notifications: [{ - ntype: 'mention', + from_profile: { id: 2 }, + id: 998, + type: 'mention', status: otherStatus, - notice: otherStatus, - is_seen: false + action: otherStatus, + seen: false }] }) @@ -317,10 +289,12 @@ describe('The Statuses module', () => { state, { notifications: [{ - ntype: 'mention', + from_profile: { id: 2 }, + id: 999, + type: 'mention', status: mentionedStatus, - notice: mentionedStatus, - is_seen: false + action: mentionedStatus, + seen: false }] }) diff --git a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js new file mode 100644 index 00000000..e5882725 --- /dev/null +++ b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js @@ -0,0 +1,102 @@ +import { parseStatus, parseUser, parseNotification } from '../../../../../src/services/entity_normalizer/entity_normalizer.service.js' + +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, + id: 10335970, + 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, + statusnet_conversation_id: 16300488, + statusnet_html: '

haha benis

', + 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: '

ebin

', + favourites_count: 0, + fields: [], + followers_count: 1, + following: true, + follows_you: true, + friends_count: 1, + id: 60717, + is_local: false, + locked: false, + name: 'Spurdo :ebin:', + name_html: 'Spurdo ', + 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) +} + +parseNotification +parseUser +parseStatus +makeMockStatusQvitter +makeMockUserQvitter + +describe('QVitter preprocessing', () => { + 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 + } + + 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('sets nsfw for statuses with the #nsfw tag', () => { + const safe = makeMockStatusQvitter({id: 1, text: 'Hello oniichan'}) + const nsfw = makeMockStatusQvitter({id: 1, text: 'Hello oniichan #nsfw'}) + + expect(parseStatus(safe).nsfw).to.eq(false) + expect(parseStatus(nsfw).nsfw).to.eq(true) + }) + + it('leaves existing nsfw settings alone', () => { + const nsfw = makeMockStatusQvitter({id: 1, text: 'Hello oniichan #nsfw', nsfw: false}) + + expect(parseStatus(nsfw).nsfw).to.eq(false) + }) +}) -- cgit v1.2.3-70-g09d2 From a2ef716f3b4b82564fb14d19665d64257d3d629b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 17 Jan 2019 19:27:57 +0300 Subject: consistency in tests too --- test/unit/specs/modules/statuses.spec.js | 28 +++++++++++----------- .../entity_normalizer/entity_normalizer.spec.js | 12 +++++----- 2 files changed, 20 insertions(+), 20 deletions(-) (limited to 'test/unit') diff --git a/test/unit/specs/modules/statuses.spec.js b/test/unit/specs/modules/statuses.spec.js index 076e238c..33628b9b 100644 --- a/test/unit/specs/modules/statuses.spec.js +++ b/test/unit/specs/modules/statuses.spec.js @@ -82,7 +82,7 @@ describe('The Statuses module', () => { const status = makeMockStatus({id: '1'}) const otherStatus = makeMockStatus({id: '3'}) status.uri = 'xxx' - const deletion = makeMockStatus({id: 2, type: 'deletion'}) + const deletion = makeMockStatus({id: '2', type: 'deletion'}) deletion.text = 'Dolus deleted notice {{tag:gs.smuglo.li,2016-11-18:noticeId=1038007:objectType=note}}.' deletion.uri = 'xxx' @@ -131,9 +131,9 @@ describe('The Statuses module', () => { it('splits retweets from their status and links them', () => { const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) - const retweet = makeMockStatus({id: 2, type: 'retweet'}) - const modStatus = makeMockStatus({id: 1, text: 'something else'}) + const status = makeMockStatus({id: '1'}) + const retweet = makeMockStatus({id: '2', type: 'retweet'}) + const modStatus = makeMockStatus({id: '1', text: 'something else'}) retweet.retweeted_status = status @@ -173,9 +173,9 @@ describe('The Statuses module', () => { it('replaces existing statuses with the same id, coming from a retweet', () => { const state = cloneDeep(defaultState) - const status = makeMockStatus({id: 1}) - const modStatus = makeMockStatus({id: 1, text: 'something else'}) - const retweet = makeMockStatus({id: 2, type: 'retweet'}) + const status = makeMockStatus({id: '1'}) + const modStatus = makeMockStatus({id: '1', text: 'something else'}) + const retweet = makeMockStatus({id: '2', type: 'retweet'}) retweet.retweeted_status = modStatus // Add original status @@ -197,7 +197,7 @@ describe('The Statuses module', () => { const status = makeMockStatus({id: '1'}) const favorite = { - id: 2, + id: '2', type: 'favorite', in_reply_to_status_id: '1', // The API uses strings here... uri: 'tag:shitposter.club,2016-08-21:fave:3895:note:773501:2016-08-21T16:52:15+00:00', @@ -225,7 +225,7 @@ describe('The Statuses module', () => { } const ownFavorite = { - id: 3, + id: '3', type: 'favorite', in_reply_to_status_id: '1', // The API uses strings here... uri: 'tag:shitposter.club,2016-08-21:fave:3895:note:773501:2016-08-21T16:52:15+00:00', @@ -251,7 +251,7 @@ describe('The Statuses module', () => { mentionedStatus.uri = 'xxx' otherStatus.attentions = [user] - const deletion = makeMockStatus({id: 4, type: 'deletion'}) + const deletion = makeMockStatus({id: '4', type: 'deletion'}) deletion.text = 'Dolus deleted notice {{tag:gs.smuglo.li,2016-11-18:noticeId=1038007:objectType=note}}.' deletion.uri = 'xxx' @@ -260,8 +260,8 @@ describe('The Statuses module', () => { state, { notifications: [{ - from_profile: { id: 2 }, - id: 998, + from_profile: { id: '2' }, + id: '998', type: 'mention', status: otherStatus, action: otherStatus, @@ -274,8 +274,8 @@ describe('The Statuses module', () => { state, { notifications: [{ - from_profile: { id: 2 }, - id: 999, + from_profile: { id: '2' }, + id: '999', type: 'mention', status: mentionedStatus, action: mentionedStatus, diff --git a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js index e5882725..2eddd470 100644 --- a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js +++ b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js @@ -9,7 +9,7 @@ const makeMockStatusQvitter = (overrides = {}) => { external_url: 'https://ap.example/whatever', fave_num: 1, favorited: false, - id: 10335970, + id: '10335970', in_reply_to_ostatus_uri: null, in_reply_to_profileurl: null, in_reply_to_screen_name: null, @@ -20,7 +20,7 @@ const makeMockStatusQvitter = (overrides = {}) => { possibly_sensitive: false, repeat_num: 0, repeated: false, - statusnet_conversation_id: 16300488, + statusnet_conversation_id: '16300488', statusnet_html: '

haha benis

', summary: null, tags: [], @@ -45,7 +45,7 @@ const makeMockUserQvitter = (overrides = {}) => { following: true, follows_you: true, friends_count: 1, - id: 60717, + id: '60717', is_local: false, locked: false, name: 'Spurdo :ebin:', @@ -87,15 +87,15 @@ describe('QVitter preprocessing', () => { }) it('sets nsfw for statuses with the #nsfw tag', () => { - const safe = makeMockStatusQvitter({id: 1, text: 'Hello oniichan'}) - const nsfw = makeMockStatusQvitter({id: 1, text: 'Hello oniichan #nsfw'}) + const safe = makeMockStatusQvitter({id: '1', text: 'Hello oniichan'}) + const nsfw = makeMockStatusQvitter({id: '1', text: 'Hello oniichan #nsfw'}) expect(parseStatus(safe).nsfw).to.eq(false) expect(parseStatus(nsfw).nsfw).to.eq(true) }) it('leaves existing nsfw settings alone', () => { - const nsfw = makeMockStatusQvitter({id: 1, text: 'Hello oniichan #nsfw', nsfw: false}) + const nsfw = makeMockStatusQvitter({id: '1', text: 'Hello oniichan #nsfw', nsfw: false}) expect(parseStatus(nsfw).nsfw).to.eq(false) }) -- cgit v1.2.3-70-g09d2 From 1e61c8140b3921183f7721ec3e0db00e671a4410 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 17 Jan 2019 20:44:37 +0300 Subject: tests for the tests god! bugfixes for bugfixes throne! --- .../entity_normalizer/entity_normalizer.service.js | 12 +- .../entity_normalizer/entity_normalizer.spec.js | 209 ++++++++++++++++++--- 2 files changed, 198 insertions(+), 23 deletions(-) (limited to 'test/unit') diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 2c8f5b54..ca0f36db 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -122,6 +122,10 @@ export const parseStatus = (data) => { // Not exactly the same but works output.statusnet_conversation_id = data.id + + if (output.type === 'retweet') { + output.retweeted_status = parseStatus(data.reblog) + } } else { output.favorited = data.favorited output.fave_num = data.fave_num @@ -150,6 +154,10 @@ export const parseStatus = (data) => { output.in_reply_to_user_id = data.in_reply_to_account_id output.statusnet_conversation_id = data.statusnet_conversation_id + + if (output.type === 'retweet') { + output.retweeted_status = parseStatus(data.retweeted_status) + } } output.id = String(data.id) @@ -187,12 +195,12 @@ export const parseNotification = (data) => { output.type = mastoDict[data.type] || data.type output.seen = null // missing output.status = parseStatus(data.status) - output.action = null // missing + output.action = output.status // not sure output.from_profile = parseUser(data.account) } else { const parsedNotice = parseStatus(data.notice) output.type = data.ntype - output.seen = data.is_seen + output.seen = Boolean(data.is_seen) output.status = output.type === 'like' ? parseStatus(data.notice.favorited_status) : parsedNotice diff --git a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js index 2eddd470..bc127f79 100644 --- a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js +++ b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js @@ -1,4 +1,6 @@ import { parseStatus, parseUser, parseNotification } from '../../../../../src/services/entity_normalizer/entity_normalizer.service.js' +import mastoapidata from '../../../../fixtures/mastoapi.json' +import qvitterapidata from '../../../../fixtures/statuses.json' const makeMockStatusQvitter = (overrides = {}) => { return Object.assign({ @@ -64,39 +66,204 @@ const makeMockUserQvitter = (overrides = {}) => { }, overrides) } +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 @hj: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: + '@sampo 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', + visibility: 'public' + }, overrides) +} + +const makeMockNotificationQvitter = (overrides = {}) => { + return Object.assign({ + notice: makeMockStatusQvitter(), + ntype: 'follow', + from_profile: makeMockUserQvitter(), + is_seen: 0, + id: 123 + }, overrides) +} + parseNotification parseUser parseStatus makeMockStatusQvitter makeMockUserQvitter -describe('QVitter preprocessing', () => { - 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 - } +describe.only('API Entities normalizer', () => { + describe('statuses', () => { + describe('QVitter preprocessing', () => { + it('doesn\'t blow up', () => { + const parsed = qvitterapidata.map(parseStatus) + expect(parsed.length).to.eq(qvitterapidata.length) + }) - const mastoFav = { - uri: 'tag:mastodon.social,2016-11-27:objectId=73903:objectType=Favourite', - is_post_verb: false - } + 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 + } - expect(parseStatus(makeMockStatusQvitter(fav))).to.have.property('type', 'favorite') - expect(parseStatus(makeMockStatusQvitter(mastoFav))).to.have.property('type', 'favorite') - }) + 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', () => { + const safe = makeMockStatusQvitter({id: '1', text: 'Hello oniichan'}) + const nsfw = makeMockStatusQvitter({id: '1', text: 'Hello oniichan #nsfw'}) - it('sets nsfw for statuses with the #nsfw tag', () => { - const safe = makeMockStatusQvitter({id: '1', text: 'Hello oniichan'}) - const nsfw = makeMockStatusQvitter({id: '1', text: 'Hello oniichan #nsfw'}) + expect(parseStatus(safe).nsfw).to.eq(false) + expect(parseStatus(nsfw).nsfw).to.eq(true) + }) + + it('leaves existing nsfw settings alone', () => { + const nsfw = makeMockStatusQvitter({id: '1', text: 'Hello oniichan #nsfw', nsfw: false}) + + 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') + }) + }) + }) + // Statuses generally already contain some info regarding users and there's nearly 1:1 mapping, so very little to test + describe('users (MastoAPI)', () => { + it('sets correct is_local for users depending on their screen_name', () => { + const local = makeMockUserMasto({ acct: 'foo' }) + const remote = makeMockUserMasto({ acct: 'foo@bar.baz' }) - expect(parseStatus(safe).nsfw).to.eq(false) - expect(parseStatus(nsfw).nsfw).to.eq(true) + expect(parseUser(local)).to.have.property('is_local', true) + expect(parseUser(remote)).to.have.property('is_local', false) + }) }) - it('leaves existing nsfw settings alone', () => { - const nsfw = makeMockStatusQvitter({id: '1', text: 'Hello oniichan #nsfw', nsfw: false}) + // We currently use QvitterAPI notifications only, and especially due to MastoAPI lacking is_seen, support for MastoAPI + // is more of an afterthought + describe('notifications (QvitterAPI)', () => { + it('correctly normalizes data to FE\'s format', () => { + const notif = makeMockNotificationQvitter({ + id: 123, + notice: makeMockStatusQvitter({ id: 444 }), + from_profile: makeMockUserQvitter({ id: 'spurdo' }) + }) + expect(parseNotification(notif)).to.have.property('id', '123') + 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') + }) - expect(parseStatus(nsfw).nsfw).to.eq(false) + 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' }) + }) + expect(parseNotification(notif)).to.have.property('id', '123') + 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') + }) }) }) -- cgit v1.2.3-70-g09d2 From d405bfe6deb79b4079965c1118a734b96fc20a09 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 22 Jan 2019 19:58:59 +0300 Subject: update test names --- .../specs/services/entity_normalizer/entity_normalizer.spec.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'test/unit') diff --git a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js index bc127f79..703fecf1 100644 --- a/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js +++ b/test/unit/specs/services/entity_normalizer/entity_normalizer.spec.js @@ -149,8 +149,8 @@ parseStatus makeMockStatusQvitter makeMockUserQvitter -describe.only('API Entities normalizer', () => { - describe('statuses', () => { +describe('API Entities normalizer', () => { + describe('parseStatus', () => { describe('QVitter preprocessing', () => { it('doesn\'t blow up', () => { const parsed = qvitterapidata.map(parseStatus) @@ -220,8 +220,9 @@ describe.only('API Entities normalizer', () => { }) }) }) + // Statuses generally already contain some info regarding users and there's nearly 1:1 mapping, so very little to test - describe('users (MastoAPI)', () => { + describe('parseUsers (MastoAPI)', () => { it('sets correct is_local for users depending on their screen_name', () => { const local = makeMockUserMasto({ acct: 'foo' }) const remote = makeMockUserMasto({ acct: 'foo@bar.baz' }) @@ -233,7 +234,7 @@ describe.only('API Entities normalizer', () => { // We currently use QvitterAPI notifications only, and especially due to MastoAPI lacking is_seen, support for MastoAPI // is more of an afterthought - describe('notifications (QvitterAPI)', () => { + describe('parseNotifications (QvitterAPI)', () => { it('correctly normalizes data to FE\'s format', () => { const notif = makeMockNotificationQvitter({ id: 123, -- cgit v1.2.3-70-g09d2