Merge branch 'mastoapi/user-stuff' into 'develop'

Transition to MastoAPI: user data

See merge request pleroma/pleroma-fe!655
This commit is contained in:
HJ 2019-03-15 13:14:41 +00:00
commit 9364964b01
14 changed files with 167 additions and 107 deletions

View File

@ -9,7 +9,7 @@ const BlockCard = {
}, },
computed: { computed: {
user () { user () {
return this.$store.getters.userById(this.userId) return this.$store.getters.findUser(this.userId)
}, },
blocked () { blocked () {
return this.user.statusnet_blocking return this.user.statusnet_blocking

View File

@ -9,7 +9,7 @@ const MuteCard = {
}, },
computed: { computed: {
user () { user () {
return this.$store.getters.userById(this.userId) return this.$store.getters.findUser(this.userId)
}, },
muted () { muted () {
return this.user.muted return this.user.muted

View File

@ -145,11 +145,11 @@ const Status = {
return !!(this.status.in_reply_to_status_id && this.status.in_reply_to_user_id) return !!(this.status.in_reply_to_status_id && this.status.in_reply_to_user_id)
}, },
replyToName () { replyToName () {
const user = this.$store.state.users.usersObject[this.status.in_reply_to_user_id] if (this.status.in_reply_to_screen_name) {
if (user) {
return user.screen_name
} else {
return this.status.in_reply_to_screen_name return this.status.in_reply_to_screen_name
} else {
const user = this.$store.getters.findUser(this.status.in_reply_to_user_id)
return user && user.screen_name
} }
}, },
hideReply () { hideReply () {

View File

@ -23,6 +23,11 @@ const UserAvatar = {
imageLoadError () { imageLoadError () {
this.showPlaceholder = true this.showPlaceholder = true
} }
},
watch: {
src () {
this.showPlaceholder = false
}
} }
} }

View File

@ -15,6 +15,9 @@ export default {
betterShadow: this.$store.state.interface.browserSupport.cssFilter betterShadow: this.$store.state.interface.browserSupport.cssFilter
} }
}, },
created () {
this.$store.dispatch('fetchUserRelationship', this.user.id)
},
computed: { computed: {
classes () { classes () {
return [{ return [{

View File

@ -9,7 +9,7 @@ import withList from '../../hocs/with_list/with_list'
const FollowerList = compose( const FollowerList = compose(
withLoadMore({ withLoadMore({
fetch: (props, $store) => $store.dispatch('addFollowers', props.userId), fetch: (props, $store) => $store.dispatch('addFollowers', props.userId),
select: (props, $store) => get($store.getters.userById(props.userId), 'followers', []), select: (props, $store) => get($store.getters.findUser(props.userId), 'followers', []),
destory: (props, $store) => $store.dispatch('clearFollowers', props.userId), destory: (props, $store) => $store.dispatch('clearFollowers', props.userId),
childPropName: 'entries', childPropName: 'entries',
additionalPropNames: ['userId'] additionalPropNames: ['userId']
@ -20,7 +20,7 @@ const FollowerList = compose(
const FriendList = compose( const FriendList = compose(
withLoadMore({ withLoadMore({
fetch: (props, $store) => $store.dispatch('addFriends', props.userId), fetch: (props, $store) => $store.dispatch('addFriends', props.userId),
select: (props, $store) => get($store.getters.userById(props.userId), 'friends', []), select: (props, $store) => get($store.getters.findUser(props.userId), 'friends', []),
destory: (props, $store) => $store.dispatch('clearFriends', props.userId), destory: (props, $store) => $store.dispatch('clearFriends', props.userId),
childPropName: 'entries', childPropName: 'entries',
additionalPropNames: ['userId'] additionalPropNames: ['userId']
@ -31,28 +31,16 @@ const FriendList = compose(
const UserProfile = { const UserProfile = {
data () { data () {
return { return {
error: false error: false,
fetchedUserId: null
} }
}, },
created () { created () {
this.$store.commit('clearTimeline', { timeline: 'user' })
this.$store.commit('clearTimeline', { timeline: 'favorites' })
this.$store.commit('clearTimeline', { timeline: 'media' })
this.$store.dispatch('startFetching', { timeline: 'user', userId: this.fetchBy })
this.$store.dispatch('startFetching', { timeline: 'media', userId: this.fetchBy })
this.startFetchFavorites()
if (!this.user.id) { if (!this.user.id) {
this.$store.dispatch('fetchUser', this.fetchBy) this.fetchUserId()
.catch((reason) => { .then(() => this.startUp())
const errorMessage = get(reason, 'error.error')
if (errorMessage === 'No user with such user_id') { // Known error
this.error = this.$t('user_profile.profile_does_not_exist')
} else if (errorMessage) {
this.error = errorMessage
} else { } else {
this.error = this.$t('user_profile.profile_loading_error') this.startUp()
}
})
} }
}, },
destroyed () { destroyed () {
@ -69,7 +57,7 @@ const UserProfile = {
return this.$store.state.statuses.timelines.media return this.$store.state.statuses.timelines.media
}, },
userId () { userId () {
return this.$route.params.id || this.user.id return this.$route.params.id || this.user.id || this.fetchedUserId
}, },
userName () { userName () {
return this.$route.params.name || this.user.screen_name return this.$route.params.name || this.user.screen_name
@ -79,10 +67,9 @@ const UserProfile = {
this.userId === this.$store.state.users.currentUser.id this.userId === this.$store.state.users.currentUser.id
}, },
userInStore () { userInStore () {
if (this.isExternal) { const routeParams = this.$route.params
return this.$store.getters.userById(this.userId) // This needs fetchedUserId so that computed will be refreshed when user is fetched
} return this.$store.getters.findUser(this.fetchedUserId || routeParams.name || routeParams.id)
return this.$store.getters.userByName(this.userName)
}, },
user () { user () {
if (this.timeline.statuses[0]) { if (this.timeline.statuses[0]) {
@ -93,9 +80,6 @@ const UserProfile = {
} }
return {} return {}
}, },
fetchBy () {
return this.isExternal ? this.userId : this.userName
},
isExternal () { isExternal () {
return this.$route.name === 'external-user-profile' return this.$route.name === 'external-user-profile'
}, },
@ -109,14 +93,38 @@ const UserProfile = {
methods: { methods: {
startFetchFavorites () { startFetchFavorites () {
if (this.isUs) { if (this.isUs) {
this.$store.dispatch('startFetching', { timeline: 'favorites', userId: this.fetchBy }) this.$store.dispatch('startFetching', { timeline: 'favorites', userId: this.userId })
} }
}, },
fetchUserId () {
let fetchPromise
if (this.userId && !this.$route.params.name) {
fetchPromise = this.$store.dispatch('fetchUser', this.userId)
} else {
fetchPromise = this.$store.dispatch('fetchUser', this.userName)
.then(({ id }) => {
this.fetchedUserId = id
})
}
return fetchPromise
.catch((reason) => {
const errorMessage = get(reason, 'error.error')
if (errorMessage === 'No user with such user_id') { // Known error
this.error = this.$t('user_profile.profile_does_not_exist')
} else if (errorMessage) {
this.error = errorMessage
} else {
this.error = this.$t('user_profile.profile_loading_error')
}
})
.then(() => this.startUp())
},
startUp () { startUp () {
this.$store.dispatch('startFetching', { timeline: 'user', userId: this.fetchBy }) if (this.userId) {
this.$store.dispatch('startFetching', { timeline: 'media', userId: this.fetchBy }) this.$store.dispatch('startFetching', { timeline: 'user', userId: this.userId })
this.$store.dispatch('startFetching', { timeline: 'media', userId: this.userId })
this.startFetchFavorites() this.startFetchFavorites()
}
}, },
cleanUp () { cleanUp () {
this.$store.dispatch('stopFetching', 'user') this.$store.dispatch('stopFetching', 'user')
@ -128,19 +136,19 @@ const UserProfile = {
} }
}, },
watch: { watch: {
userName () { // userId can be undefined if we don't know it yet
if (this.isExternal) { userId (newVal) {
return if (newVal) {
}
this.cleanUp() this.cleanUp()
this.startUp() this.startUp()
}
}, },
userId () { userName () {
if (!this.isExternal) { if (this.$route.params.name) {
return this.fetchUserId()
}
this.cleanUp() this.cleanUp()
this.startUp() this.startUp()
}
}, },
$route () { $route () {
this.$refs.tabSwitcher.activateTab(0)() this.$refs.tabSwitcher.activateTab(0)()

View File

@ -11,7 +11,7 @@
:title="$t('user_profile.timeline_title')" :title="$t('user_profile.timeline_title')"
:timeline="timeline" :timeline="timeline"
:timeline-name="'user'" :timeline-name="'user'"
:user-id="fetchBy" :user-id="userId"
/> />
<div :label="$t('user_card.followees')" v-if="followsTabVisible" :disabled="!user.friends_count"> <div :label="$t('user_card.followees')" v-if="followsTabVisible" :disabled="!user.friends_count">
<FriendList :userId="userId" /> <FriendList :userId="userId" />
@ -25,7 +25,7 @@
:embedded="true" :title="$t('user_card.media')" :embedded="true" :title="$t('user_card.media')"
timeline-name="media" timeline-name="media"
:timeline="media" :timeline="media"
:user-id="fetchBy" :user-id="userId"
/> />
<Timeline <Timeline
v-if="isUs" v-if="isUs"

View File

@ -1,4 +1,4 @@
import { remove, slice, each, find, maxBy, minBy, merge, first, last, isArray } from 'lodash' import { remove, slice, each, find, maxBy, minBy, merge, first, last, isArray, omitBy } from 'lodash'
import apiService from '../services/api/api.service.js' import apiService from '../services/api/api.service.js'
// import parse from '../services/status_parser/status_parser.js' // import parse from '../services/status_parser/status_parser.js'
@ -72,7 +72,9 @@ const mergeOrAdd = (arr, obj, item) => {
if (oldItem) { if (oldItem) {
// We already have this, so only merge the new info. // We already have this, so only merge the new info.
merge(oldItem, item) // We ignore null values to avoid overwriting existing properties with missing data
// we also skip 'user' because that is handled by users module
merge(oldItem, omitBy(item, (v, k) => v === null || k === 'user'))
// Reactivity fix. // Reactivity fix.
oldItem.attachments.splice(oldItem.attachments.length) oldItem.attachments.splice(oldItem.attachments.length)
return {item: oldItem, new: false} return {item: oldItem, new: false}

View File

@ -18,7 +18,7 @@ export const mergeOrAdd = (arr, obj, item) => {
arr.push(item) arr.push(item)
obj[item.id] = item obj[item.id] = item
if (item.screen_name && !item.screen_name.includes('@')) { if (item.screen_name && !item.screen_name.includes('@')) {
obj[item.screen_name] = item obj[item.screen_name.toLowerCase()] = item
} }
return { item, new: true } return { item, new: true }
} }
@ -91,6 +91,17 @@ export const mutations = {
addNewUsers (state, users) { addNewUsers (state, users) {
each(users, (user) => mergeOrAdd(state.users, state.usersObject, user)) each(users, (user) => mergeOrAdd(state.users, state.usersObject, user))
}, },
updateUserRelationship (state, relationships) {
relationships.forEach((relationship) => {
const user = state.usersObject[relationship.id]
if (user) {
user.follows_you = relationship.followed_by
user.following = relationship.following
user.muted = relationship.muting
user.statusnet_blocking = relationship.blocking
}
})
},
saveBlocks (state, blockIds) { saveBlocks (state, blockIds) {
state.currentUser.blockIds = blockIds state.currentUser.blockIds = blockIds
}, },
@ -122,12 +133,14 @@ export const mutations = {
} }
export const getters = { export const getters = {
userById: state => id => findUser: state => query => {
state.users.find(user => user.id === id), const result = state.usersObject[query]
userByName: state => name => // In case it's a screen_name, we can try searching case-insensitive
state.users.find(user => user.screen_name && if (!result && typeof query === 'string') {
(user.screen_name.toLowerCase() === name.toLowerCase()) return state.usersObject[query.toLowerCase()]
) }
return result
}
} }
export const defaultState = { export const defaultState = {
@ -147,7 +160,14 @@ const users = {
actions: { actions: {
fetchUser (store, id) { fetchUser (store, id) {
return store.rootState.api.backendInteractor.fetchUser({ id }) return store.rootState.api.backendInteractor.fetchUser({ id })
.then((user) => store.commit('addNewUsers', [user])) .then((user) => {
store.commit('addNewUsers', [user])
return user
})
},
fetchUserRelationship (store, id) {
return store.rootState.api.backendInteractor.fetchUserRelationship({ id })
.then((relationships) => store.commit('updateUserRelationship', relationships))
}, },
fetchBlocks (store) { fetchBlocks (store) {
return store.rootState.api.backendInteractor.fetchBlocks() return store.rootState.api.backendInteractor.fetchBlocks()

View File

@ -28,12 +28,10 @@ const BG_UPDATE_URL = '/api/qvitter/update_background_image.json'
const BANNER_UPDATE_URL = '/api/account/update_profile_banner.json' const BANNER_UPDATE_URL = '/api/account/update_profile_banner.json'
const PROFILE_UPDATE_URL = '/api/account/update_profile.json' const PROFILE_UPDATE_URL = '/api/account/update_profile.json'
const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json' const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json'
const QVITTER_USER_TIMELINE_URL = '/api/qvitter/statuses/user_timeline.json'
const QVITTER_USER_NOTIFICATIONS_URL = '/api/qvitter/statuses/notifications.json' const QVITTER_USER_NOTIFICATIONS_URL = '/api/qvitter/statuses/notifications.json'
const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json' const QVITTER_USER_NOTIFICATIONS_READ_URL = '/api/qvitter/statuses/notifications/read.json'
const BLOCKING_URL = '/api/blocks/create.json' const BLOCKING_URL = '/api/blocks/create.json'
const UNBLOCKING_URL = '/api/blocks/destroy.json' const UNBLOCKING_URL = '/api/blocks/destroy.json'
const USER_URL = '/api/users/show.json'
const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import' const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import'
const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account' const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account'
const CHANGE_PASSWORD_URL = '/api/pleroma/change_password' const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
@ -43,6 +41,9 @@ const DENY_USER_URL = '/api/pleroma/friendships/deny'
const SUGGESTIONS_URL = '/api/v1/suggestions' const SUGGESTIONS_URL = '/api/v1/suggestions'
const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites' const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites'
const MASTODON_USER_URL = '/api/v1/accounts'
const MASTODON_USER_RELATIONSHIPS_URL = '/api/v1/accounts/relationships'
const MASTODON_USER_TIMELINE_URL = id => `/api/v1/accounts/${id}/statuses`
import { each, map } from 'lodash' import { each, map } from 'lodash'
import { parseStatus, parseUser, parseNotification } from '../entity_normalizer/entity_normalizer.service.js' import { parseStatus, parseUser, parseNotification } from '../entity_normalizer/entity_normalizer.service.js'
@ -243,7 +244,7 @@ const denyUser = ({id, credentials}) => {
} }
const fetchUser = ({id, credentials}) => { const fetchUser = ({id, credentials}) => {
let url = `${USER_URL}?user_id=${id}` let url = `${MASTODON_USER_URL}/${id}`
return fetch(url, { headers: authHeaders(credentials) }) return fetch(url, { headers: authHeaders(credentials) })
.then((response) => { .then((response) => {
return new Promise((resolve, reject) => response.json() return new Promise((resolve, reject) => response.json()
@ -257,6 +258,20 @@ const fetchUser = ({id, credentials}) => {
.then((data) => parseUser(data)) .then((data) => parseUser(data))
} }
const fetchUserRelationship = ({id, credentials}) => {
let url = `${MASTODON_USER_RELATIONSHIPS_URL}/?id=${id}`
return fetch(url, { headers: authHeaders(credentials) })
.then((response) => {
return new Promise((resolve, reject) => response.json()
.then((json) => {
if (!response.ok) {
return reject(new StatusCodeError(response.status, json, { url }, response))
}
return resolve(json)
}))
})
}
const fetchFriends = ({id, page, credentials}) => { const fetchFriends = ({id, page, credentials}) => {
let url = `${FRIENDS_URL}?user_id=${id}` let url = `${FRIENDS_URL}?user_id=${id}`
if (page) { if (page) {
@ -347,8 +362,8 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false, use
dms: DM_TIMELINE_URL, dms: DM_TIMELINE_URL,
notifications: QVITTER_USER_NOTIFICATIONS_URL, notifications: QVITTER_USER_NOTIFICATIONS_URL,
'publicAndExternal': PUBLIC_AND_EXTERNAL_TIMELINE_URL, 'publicAndExternal': PUBLIC_AND_EXTERNAL_TIMELINE_URL,
user: QVITTER_USER_TIMELINE_URL, user: MASTODON_USER_TIMELINE_URL,
media: QVITTER_USER_TIMELINE_URL, media: MASTODON_USER_TIMELINE_URL,
favorites: MASTODON_USER_FAVORITES_TIMELINE_URL, favorites: MASTODON_USER_FAVORITES_TIMELINE_URL,
tag: TAG_TIMELINE_URL tag: TAG_TIMELINE_URL
} }
@ -357,15 +372,16 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false, use
let url = timelineUrls[timeline] let url = timelineUrls[timeline]
if (timeline === 'user' || timeline === 'media') {
url = url(userId)
}
if (since) { if (since) {
params.push(['since_id', since]) params.push(['since_id', since])
} }
if (until) { if (until) {
params.push(['max_id', until]) params.push(['max_id', until])
} }
if (userId) {
params.push(['user_id', userId])
}
if (tag) { if (tag) {
url += `/${tag}.json` url += `/${tag}.json`
} }
@ -588,6 +604,7 @@ const apiService = {
blockUser, blockUser,
unblockUser, unblockUser,
fetchUser, fetchUser,
fetchUserRelationship,
favorite, favorite,
unfavorite, unfavorite,
retweet, retweet,

View File

@ -30,6 +30,10 @@ const backendInteractorService = (credentials) => {
return apiService.fetchUser({id, credentials}) return apiService.fetchUser({id, credentials})
} }
const fetchUserRelationship = ({id}) => {
return apiService.fetchUserRelationship({id, credentials})
}
const followUser = (id) => { const followUser = (id) => {
return apiService.followUser({credentials, id}) return apiService.followUser({credentials, id})
} }
@ -92,6 +96,7 @@ const backendInteractorService = (credentials) => {
blockUser, blockUser,
unblockUser, unblockUser,
fetchUser, fetchUser,
fetchUserRelationship,
fetchAllFollowing, fetchAllFollowing,
verifyCredentials: apiService.verifyCredentials, verifyCredentials: apiService.verifyCredentials,
startFetching, startFetching,

View File

@ -39,10 +39,10 @@ export const parseUser = (data) => {
return output return output
} }
output.name = null // missing // output.name = ??? missing
output.name_html = data.display_name output.name_html = data.display_name
output.description = null // missing // output.description = ??? missing
output.description_html = data.note output.description_html = data.note
// Utilize avatar_static for gif avatars? // Utilize avatar_static for gif avatars?
@ -59,10 +59,14 @@ export const parseUser = (data) => {
output.statusnet_profile_url = data.url output.statusnet_profile_url = data.url
if (data.pleroma) { if (data.pleroma) {
const pleroma = data.pleroma const relationship = data.pleroma.relationship
output.follows_you = pleroma.follows_you
output.statusnet_blocking = pleroma.statusnet_blocking if (relationship) {
output.muted = pleroma.muted output.follows_you = relationship.followed_by
output.following = relationship.following
output.statusnet_blocking = relationship.blocking
output.muted = relationship.muting
}
} }
// Missing, trying to recover // Missing, trying to recover
@ -83,7 +87,7 @@ export const parseUser = (data) => {
output.friends_count = data.friends_count output.friends_count = data.friends_count
output.bot = null // missing // output.bot = ??? missing
output.statusnet_profile_url = data.statusnet_profile_url output.statusnet_profile_url = data.statusnet_profile_url
@ -134,7 +138,7 @@ const parseAttachment = (data) => {
output.meta = data.meta // not present in BE yet output.meta = data.meta // not present in BE yet
} else { } else {
output.mimetype = data.mimetype output.mimetype = data.mimetype
output.meta = null // missing // output.meta = ??? missing
} }
output.url = data.url output.url = data.url
@ -166,7 +170,7 @@ export const parseStatus = (data) => {
output.in_reply_to_user_id = data.in_reply_to_account_id output.in_reply_to_user_id = data.in_reply_to_account_id
// Missing!! fix in UI? // Missing!! fix in UI?
output.in_reply_to_screen_name = null // output.in_reply_to_screen_name = ???
// Not exactly the same but works // Not exactly the same but works
output.statusnet_conversation_id = data.id output.statusnet_conversation_id = data.id
@ -179,8 +183,7 @@ export const parseStatus = (data) => {
output.summary_html = data.spoiler_text output.summary_html = data.spoiler_text
output.external_url = data.url output.external_url = data.url
// FIXME missing!! // output.is_local = ??? missing
output.is_local = false
} else { } else {
output.favorited = data.favorited output.favorited = data.favorited
output.fave_num = data.fave_num output.fave_num = data.fave_num
@ -259,7 +262,7 @@ export const parseNotification = (data) => {
if (masto) { if (masto) {
output.type = mastoDict[data.type] || data.type output.type = mastoDict[data.type] || data.type
output.seen = null // missing // output.seen = ??? missing
output.status = parseStatus(data.status) output.status = parseStatus(data.status)
output.action = output.status // not sure output.action = output.status // not sure
output.from_profile = parseUser(data.account) output.from_profile = parseUser(data.account)

View File

@ -12,9 +12,13 @@ const mutations = {
setError: () => {} setError: () => {}
} }
const actions = {
fetchUser: () => {},
fetchUserByScreenName: () => {}
}
const testGetters = { const testGetters = {
userByName: state => getters.userByName(state.users), findUser: state => getters.findUser(state.users)
userById: state => getters.userById(state.users)
} }
const localUser = { const localUser = {
@ -31,6 +35,7 @@ const extUser = {
const externalProfileStore = new Vuex.Store({ const externalProfileStore = new Vuex.Store({
mutations, mutations,
actions,
getters: testGetters, getters: testGetters,
state: { state: {
api: { api: {
@ -89,7 +94,7 @@ const externalProfileStore = new Vuex.Store({
currentUser: { currentUser: {
credentials: '' credentials: ''
}, },
usersObject: [extUser], usersObject: { 100: extUser },
users: [extUser] users: [extUser]
} }
} }
@ -97,6 +102,7 @@ const externalProfileStore = new Vuex.Store({
const localProfileStore = new Vuex.Store({ const localProfileStore = new Vuex.Store({
mutations, mutations,
actions,
getters: testGetters, getters: testGetters,
state: { state: {
api: { api: {
@ -155,7 +161,7 @@ const localProfileStore = new Vuex.Store({
currentUser: { currentUser: {
credentials: '' credentials: ''
}, },
usersObject: [localUser], usersObject: { 100: localUser, 'testuser': localUser },
users: [localUser] users: [localUser]
} }
} }

View File

@ -34,40 +34,31 @@ describe('The users module', () => {
}) })
}) })
describe('getUserByName', () => { describe('findUser', () => {
it('returns user with matching screen_name', () => { it('returns user with matching screen_name', () => {
const user = { screen_name: 'Guy', id: '1' }
const state = { const state = {
users: [ usersObject: {
{ screen_name: 'Guy', id: '1' } 1: user,
] guy: user
}
} }
const name = 'Guy' 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) expect(getters.findUser(state)(name)).to.eql(expected)
}) })
it('returns user with matching screen_name with different case', () => {
const state = {
users: [
{ screen_name: 'guy', id: '1' }
]
}
const name = 'Guy'
const expected = { screen_name: 'guy', id: '1' }
expect(getters.userByName(state)(name)).to.eql(expected)
})
})
describe('getUserById', () => {
it('returns user with matching id', () => { it('returns user with matching id', () => {
const user = { screen_name: 'Guy', id: '1' }
const state = { const state = {
users: [ usersObject: {
{ screen_name: 'Guy', id: '1' } 1: user,
] guy: user
}
} }
const id = '1' const id = '1'
const expected = { screen_name: 'Guy', id: '1' } const expected = { screen_name: 'Guy', id: '1' }
expect(getters.userById(state)(id)).to.eql(expected) expect(getters.findUser(state)(id)).to.eql(expected)
}) })
}) })
}) })