fix: fix bell notifications, add tests

misskey-voters
Nolan Lawson 2022-04-28 08:18:50 -07:00
rodzic 2e9afd711f
commit c67be9acc2
21 zmienionych plików z 177 dodań i 152 usunięć

Wyświetl plik

@ -1,6 +1,7 @@
export default [
{ id: 'pinafore-logo', src: 'src/static/sailboat.svg', inline: true },
{ id: 'fa-bell', src: 'src/thirdparty/font-awesome-svg-png/white/svg/bell.svg', inline: true },
{ id: 'fa-bell-o', src: 'src/thirdparty/font-awesome-svg-png/white/svg/bell-o.svg' },
{ id: 'fa-users', src: 'src/thirdparty/font-awesome-svg-png/white/svg/users.svg', inline: true },
{ id: 'fa-globe', src: 'src/thirdparty/font-awesome-svg-png/white/svg/globe.svg' },
{ id: 'fa-gear', src: 'src/thirdparty/font-awesome-svg-png/white/svg/gear.svg', inline: true },
@ -22,6 +23,7 @@ export default [
{ id: 'fa-user-plus', src: 'src/thirdparty/font-awesome-svg-png/white/svg/user-plus.svg' },
{ id: 'fa-external-link', src: 'src/thirdparty/font-awesome-svg-png/white/svg/external-link.svg' },
{ id: 'fa-search', src: 'src/thirdparty/font-awesome-svg-png/white/svg/search.svg', inline: true },
{ id: 'fa-comment', src: 'src/thirdparty/font-awesome-svg-png/white/svg/comment.svg' },
{ id: 'fa-comments', src: 'src/thirdparty/font-awesome-svg-png/white/svg/comments.svg', inline: true },
{ id: 'fa-paperclip', src: 'src/thirdparty/font-awesome-svg-png/white/svg/paperclip.svg' },
{ id: 'fa-thumb-tack', src: 'src/thirdparty/font-awesome-svg-png/white/svg/thumb-tack.svg' },

Wyświetl plik

@ -309,10 +309,10 @@ export default {
true {(follow requested)}
other {}
}`,
notifyLabel: `Subscribe`,
denotifyLabel: `Unsubscribe`,
notify: 'Subscribe to {account}',
denotify: 'Unsubscribe from {account}',
subscribedAccount: 'Subscribed to account',
unsubscribedAccount: 'Unsubscribed to account',
unsubscribedAccount: 'Unsubscribed from account',
unblock: 'Unblock',
nameAndFollowing: 'Name and following',
clickToSeeAvatar: 'Click to see avatar',
@ -474,6 +474,7 @@ export default {
newFollowers: 'New followers',
reblogs: 'Boosts',
pollResults: 'Poll results',
subscriptions: 'Subscribed toots',
needToReauthenticate: 'You need to reauthenticate in order to enable push notification. Log out of {instance}?',
failedToUpdatePush: 'Failed to update push notification settings: {error}',
// Themes
@ -508,6 +509,7 @@ export default {
rebloggedYou: 'boosted your toot',
favoritedYou: 'favorited your toot',
followedYou: 'followed you',
posted: 'posted',
pollYouCreatedEnded: 'A poll you created has ended',
pollYouVotedEnded: 'A poll you voted on has ended',
reblogged: 'boosted',

Wyświetl plik

@ -4,7 +4,7 @@ import { toast } from '../_components/toast/toast.js'
import { updateLocalRelationship } from './accounts.js'
import { formatIntl } from '../_utils/formatIntl.js'
export async function setAccountNotify (accountId, notify, toastOnSuccess) {
export async function setAccountNotified (accountId, notify, toastOnSuccess) {
const { currentInstance, accessToken } = store.get()
try {
let relationship
@ -15,11 +15,11 @@ export async function setAccountNotify (accountId, notify, toastOnSuccess) {
}
await updateLocalRelationship(currentInstance, accountId, relationship)
if (toastOnSuccess) {
/* no await */ toast.say(follow ? 'intl.subscribedAccount' : 'intl.unsubscribedAccount')
/* no await */ toast.say(notify ? 'intl.subscribedAccount' : 'intl.unsubscribedAccount')
}
} catch (e) {
console.error(e)
/* no await */ toast.say(follow
/* no await */ toast.say(notify
? formatIntl('intl.unableToSubscribe', { error: (e.message || '') })
: formatIntl('intl.unableToUnsubscribe', { error: (e.message || '') })
)

Wyświetl plik

@ -4,13 +4,13 @@ import { auth, basename } from './utils.js'
export async function notifyAccount (instanceName, accessToken, accountId) {
const url = `${basename(instanceName)}/api/v1/accounts/${accountId}/follow`
return post(url, {
"notify": true,
notify: true
}, auth(accessToken), { timeout: WRITE_TIMEOUT })
}
export async function denotifyAccount (instanceName, accessToken, accountId) {
const url = `${basename(instanceName)}/api/v1/accounts/${accountId}/follow`
return post(url, {
"notify": false
notify: false
}, auth(accessToken), { timeout: WRITE_TIMEOUT })
}

Wyświetl plik

@ -23,6 +23,7 @@ import { composeNewStatusMentioning } from '../../../_actions/mention.js'
import { toggleMute } from '../../../_actions/toggleMute.js'
import { reportStatusOrAccount } from '../../../_actions/report.js'
import { formatIntl } from '../../../_utils/formatIntl.js'
import { setAccountNotified } from '../../../_actions/setAccountNotified.js'
export default {
oncreate,
@ -39,6 +40,7 @@ export default {
username: ({ account }) => account.username,
muting: ({ relationship }) => relationship && relationship.muting,
blocking: ({ relationship }) => relationship && relationship.blocking,
notifying: ({ relationship }) => relationship && relationship.notifying,
followLabel: ({ following, followRequested, account, username }) => {
if (typeof following === 'undefined' || !account) {
return ''
@ -86,7 +88,7 @@ export default {
blockLabel, blocking, blockIcon, muteLabel, muteIcon,
followLabel, followIcon, following, followRequested,
accountId, verifyCredentialsId, username, isUser, showReblogsLabel,
domain, blockDomainLabel, reportLabel
domain, blockDomainLabel, reportLabel, notifying
}) => ([
!isUser && {
key: 'mention',
@ -98,6 +100,16 @@ export default {
label: followLabel,
icon: followIcon
},
!isUser && following && notifying === false && { // notifying could be undefined for old servers
key: 'notify',
label: formatIntl('intl.notify', { account: `@${username}` }),
icon: '#fa-bell'
},
!isUser && following && notifying === true && { // notifying could be undefined for old servers
key: 'denotify',
label: formatIntl('intl.denotify', { account: `@${username}` }),
icon: '#fa-bell-o'
},
!isUser && {
key: 'block',
label: blockLabel,
@ -151,6 +163,10 @@ export default {
return this.onCopyClicked()
case 'report':
return this.onReport()
case 'notify':
return this.onNotifyClicked()
case 'denotify':
return this.onDenotifyClicked()
}
},
async onMentionClicked () {
@ -193,6 +209,16 @@ export default {
const { account } = this.get()
this.close()
await reportStatusOrAccount({ account })
},
async onNotifyClicked () {
const { accountId } = this.get()
this.close()
await setAccountNotified(accountId, /* notify */ true, /* toastOnSuccess */ true)
},
async onDenotifyClicked () {
const { accountId } = this.get()
this.close()
await setAccountNotified(accountId, /* notify */ false, /* toastOnSuccess */ true)
}
},
components: {

Wyświetl plik

@ -26,6 +26,7 @@ import { shareStatus } from '../../../_actions/share.js'
import { toggleMute } from '../../../_actions/toggleMute.js'
import { reportStatusOrAccount } from '../../../_actions/report.js'
import { formatIntl } from '../../../_utils/formatIntl.js'
import { setAccountNotified } from '../../../_actions/setAccountNotified.js'
export default {
oncreate,
@ -53,6 +54,7 @@ export default {
username: ({ account }) => account.username,
muting: ({ relationship }) => relationship.muting,
blocking: ({ relationship }) => relationship.blocking,
notifying: ({ relationship }) => relationship && relationship.notifying,
followLabel: ({ following, followRequested, account, username }) => {
if (typeof following === 'undefined' || !account) {
return ''
@ -96,7 +98,8 @@ export default {
items: ({
blockLabel, blocking, blockIcon, muteLabel, muteIcon, followLabel, followIcon,
following, followRequested, pinLabel, isUser, visibility, mentionsUser, mutingConversation,
muteConversationLabel, muteConversationIcon, supportsWebShare, isPublicOrUnlisted, bookmarkLabel
muteConversationLabel, muteConversationIcon, supportsWebShare, isPublicOrUnlisted, bookmarkLabel,
username, notifying
}) => ([
isUser && {
key: 'delete',
@ -113,6 +116,16 @@ export default {
label: followLabel,
icon: followIcon
},
!isUser && following && notifying === false && { // notifying could be undefined for old servers
key: 'notify',
label: formatIntl('intl.notify', { account: `@${username}` }),
icon: '#fa-bell'
},
!isUser && following && notifying === true && { // notifying could be undefined for old servers
key: 'denotify',
label: formatIntl('intl.denotify', { account: `@${username}` }),
icon: '#fa-bell-o'
},
!isUser && {
key: 'block',
label: blockLabel,
@ -187,6 +200,10 @@ export default {
return this.onReport()
case 'bookmark':
return this.onBookmark()
case 'notify':
return this.onNotifyClicked()
case 'denotify':
return this.onDenotifyClicked()
}
},
async onDeleteClicked () {
@ -244,6 +261,16 @@ export default {
const { status } = this.get()
this.close()
await setStatusBookmarkedOrUnbookmarked(status.id, !status.bookmarked)
},
async onNotifyClicked () {
const { accountId } = this.get()
this.close()
await setAccountNotified(accountId, /* notify */ true, /* toastOnSuccess */ true)
},
async onDenotifyClicked () {
const { accountId } = this.get()
this.close()
await setAccountNotified(accountId, /* notify */ false, /* toastOnSuccess */ true)
}
}
}

Wyświetl plik

@ -8,7 +8,6 @@
<div class="account-profile-grid-wrapper">
<div class="account-profile-grid">
<AccountProfileHeader {account} {relationship} {verifyCredentials} />
<AccountProfileNotify {account} {relationship} {verifyCredentials} />
<AccountProfileFollow {account} {relationship} {verifyCredentials} />
<AccountProfileNote {account} />
<AccountProfileMeta {account} />
@ -38,7 +37,7 @@
display: grid;
grid-template-areas: "avatar name label followed-by follow"
"avatar username username username follow"
"avatar note note note notify"
"avatar note note note follow"
"meta meta meta meta meta"
"details details details details details";
grid-template-columns: min-content auto 1fr 1fr min-content;
@ -72,7 +71,7 @@
grid-template-areas: "avatar name follow"
"avatar label follow"
"avatar username follow"
"avatar followed-by notify"
"avatar followed-by follow"
"note note note"
"meta meta meta"
"details details details";
@ -98,7 +97,6 @@
"username username"
"followed-by followed-by"
"follow follow"
"notify notify"
"note note"
"meta meta"
"details details";
@ -110,7 +108,6 @@
</style>
<script>
import AccountProfileHeader from './AccountProfileHeader.html'
import AccountProfileNotify from './AccountProfileNotify.html'
import AccountProfileFollow from './AccountProfileFollow.html'
import AccountProfileNote from './AccountProfileNote.html'
import AccountProfileMeta from './AccountProfileMeta.html'
@ -147,7 +144,6 @@
AccountProfileHeader,
AccountProfileFollow,
AccountProfileNote,
AccountProfileNotify,
AccountProfileMeta,
AccountProfileDetails,
AccountProfileMovedBanner,

Wyświetl plik

@ -1,92 +0,0 @@
<div class="account-profile-notify {shown ? 'shown' : ''}">
<!--
The bell notification button (Mastodon 3.3+)
Shows if we're getting notifications or not.
It is not possible to turn on notifications for accounts you don't follow.
Also the instance can just have no support for this feature.
-->
<IconButton
className="account-profile-notify-icon-button"
{label}
pressedLabel="{intl.denotifyLabel}"
{href}
big={!$isVeryTinyMobileSize}
on:click="onNotifyButtonClick(event)"
ref:icon
/>
</div>
<style>
.account-profile-notify {
grid-area: notify;
align-self: flex-start;
display: none;
}
.account-profile-notify.shown {
display: block;
}
@media (max-width: 240px) {
.account-profile-notify {
justify-self: flex-end;
}
}
</style>
<script>
import IconButton from '../IconButton.html'
import { FOLLOW_BUTTON_ANIMATION } from '../../_static/animations.js'
import { store } from '../../_store/store.js'
import { setAccountNotify } from '../../_actions/notify.js'
import { formatIntl } from '../../_utils/formatIntl.js'
export default {
methods: {
oncreate () {
if (process.browser) {
window.__button = this
}
},
async onNotifyButtonClick (e) {
e.preventDefault()
e.stopPropagation()
const {
account,
accountId,
notifying
} = this.get()
if (notifying) { // unblock
await setAccountNotify(accountId, false)
} else { // follow/unfollow
this.refs.icon.animate(FOLLOW_BUTTON_ANIMATION)
await setAccountNotify(accountId, true)
}
}
},
store: () => store,
data: () => ({
}),
computed: {
accountId: ({ account }) => account.id,
notifying: ({ relationship }) => {
return relationship && relationship.notifying
},
href: ({ notifying }) => {
if (notifying) {
return '#fa-bell-ringing'
}
return '#fa-bell-o'
},
label: ({ notifying }) => {
if (notifying) {
return formatIntl('intl.notifyLabel')
}
return formatIntl('intl.denotifyLabel')
},
shown: ({ verifyCredentials, relationship }) => (
verifyCredentials && relationship && verifyCredentials.id !== relationship.id && relationship.following
),
},
components: {
IconButton
}
}
</script>

Wyświetl plik

@ -10,7 +10,8 @@
NOTIFICATION_FAVORITES,
NOTIFICATION_FOLLOWS,
NOTIFICATION_MENTIONS,
NOTIFICATION_POLLS
NOTIFICATION_POLLS,
NOTIFICATION_SUBSCRIPTIONS
} from '../../../_static/instanceSettings.js'
export default {
@ -40,6 +41,11 @@
key: NOTIFICATION_POLLS,
label: 'intl.pollResults',
defaultValue: true
},
{
key: NOTIFICATION_SUBSCRIPTIONS,
label: 'intl.subscriptions',
defaultValue: true
}
]
}),

Wyświetl plik

@ -76,6 +76,10 @@
{
key: 'poll',
label: 'intl.pollResults'
},
{
key: 'status',
label: 'intl.subscriptions'
}
]
}),

Wyświetl plik

@ -295,7 +295,7 @@
)
),
showHeader: ({ notification, status, timelineType }) => (
(notification && ['reblog', 'favourite', 'poll'].includes(notification.type)) ||
(notification && ['reblog', 'favourite', 'poll', 'status'].includes(notification.type)) ||
status.reblog ||
timelineType === 'pinned'
),

Wyświetl plik

@ -125,6 +125,8 @@
return '#fa-user-plus'
} else if (notificationType === 'poll') {
return '#fa-bar-chart'
} else if (notificationType === 'status') {
return '#fa-comment'
}
return '#fa-star'
},
@ -135,6 +137,8 @@
return 'intl.favoritedYou'
} else if (notificationType === 'follow') {
return 'intl.followedYou'
} else if (notificationType === 'status') {
return 'intl.posted'
} else if (notificationType === 'poll') {
if ($currentVerifyCredentials && status && $currentVerifyCredentials.id === status.account.id) {
return 'intl.pollYouCreatedEnded'

Wyświetl plik

@ -6,3 +6,4 @@ export const NOTIFICATION_FAVORITES = 'notificationFavs'
export const NOTIFICATION_FOLLOWS = 'notificationFollows'
export const NOTIFICATION_MENTIONS = 'notificationMentions'
export const NOTIFICATION_POLLS = 'notificationPolls'
export const NOTIFICATION_SUBSCRIPTIONS = 'notificationSubscriptions'

Wyświetl plik

@ -3,7 +3,7 @@ import {
HOME_REPLIES,
NOTIFICATION_FAVORITES,
NOTIFICATION_FOLLOWS, NOTIFICATION_MENTIONS, NOTIFICATION_POLLS,
NOTIFICATION_REBLOGS
NOTIFICATION_REBLOGS, NOTIFICATION_SUBSCRIPTIONS
} from '../../_static/instanceSettings.js'
import {
WORD_FILTER_CONTEXT_ACCOUNT,
@ -46,12 +46,14 @@ export function timelineFilterComputations (store) {
computeTimelineFilter(store, 'timelineShowFavs', { notifications: NOTIFICATION_FAVORITES })
computeTimelineFilter(store, 'timelineShowMentions', { notifications: NOTIFICATION_MENTIONS })
computeTimelineFilter(store, 'timelineShowPolls', { notifications: NOTIFICATION_POLLS })
computeTimelineFilter(store, 'timelineShowSubscriptions', { notifications: NOTIFICATION_SUBSCRIPTIONS })
computeNotificationFilter(store, 'timelineNotificationShowReblogs', NOTIFICATION_REBLOGS)
computeNotificationFilter(store, 'timelineNotificationShowFollows', NOTIFICATION_FOLLOWS)
computeNotificationFilter(store, 'timelineNotificationShowFavs', NOTIFICATION_FAVORITES)
computeNotificationFilter(store, 'timelineNotificationShowMentions', NOTIFICATION_MENTIONS)
computeNotificationFilter(store, 'timelineNotificationShowPolls', NOTIFICATION_POLLS)
computeNotificationFilter(store, 'timelineNotificationShowSubscriptions', NOTIFICATION_SUBSCRIPTIONS)
store.compute(
'timelineWordFilterContext',
@ -85,10 +87,10 @@ export function timelineFilterComputations (store) {
[
'timelineShowReblogs', 'timelineShowReplies', 'timelineShowFollows',
'timelineShowFavs', 'timelineShowMentions', 'timelineShowPolls',
'timelineWordFilterContext'
'timelineShowSubscriptions', 'timelineWordFilterContext'
],
(showReblogs, showReplies, showFollows, showFavs, showMentions, showPolls, wordFilterContext) => (
createFilterFunction(showReblogs, showReplies, showFollows, showFavs, showMentions, showPolls, wordFilterContext)
(showReblogs, showReplies, showFollows, showFavs, showMentions, showPolls, showSubscriptions, wordFilterContext) => (
createFilterFunction(showReblogs, showReplies, showFollows, showFavs, showMentions, showPolls, showSubscriptions, wordFilterContext)
)
)
@ -99,10 +101,10 @@ export function timelineFilterComputations (store) {
[
'timelineNotificationShowReblogs', 'timelineNotificationShowFollows',
'timelineNotificationShowFavs', 'timelineNotificationShowMentions',
'timelineNotificationShowPolls'
'timelineNotificationShowPolls', 'timelineNotificationShowSubscriptions'
],
(showReblogs, showFollows, showFavs, showMentions, showPolls) => (
createFilterFunction(showReblogs, true, showFollows, showFavs, showMentions, showPolls, WORD_FILTER_CONTEXT_NOTIFICATIONS)
(showReblogs, showFollows, showFavs, showMentions, showPolls, showSubscriptions) => (
createFilterFunction(showReblogs, true, showFollows, showFavs, showMentions, showPolls, showSubscriptions, WORD_FILTER_CONTEXT_NOTIFICATIONS)
)
)

Wyświetl plik

@ -1,7 +1,8 @@
// create a function for filtering timeline item summaries
export const createFilterFunction = (
showReblogs, showReplies, showFollows, showFavs, showMentions, showPolls, wordFilterContext
showReblogs, showReplies, showFollows, showFavs, showMentions, showPolls,
showSubscriptions, wordFilterContext
) => {
return item => {
if (item.filterContexts && item.filterContexts.includes(wordFilterContext)) {
@ -19,6 +20,8 @@ export const createFilterFunction = (
return showMentions
case 'follow':
return showFollows
case 'status':
return showSubscriptions
}
if (item.reblogId) {
return showReblogs

Wyświetl plik

@ -214,6 +214,7 @@ async function showRichNotification (data, notification) {
}
case 'reblog':
case 'favourite':
case 'status':
case 'poll': {
await self.registration.showNotification(data.title, {
badge,

Wyświetl plik

@ -1,18 +1,18 @@
import { favoriteStatus } from '../src/routes/_api/favorite'
import { favoriteStatus } from '../src/routes/_api/favorite.js'
import fetch from 'node-fetch'
import FileApi from 'file-api'
import { users } from './users'
import { postStatus } from '../src/routes/_api/statuses'
import { deleteStatus } from '../src/routes/_api/delete'
import { authorizeFollowRequest, getFollowRequests } from '../src/routes/_api/followRequests'
import { followAccount, unfollowAccount } from '../src/routes/_api/follow'
import { updateCredentials } from '../src/routes/_api/updateCredentials'
import { reblogStatus } from '../src/routes/_api/reblog'
import { users } from './users.js'
import { postStatus } from '../src/routes/_api/statuses.js'
import { deleteStatus } from '../src/routes/_api/delete.js'
import { authorizeFollowRequest, getFollowRequests } from '../src/routes/_api/followRequests.js'
import { followAccount, unfollowAccount } from '../src/routes/_api/follow.js'
import { updateCredentials } from '../src/routes/_api/updateCredentials.js'
import { reblogStatus } from '../src/routes/_api/reblog.js'
import { submitMedia } from './submitMedia.js'
import { voteOnPoll } from '../src/routes/_api/polls'
import { POLL_EXPIRY_DEFAULT } from '../src/routes/_static/polls'
import { createList, getLists } from '../src/routes/_api/lists'
import { createFilter, deleteFilter, getFilters } from '../src/routes/_api/filters'
import { voteOnPoll } from '../src/routes/_api/polls.js'
import { POLL_EXPIRY_DEFAULT } from '../src/routes/_static/polls.js'
import { createList, getLists } from '../src/routes/_api/lists.js'
import { createFilter, deleteFilter, getFilters } from '../src/routes/_api/filters.js'
global.fetch = fetch
global.File = FileApi.File

Wyświetl plik

@ -2,7 +2,7 @@ import {
accountProfileFollowButton,
accountProfileFollowedBy, accountProfileMoreOptionsButton, communityNavButton, getNthSearchResult,
getNthStatus, getNthStatusOptionsButton, getNthDialogOptionsOption, getUrl, modalDialog,
sleep
sleep, getDialogOptionWithText
} from '../utils'
import { Selector as $ } from 'testcafe'
import { loginAsFoobar } from '../roles'
@ -21,10 +21,10 @@ test('Can block and unblock an account from a status', async t => {
await t
.click(getNthStatusOptionsButton(1))
.expect(getNthDialogOptionsOption(1).innerText).contains('Unfollow @admin')
.expect(getNthDialogOptionsOption(2).innerText).contains('Block @admin')
.expect(getNthDialogOptionsOption(3).innerText).contains('Block @admin')
await sleep(500)
await t
.click(getNthDialogOptionsOption(2))
.click(getDialogOptionWithText('Block @admin'))
.expect(modalDialog.exists).notOk()
await sleep(500)
await t
@ -60,12 +60,9 @@ test('Can block and unblock an account from the account profile page', async t =
await sleep(500)
await t
.click(accountProfileMoreOptionsButton)
.expect(getNthDialogOptionsOption(1).innerText).contains('Mention @baz')
.expect(getNthDialogOptionsOption(2).innerText).contains('Follow @baz')
.expect(getNthDialogOptionsOption(3).innerText).contains('Block @baz')
await sleep(500)
await t
.click(getNthDialogOptionsOption(3))
.click(getDialogOptionWithText('Block @baz'))
.expect(accountProfileFollowedBy.innerText).match(/blocked/i)
.expect(accountProfileFollowButton.getAttribute('aria-label')).eql('Unblock')
.expect(accountProfileFollowButton.getAttribute('title')).eql('Unblock')

Wyświetl plik

@ -5,11 +5,10 @@ import {
getNthSearchResult,
getNthStatus,
getNthStatusOptionsButton,
getNthDialogOptionsOption,
getUrl,
modalDialog,
closeDialogButton,
confirmationDialogOKButton, sleep
confirmationDialogOKButton, sleep, getDialogOptionWithText
} from '../utils'
import { Selector as $ } from 'testcafe'
import { loginAsFoobar } from '../roles'
@ -25,12 +24,9 @@ test('Can mute and unmute an account', async t => {
await t.expect(getNthStatus(1).innerText).contains(post, { timeout: 20000 })
.click(getNthStatusOptionsButton(1))
.expect(getNthDialogOptionsOption(1).innerText).contains('Unfollow @admin')
.expect(getNthDialogOptionsOption(2).innerText).contains('Block @admin')
.expect(getNthDialogOptionsOption(3).innerText).contains('Mute @admin')
await sleep(1000)
await t
.click(getNthDialogOptionsOption(3))
.click(getDialogOptionWithText('Mute @admin'))
await sleep(1000)
await t
.click(confirmationDialogOKButton)
@ -43,20 +39,13 @@ test('Can mute and unmute an account', async t => {
.click(getNthSearchResult(1))
.expect(getUrl()).contains('/accounts/1')
.click(accountProfileMoreOptionsButton)
.expect(getNthDialogOptionsOption(1).innerText).contains('Mention @admin')
.expect(getNthDialogOptionsOption(2).innerText).contains('Unfollow @admin')
.expect(getNthDialogOptionsOption(3).innerText).contains('Block @admin')
.expect(getNthDialogOptionsOption(4).innerText).contains('Unmute @admin')
await sleep(1000)
await t
.click(getNthDialogOptionsOption(4))
.click(getDialogOptionWithText('Unmute @admin'))
await sleep(1000)
await t
.click(accountProfileMoreOptionsButton)
.expect(getNthDialogOptionsOption(1).innerText).contains('Mention @admin')
.expect(getNthDialogOptionsOption(2).innerText).contains('Unfollow @admin')
.expect(getNthDialogOptionsOption(3).innerText).contains('Block @admin')
.expect(getNthDialogOptionsOption(4).innerText).contains('Mute @admin')
.expect(getDialogOptionWithText('Mute @admin').exists).ok()
await sleep(1000)
await t
.click(closeDialogButton)

Wyświetl plik

@ -0,0 +1,49 @@
import {
accountProfileMoreOptionsButton,
getNthStatus,
getNthStatusOptionsButton,
getUrl,
modalDialog,
sleep, getDialogOptionWithText, getNthStatusAccountLink, notificationsNavButton, getNthStatusHeader
} from '../utils'
import { loginAsFoobar } from '../roles'
import { postAs } from '../serverActions'
fixture`139-notify-denotify.js`
.page`http://localhost:4002`
test('Can notify and denotify an account', async t => {
await loginAsFoobar(t)
const post = 'ha ha ha'
await postAs('admin', post)
await t.expect(getNthStatus(1).innerText).contains(post, { timeout: 20000 })
.click(getNthStatusOptionsButton(1))
await sleep(1000)
await t.click(getDialogOptionWithText('Subscribe to @admin'))
await sleep(1000)
await t
.expect(modalDialog.exists).notOk()
await sleep(1000)
const notificationPost = 'get a notification for this'
await postAs('admin', notificationPost)
await sleep(1000)
await t
.expect(notificationsNavButton.getAttribute('aria-label')).eql('Notifications (1 notification)', {
timeout: 20000
})
.click(notificationsNavButton)
.expect(getUrl()).contains('/notifications')
await t
.expect(getNthStatus(1).innerText).contains(notificationPost, { timeout: 20000 })
.expect(getNthStatusHeader(1).innerText).contains('posted')
.click(getNthStatusAccountLink(1))
.expect(getUrl()).contains('/accounts/1')
.click(accountProfileMoreOptionsButton)
await sleep(1000)
await t.click(getDialogOptionWithText('Unsubscribe from @admin'))
await sleep(1000)
await t.click(accountProfileMoreOptionsButton)
await t
.expect(getDialogOptionWithText('Subscribe to @admin').exists).ok()
})

Wyświetl plik

@ -522,6 +522,10 @@ export function getNthStatusOptionsButton (n) {
return $(`${getNthStatusSelector(n)} .status-toolbar button:nth-child(4)`)
}
export function getNthStatusAccountLink (n) {
return $(`${getNthStatusSelector(n)} .status-author-name`)
}
export function getNthFavoritedLabel (n) {
return getNthFavoriteButton(n).getAttribute('aria-label')
}
@ -546,6 +550,10 @@ export function getNthDialogOptionsOption (n) {
return $(`.modal-dialog li:nth-child(${n}) button`)
}
export function getDialogOptionWithText (text) {
return $('.modal-dialog li button').withText(text)
}
export function getReblogsCount () {
return reblogsCountElement.innerCount
}