diff --git a/package.json b/package.json index 337d5d4..af810fe 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "emoji-regex": "^8.0.0", "encoding": "^0.1.12", "escape-html": "^1.0.3", - "esm": "^3.2.22", + "esm": "^3.2.25", "events-light": "^1.0.5", "express": "^4.16.4", "file-api": "^0.10.4", @@ -88,7 +88,7 @@ "requestidlecallback": "^0.3.0", "rollup": "^1.11.3", "rollup-plugin-replace": "^2.2.0", - "rollup-plugin-terser": "^4.0.4", + "rollup-plugin-terser": "^5.0.0", "sapper": "nolanlawson/sapper#for-pinafore-14", "stringz": "^1.0.0", "svelte": "^2.16.1", @@ -103,7 +103,7 @@ "webpack-bundle-analyzer": "^3.3.2" }, "devDependencies": { - "assert": "^1.5.0", + "assert": "^2.0.0", "eslint-plugin-html": "^5.0.3", "fake-indexeddb": "^2.1.0", "mocha": "^6.1.4", diff --git a/src/build/template.html b/src/build/template.html index 9587912..f1ee4bc 100644 --- a/src/build/template.html +++ b/src/build/template.html @@ -10,8 +10,7 @@ - - + diff --git a/src/inline-script/inline-script.js b/src/inline-script/inline-script.js index 6064dce..1d084a2 100644 --- a/src/inline-script/inline-script.js +++ b/src/inline-script/inline-script.js @@ -4,7 +4,7 @@ // the build process and write it to checksum.js. import { testHasLocalStorageOnce } from '../routes/_utils/testStorage' -import { DEFAULT_LIGHT_THEME, DEFAULT_THEME, switchToTheme } from '../routes/_utils/themeEngine' +import { INLINE_THEME, DEFAULT_THEME, switchToTheme } from '../routes/_utils/themeEngine' import { basename } from '../routes/_api/utils' import { onUserIsLoggedOut } from '../routes/_actions/onUserIsLoggedOut' @@ -30,7 +30,7 @@ let theme = (currentInstance && localStorage.store_instanceThemes && safeParse(localStorage.store_instanceThemes)[safeParse(localStorage.store_currentInstance)]) || DEFAULT_THEME -if (theme !== DEFAULT_LIGHT_THEME) { +if (theme !== INLINE_THEME) { // switch theme ASAP to minimize flash of default theme switchToTheme(theme) } diff --git a/src/routes/_components/settings/instance/GenericInstanceSettings.html b/src/routes/_components/settings/instance/GenericInstanceSettings.html new file mode 100644 index 0000000..d7c220e --- /dev/null +++ b/src/routes/_components/settings/instance/GenericInstanceSettings.html @@ -0,0 +1,48 @@ +
+
+ {#each options as option, i (option.key) } + {#if i > 0} +
+ {/if} + + + {/each} +
+
+ + diff --git a/src/routes/_components/settings/instance/HomeTimelineFilterSettings.html b/src/routes/_components/settings/instance/HomeTimelineFilterSettings.html new file mode 100644 index 0000000..52f7c9b --- /dev/null +++ b/src/routes/_components/settings/instance/HomeTimelineFilterSettings.html @@ -0,0 +1,29 @@ + + diff --git a/src/routes/_components/settings/instance/NotificationFilterSettings.html b/src/routes/_components/settings/instance/NotificationFilterSettings.html new file mode 100644 index 0000000..c4d2cbd --- /dev/null +++ b/src/routes/_components/settings/instance/NotificationFilterSettings.html @@ -0,0 +1,50 @@ + + diff --git a/src/routes/_components/settings/instance/PushNotificationSettings.html b/src/routes/_components/settings/instance/PushNotificationSettings.html index 98727f1..75f6d1d 100644 --- a/src/routes/_components/settings/instance/PushNotificationSettings.html +++ b/src/routes/_components/settings/instance/PushNotificationSettings.html @@ -4,18 +4,21 @@ {:elseif $notificationPermission === "denied"}

You have denied permission to show notifications.

{/if} -
- - -
- - -
- - -
- - + + {#each options as option, i (option.key)} + {#if i > 0} +
+ {/if} + + + {/each}
diff --git a/src/routes/_components/timeline/Timeline.html b/src/routes/_components/timeline/Timeline.html index 6fb2d34..7efd9cb 100644 --- a/src/routes/_components/timeline/Timeline.html +++ b/src/routes/_components/timeline/Timeline.html @@ -59,6 +59,22 @@ import { observe } from 'svelte-extras' import { createMakeProps } from '../../_actions/createMakeProps' import { showMoreAndScrollToTop } from '../../_actions/showMoreAndScrollToTop' + import { get } from '../../_utils/lodash-lite' + import { + HOME_REBLOGS, + HOME_REPLIES, + NOTIFICATION_REBLOGS, + NOTIFICATION_FOLLOWS, + NOTIFICATION_FAVORITES, + NOTIFICATION_POLLS, + NOTIFICATION_MENTIONS, + FILTER_FAVORITE, + FILTER_FOLLOW, + FILTER_MENTION, + FILTER_POLL, + FILTER_REBLOG, + FILTER_REPLY + } from '../../_static/instanceSettings' export default { oncreate () { @@ -127,9 +143,56 @@ timelineValue !== $firstTimelineItemId && timelineValue ), - itemIds: ({ $timelineItemSummaries }) => ( - // TODO: filter - $timelineItemSummaries && $timelineItemSummaries.map(_ => _.id) + currentInstanceSettings: ({ $currentInstance, $instanceSettings }) => ( + $instanceSettings[$currentInstance] || {} + ), + timelineFilters: ({ currentInstanceSettings, timeline }) => { + if (timeline === 'home') { + return { + [FILTER_REBLOG]: get(currentInstanceSettings, [HOME_REBLOGS], true), + [FILTER_REPLY]: get(currentInstanceSettings, [HOME_REPLIES], true) + } + } else if (timeline === 'notifications') { + return { + [FILTER_REBLOG]: get(currentInstanceSettings, [NOTIFICATION_REBLOGS], true), + [FILTER_FOLLOW]: get(currentInstanceSettings, [NOTIFICATION_FOLLOWS], true), + [FILTER_FAVORITE]: get(currentInstanceSettings, [NOTIFICATION_FAVORITES], true), + [FILTER_MENTION]: get(currentInstanceSettings, [NOTIFICATION_MENTIONS], true), + [FILTER_POLL]: get(currentInstanceSettings, [NOTIFICATION_POLLS], true) + } + } + }, + showReblogs: ({ timelineFilters }) => get(timelineFilters, [FILTER_REBLOG], true), + showReplies: ({ timelineFilters }) => get(timelineFilters, [FILTER_REPLY], true), + showFollows: ({ timelineFilters }) => get(timelineFilters, [FILTER_FOLLOW], true), + showMentions: ({ timelineFilters }) => get(timelineFilters, [FILTER_MENTION], true), + showPolls: ({ timelineFilters }) => get(timelineFilters, [FILTER_POLL], true), + showFavs: ({ timelineFilters }) => get(timelineFilters, [FILTER_FAVORITE], true), + itemIds: ({ + $timelineItemSummaries, showReblogs, showReplies, showFollows, showMentions, + showPolls, showFavs + }) => ( + $timelineItemSummaries && $timelineItemSummaries.filter(item => { + switch (item.type) { + case 'poll': + return showPolls + case 'favourite': + return showFavs + case 'reblog': + return showReblogs + case 'mention': + return showMentions + case 'follow': + return showFollows + } + if (item.reblogId) { + return showReblogs + } else if (item.replyId) { + return showReplies + } else { + return true + } + }).map(_ => _.id) ), itemIdsToAdd: ({ $timelineItemSummariesToAdd }) => ( // TODO: filter diff --git a/src/routes/_pages/settings/general.html b/src/routes/_pages/settings/general.html index 3f0fbfe..33ff8a7 100644 --- a/src/routes/_pages/settings/general.html +++ b/src/routes/_pages/settings/general.html @@ -3,15 +3,15 @@

Media

-
- - -
- + +
+
+ +
Logged in as: -

Push notifications:

+

Home timeline filters

+ +

Notification filters

+ +

Push notifications

-

Theme:

+

Theme

@@ -23,6 +27,8 @@ import { store } from '../../../_store/store' import SettingsLayout from '../../../_components/settings/SettingsLayout.html' import InstanceUserProfile from '../../../_components/settings/instance/InstanceUserProfile.html' + import HomeTimelineFilterSettings from '../../../_components/settings/instance/HomeTimelineFilterSettings.html' + import NotificationFilterSettings from '../../../_components/settings/instance/NotificationFilterSettings.html' import PushNotificationSettings from '../../../_components/settings/instance/PushNotificationSettings.html' import ThemeSettings from '../../../_components/settings/instance/ThemeSettings.html' import InstanceActions from '../../../_components/settings/instance/InstanceActions.html' @@ -43,7 +49,9 @@ InstanceUserProfile, PushNotificationSettings, ThemeSettings, - InstanceActions + InstanceActions, + HomeTimelineFilterSettings, + NotificationFilterSettings } } - \ No newline at end of file + diff --git a/src/routes/_static/instanceSettings.js b/src/routes/_static/instanceSettings.js new file mode 100644 index 0000000..db45398 --- /dev/null +++ b/src/routes/_static/instanceSettings.js @@ -0,0 +1,15 @@ +export const HOME_REBLOGS = 'homeReblogs' +export const HOME_REPLIES = 'homeReplies' + +export const NOTIFICATION_REBLOGS = 'notificationReblogs' +export const NOTIFICATION_FAVORITES = 'notificationFavs' +export const NOTIFICATION_FOLLOWS = 'notificationFollows' +export const NOTIFICATION_MENTIONS = 'notificationMentions' +export const NOTIFICATION_POLLS = 'notificationPolls' + +export const FILTER_REBLOG = 'reblog' +export const FILTER_REPLY = 'reply' +export const FILTER_MENTION = 'mention' +export const FILTER_FOLLOW = 'follow' +export const FILTER_FAVORITE = 'fav' +export const FILTER_POLL = 'poll' diff --git a/src/routes/_store/mixins/instanceMixins.js b/src/routes/_store/mixins/instanceMixins.js index 67d5012..7016e21 100644 --- a/src/routes/_store/mixins/instanceMixins.js +++ b/src/routes/_store/mixins/instanceMixins.js @@ -1,3 +1,5 @@ +import { get } from '../../_utils/lodash-lite' + export function instanceMixins (Store) { Store.prototype.setComposeData = function (realm, obj) { let { composeData, currentInstance } = this.get() @@ -20,4 +22,18 @@ export function instanceMixins (Store) { } this.set({ composeData }) } + + Store.prototype.getInstanceSetting = function (instanceName, settingName, defaultValue) { + let { instanceSettings } = this.get() + return get(instanceSettings, [instanceName, settingName], defaultValue) + } + + Store.prototype.setInstanceSetting = function (instanceName, settingName, value) { + let { instanceSettings } = this.get() + if (!instanceSettings[instanceName]) { + instanceSettings[instanceName] = {} + } + instanceSettings[instanceName][settingName] = value + this.set({ instanceSettings }) + } } diff --git a/src/routes/_store/store.js b/src/routes/_store/store.js index 940438b..60e28c3 100644 --- a/src/routes/_store/store.js +++ b/src/routes/_store/store.js @@ -19,6 +19,7 @@ const persistedState = { largeInlineMedia: false, instanceNameInSearch: '', instanceThemes: {}, + instanceSettings: {}, loggedInInstances: {}, loggedInInstancesInOrder: [], markMediaAsSensitive: false, diff --git a/src/routes/_utils/themeEngine.js b/src/routes/_utils/themeEngine.js index 715804b..e7ed2eb 100644 --- a/src/routes/_utils/themeEngine.js +++ b/src/routes/_utils/themeEngine.js @@ -2,8 +2,9 @@ let meta = process.browser && document.getElementById('theThemeColor') let offlineStyle = process.browser && document.getElementById('theOfflineStyle') let prefersDarkTheme = process.browser && window.matchMedia('(prefers-color-scheme: dark)').matches -export const DEFAULT_LIGHT_THEME = 'default' -export const DEFAULT_DARK_THEME = 'ozark' +export const INLINE_THEME = 'default' // theme that does not require external CSS +export const DEFAULT_LIGHT_THEME = 'default' // theme that is shown by default +export const DEFAULT_DARK_THEME = 'ozark' // theme that is shown for prefers-color-scheme:dark export const DEFAULT_THEME = prefersDarkTheme ? DEFAULT_DARK_THEME : DEFAULT_LIGHT_THEME function getExistingThemeLink () { @@ -38,7 +39,7 @@ function loadCSS (href) { export function switchToTheme (themeName = DEFAULT_THEME) { let themeColor = window.__themeColors[themeName] meta.content = themeColor || window.__themeColors[DEFAULT_THEME] - if (themeName !== DEFAULT_LIGHT_THEME) { + if (themeName !== INLINE_THEME) { loadCSS(`/theme-${themeName}.css`) } else { resetExistingTheme() diff --git a/src/service-worker.js b/src/service-worker.js index 9e148c6..e8de784 100644 --- a/src/service-worker.js +++ b/src/service-worker.js @@ -46,7 +46,7 @@ self.addEventListener('activate', event => { // delete old asset/ondemand caches for (let key of keys) { if (key !== ASSETS && - !key.startsWith('webpack_assets_')) { + !key.startsWith('webpack_assets_')) { await caches.delete(key) } } @@ -131,86 +131,71 @@ async function showSimpleNotification (data) { } async function showRichNotification (data, notification) { - const { origin } = new URL(data.icon) + const { icon, body } = data + const tag = notification.id + const { origin } = self.location switch (notification.type) { case 'follow': { await self.registration.showNotification(data.title, { - icon: data.icon, - body: data.body, - tag: notification.id, + icon, + body, + tag, data: { - url: `${self.location.origin}/accounts/${notification.account.id}` + url: `${origin}/accounts/${notification.account.id}` } }) break } - case 'mention': { - const actions = [{ - action: 'favourite', - title: 'Favourite' - }] - - if ('reply' in NotificationEvent.prototype) { - actions.splice(0, 0, { - action: 'reply', - type: 'text', - title: 'Reply' - }) - } - - if (['public', 'unlisted'].includes(notification.status.visibility)) { - actions.push({ + case 'reblog': + case 'favourite': + case 'poll': + await self.registration.showNotification(data.title, { + icon, + body, + tag, + data: { + url: `${origin}/statuses/${notification.status.id}` + } + }) + break + case 'mention': + const isPublic = ['public', 'unlisted'].includes(notification.status.visibility) + const actions = [ + { + action: 'favourite', + title: 'Favorite' + }, + isPublic && { action: 'reblog', title: 'Boost' - }) - } + } + ].filter(Boolean) await self.registration.showNotification(data.title, { - icon: data.icon, - body: data.body, - tag: notification.id, + icon, + body, + tag, data: { - instance: origin, + instance: new URL(data.icon).origin, status_id: notification.status.id, access_token: data.access_token, - url: `${self.location.origin}/statuses/${notification.status.id}` + url: `${origin}/statuses/${notification.status.id}` }, actions }) break - } - case 'reblog': { - await self.registration.showNotification(data.title, { - icon: data.icon, - body: data.body, - tag: notification.id, - data: { - url: `${self.location.origin}/statuses/${notification.status.id}` - } - }) - break - } - case 'favourite': { - await self.registration.showNotification(data.title, { - icon: data.icon, - body: data.body, - tag: notification.id, - data: { - url: `${self.location.origin}/statuses/${notification.status.id}` - } - }) - break - } } } const cloneNotification = notification => { - const clone = { } + const clone = {} // Object.assign() does not work with notifications for (let k in notification) { - clone[k] = notification[k] + if (notification.hasOwnProperty(k)) { + clone[k] = notification[k] + } } return clone @@ -227,21 +212,19 @@ const updateNotificationWithoutAction = (notification, action) => { self.addEventListener('notificationclick', event => { event.waitUntil((async () => { switch (event.action) { - case 'reply': { - await post(`${event.notification.data.instance}/api/v1/statuses/`, { - status: event.reply, - in_reply_to_id: event.notification.data.status_id - }, { 'Authorization': `Bearer ${event.notification.data.access_token}` }) - await updateNotificationWithoutAction(event.notification, 'reply') - break - } case 'reblog': { - await post(`${event.notification.data.instance}/api/v1/statuses/${event.notification.data.status_id}/reblog`, null, { 'Authorization': `Bearer ${event.notification.data.access_token}` }) + const url = `${event.notification.data.instance}/api/v1/statuses/${event.notification.data.status_id}/reblog` + await post(url, null, { + 'Authorization': `Bearer ${event.notification.data.access_token}` + }) await updateNotificationWithoutAction(event.notification, 'reblog') break } case 'favourite': { - await post(`${event.notification.data.instance}/api/v1/statuses/${event.notification.data.status_id}/favourite`, null, { 'Authorization': `Bearer ${event.notification.data.access_token}` }) + const url = `${event.notification.data.instance}/api/v1/statuses/${event.notification.data.status_id}/favourite` + await post(url, null, { + 'Authorization': `Bearer ${event.notification.data.access_token}` + }) await updateNotificationWithoutAction(event.notification, 'favourite') break } diff --git a/static/apple-icon-120.png b/static/apple-icon-120.png deleted file mode 100644 index 949e959..0000000 Binary files a/static/apple-icon-120.png and /dev/null differ diff --git a/static/apple-icon-180.png b/static/apple-icon.png similarity index 100% rename from static/apple-icon-180.png rename to static/apple-icon.png diff --git a/tests/spec/033-notification-filters.js b/tests/spec/033-notification-mentions.js similarity index 70% rename from tests/spec/033-notification-filters.js rename to tests/spec/033-notification-mentions.js index 3f831f0..dc00d2e 100644 --- a/tests/spec/033-notification-filters.js +++ b/tests/spec/033-notification-mentions.js @@ -1,22 +1,22 @@ import { - getUrl, notificationFiltersAll, notificationFiltersMention, + getUrl, notificationsTabAll, notificationsTabMentions, notificationsNavButton, validateTimeline } from '../utils' import { loginAsFoobar } from '../roles' import { notificationsMentions, notifications } from '../fixtures' -fixture`033-notification-filters.js` +fixture`033-notification-mentions.js` .page`http://localhost:4002` -test('Shows notification filters', async t => { +test('Shows notification mentions', async t => { await loginAsFoobar(t) await t .click(notificationsNavButton) .expect(getUrl()).match(/\/notifications$/) - .click(notificationFiltersMention) + .click(notificationsTabMentions) .expect(getUrl()).match(/\/notifications\/mentions$/) await validateTimeline(t, notificationsMentions) - await t.click(notificationFiltersAll) + await t.click(notificationsTabAll) .expect(getUrl()).match(/\/notifications$/) await validateTimeline(t, notifications) }) diff --git a/tests/spec/034-home-timeline-filters.js b/tests/spec/034-home-timeline-filters.js new file mode 100644 index 0000000..3de08bf --- /dev/null +++ b/tests/spec/034-home-timeline-filters.js @@ -0,0 +1,23 @@ +import { + validateTimeline, settingsNavButton, instanceSettingHomeReblogs, homeNavButton +} from '../utils' +import { loginAsFoobar } from '../roles' +import { homeTimeline } from '../fixtures' +import { Selector as $ } from 'testcafe' + +fixture`034-home-timeline-filters.js` + .page`http://localhost:4002` + +test('Filters reblogs from home timeline', async t => { + await loginAsFoobar(t) + await t + .click(settingsNavButton) + .click($('a').withText('Instances')) + .click($('a').withText('localhost:3000')) + .click(instanceSettingHomeReblogs) + .expect(instanceSettingHomeReblogs.checked).notOk() + .click(homeNavButton) + await validateTimeline(t, homeTimeline.filter(({ content }) => { + return content !== 'pinned toot 1' + })) +}) diff --git a/tests/spec/035-notification-timeline-filters.js b/tests/spec/035-notification-timeline-filters.js new file mode 100644 index 0000000..f7888c5 --- /dev/null +++ b/tests/spec/035-notification-timeline-filters.js @@ -0,0 +1,48 @@ +import { + validateTimeline, + settingsNavButton, + instanceSettingNotificationReblogs, + notificationsNavButton, + instanceSettingNotificationFavs, + instanceSettingNotificationFollows, + instanceSettingNotificationMentions +} from '../utils' +import { loginAsFoobar } from '../roles' +import { notifications } from '../fixtures' +import { Selector as $ } from 'testcafe' + +fixture`035-notification-timeline-filters.js` + .page`http://localhost:4002` + +function setSettingAndGoToNotifications (t, setting) { + return t.click(settingsNavButton) + .click($('a').withText('Instances')) + .click($('a').withText('localhost:3000')) + .click(setting) + .expect(setting.checked).notOk() + .click(notificationsNavButton) +} + +test('Filters reblogs from notification timeline', async t => { + await loginAsFoobar(t) + await setSettingAndGoToNotifications(t, instanceSettingNotificationReblogs) + await validateTimeline(t, notifications.filter(_ => !_.rebloggedBy)) +}) + +test('Filters favs from notification timeline', async t => { + await loginAsFoobar(t) + await setSettingAndGoToNotifications(t, instanceSettingNotificationFavs) + await validateTimeline(t, notifications.filter(_ => !_.favoritedBy)) +}) + +test('Filters follows from notification timeline', async t => { + await loginAsFoobar(t) + await setSettingAndGoToNotifications(t, instanceSettingNotificationFollows) + await validateTimeline(t, notifications.filter(_ => !_.followedBy)) +}) + +test('Filters mentions from notification timeline', async t => { + await loginAsFoobar(t) + await setSettingAndGoToNotifications(t, instanceSettingNotificationMentions) + await validateTimeline(t, notifications.filter(_ => !_.content)) +}) diff --git a/tests/spec/123-notification-filters.js b/tests/spec/123-notification-mentions.js similarity index 91% rename from tests/spec/123-notification-filters.js rename to tests/spec/123-notification-mentions.js index ba9304b..1bf8d5c 100644 --- a/tests/spec/123-notification-filters.js +++ b/tests/spec/123-notification-mentions.js @@ -1,12 +1,12 @@ import { getNthStatusContent, - getUrl, notificationFiltersAll, notificationFiltersMention, + getUrl, notificationsTabAll, notificationsTabMentions, notificationsNavButton, sleep } from '../utils' import { loginAsFoobar } from '../roles' import { favoriteStatusAs, postAs } from '../serverActions' -fixture`123-notification-filters.js` +fixture`123-notification-mentions.js` .page`http://localhost:4002` // maybe in the "mentions" view it should prevent the notification icon from showing (1), (2) etc @@ -18,7 +18,7 @@ test('Handles incoming notifications that are mentions', async t => { await t .click(notificationsNavButton) .expect(getUrl()).match(/\/notifications$/) - .click(notificationFiltersMention) + .click(notificationsTabMentions) .expect(getUrl()).match(/\/notifications\/mentions$/) await sleep(2000) await postAs('admin', 'hey @foobar I am mentioning you') @@ -27,7 +27,7 @@ test('Handles incoming notifications that are mentions', async t => { timeout }) .expect(getNthStatusContent(1).innerText).contains('hey @foobar I am mentioning you') - .click(notificationFiltersAll) + .click(notificationsTabAll) .expect(notificationsNavButton.getAttribute('aria-label')).eql('Notifications (current page)', { timeout }) }) @@ -39,7 +39,7 @@ test('Handles incoming notifications that are not mentions', async t => { await t .click(notificationsNavButton) .expect(getUrl()).match(/\/notifications$/) - .click(notificationFiltersMention) + .click(notificationsTabMentions) .expect(getUrl()).match(/\/notifications\/mentions$/) await sleep(2000) await postAs('admin', 'woot I am mentioning you again @foobar') @@ -57,7 +57,7 @@ test('Handles incoming notifications that are not mentions', async t => { await sleep(2000) await t .expect(getNthStatusContent(1).innerText).contains('woot I am mentioning you again @foobar') - .click(notificationFiltersAll) + .click(notificationsTabAll) .expect(notificationsNavButton.getAttribute('aria-label')).eql('Notifications (current page)', { timeout }) await t .expect(getNthStatusContent(1).innerText).contains('this is a post that I hope somebody will favorite') diff --git a/tests/spec/124-home-timeline-filters.js b/tests/spec/124-home-timeline-filters.js new file mode 100644 index 0000000..63234d1 --- /dev/null +++ b/tests/spec/124-home-timeline-filters.js @@ -0,0 +1,29 @@ +import { + settingsNavButton, instanceSettingHomeReblogs, homeNavButton, sleep, getNthStatusContent +} from '../utils' +import { loginAsFoobar } from '../roles' +import { Selector as $ } from 'testcafe' +import { postAs, reblogStatusAs } from '../serverActions' + +fixture`124-home-timeline-filters.js` + .page`http://localhost:4002` + +test('Filters favs from home timeline', async t => { + await postAs('foobar', 'Nobody should boost this') + await sleep(1000) + let { id: statusId } = await postAs('quux', 'I hope someone cool boosts this') + await reblogStatusAs('admin', statusId) + await sleep(2000) + await loginAsFoobar(t) + await t + .expect(getNthStatusContent(1).innerText).contains('I hope someone cool boosts this') + .expect(getNthStatusContent(2).innerText).contains('Nobody should boost this') + .click(settingsNavButton) + .click($('a').withText('Instances')) + .click($('a').withText('localhost:3000')) + .click(instanceSettingHomeReblogs) + .expect(instanceSettingHomeReblogs.checked).notOk() + .click(homeNavButton) + await t + .expect(getNthStatusContent(1).innerText).contains('Nobody should boost this') +}) diff --git a/tests/utils.js b/tests/utils.js index d596211..601c90e 100644 --- a/tests/utils.js +++ b/tests/utils.js @@ -64,8 +64,14 @@ export const accountProfileFilterStatuses = $('.account-profile-filters li:nth-c export const accountProfileFilterStatusesAndReplies = $('.account-profile-filters li:nth-child(2)') export const accountProfileFilterMedia = $('.account-profile-filters li:nth-child(3)') -export const notificationFiltersAll = $('.notification-filters li:nth-child(1)') -export const notificationFiltersMention = $('.notification-filters li:nth-child(2)') +export const notificationsTabAll = $('.notification-filters li:nth-child(1)') +export const notificationsTabMentions = $('.notification-filters li:nth-child(2)') + +export const instanceSettingHomeReblogs = $('#instance-option-homeReblogs') +export const instanceSettingNotificationFollows = $('#instance-option-notificationFollows') +export const instanceSettingNotificationFavs = $('#instance-option-notificationFavs') +export const instanceSettingNotificationReblogs = $('#instance-option-notificationReblogs') +export const instanceSettingNotificationMentions = $('#instance-option-notificationMentions') export function getComposeModalNthMediaAltInput (n) { return $(`.modal-dialog .compose-media:nth-child(${n}) .compose-media-alt input`) diff --git a/yarn.lock b/yarn.lock index 20f296f..dd0b82f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -642,13 +642,15 @@ assert@^1.1.1: dependencies: util "0.10.3" -assert@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" - integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== +assert@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32" + integrity sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A== dependencies: - object-assign "^4.1.1" - util "0.10.3" + es6-object-assign "^1.1.0" + is-nan "^1.2.1" + object-is "^1.0.1" + util "^0.12.0" assertion-error@^1.0.1, assertion-error@^1.1.0: version "1.1.0" @@ -2031,6 +2033,11 @@ commander@^2.18.0, commander@^2.8.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== +commander@^2.19.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -2452,7 +2459,7 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= -define-properties@^1.1.2, define-properties@^1.1.3: +define-properties@^1.1.1, define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== @@ -2798,6 +2805,11 @@ es-to-primitive@^1.2.0: is-date-object "^1.0.1" is-symbol "^1.0.2" +es6-object-assign@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" + integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw= + escape-html@^1.0.3, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -2960,10 +2972,10 @@ eslint@~5.4.0: table "^4.0.3" text-table "^0.2.0" -esm@^3.2.22: - version "3.2.22" - resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.22.tgz#5062c2e22fee3ccfee4e8f20da768330da90d6e3" - integrity sha512-z8YG7U44L82j1XrdEJcqZOLUnjxco8pO453gKOlaMD1/md1n/5QrscAmYG+oKUspsmDLuBFZrpbxI6aQ67yRxA== +esm@^3.2.25: + version "3.2.25" + resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" + integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== esotope-hammerhead@^0.2.1: version "0.2.1" @@ -4008,6 +4020,11 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-arguments@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" + integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -4144,6 +4161,11 @@ is-fullwidth-code-point@^2.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= +is-generator-function@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" + integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw== + is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -4177,6 +4199,13 @@ is-jquery-obj@^0.1.0: resolved "https://registry.yarnpkg.com/is-jquery-obj/-/is-jquery-obj-0.1.1.tgz#e8d9cc9737b1ab0733b50303e33a38ed7cc2f60b" integrity sha512-18toSebUVF7y717dgw/Dzn6djOCqrkiDp3MhB8P6TdKyCVkbD1ZwE7Uz8Hwx6hUPTvKjbyYH9ncXT4ts4qLaSA== +is-nan@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.2.1.tgz#9faf65b6fb6db24b7f5c0628475ea71f988401e2" + integrity sha1-n69ltvttskt/XAYoR16nH5iEAeI= + dependencies: + define-properties "^1.1.1" + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -4286,10 +4315,10 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -jest-worker@^24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.0.0.tgz#3d3483b077bf04f412f47654a27bba7e947f8b6d" - integrity sha512-s64/OThpfQvoCeHG963MiEZOAAxu8kHsaL/rCMF7lpdzo7vgF0CtPml9hfguOMgykgH/eOm4jFP4ibfHLruytg== +jest-worker@^24.6.0: + version "24.6.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.6.0.tgz#7f81ceae34b7cde0c9827a6980c35b7cdc0161b3" + integrity sha512-jDwgW5W9qGNvpI1tNnvajh0a5IE/PuGLFmHk6aR/BZFz8tSgGw17GsDPXAJ6p91IvYDjOw8GpFbvvZGAK+DPQQ== dependencies: merge-stream "^1.0.1" supports-color "^6.1.0" @@ -5246,6 +5275,11 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" +object-is@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6" + integrity sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY= + object-keys@^1.0.11: version "1.1.0" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.0.tgz#11bd22348dd2e096a045ab06f6c85bcc340fa032" @@ -5273,6 +5307,16 @@ object.assign@4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" +object.entries@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519" + integrity sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.12.0" + function-bind "^1.1.1" + has "^1.0.3" + object.getownpropertydescriptors@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" @@ -6352,15 +6396,15 @@ rollup-plugin-replace@^2.2.0: magic-string "^0.25.2" rollup-pluginutils "^2.6.0" -rollup-plugin-terser@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-4.0.4.tgz#6f661ef284fa7c27963d242601691dc3d23f994e" - integrity sha512-wPANT5XKVJJ8RDUN0+wIr7UPd0lIXBo4UdJ59VmlPCtlFsE20AM+14pe+tk7YunCsWEiuzkDBY3QIkSCjtrPXg== +rollup-plugin-terser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.0.0.tgz#ac50fdb703b580447a7e6b1692aeed515a6be8cf" + integrity sha512-W+jJ4opYnlmNyVW0vtRufs+EGf68BIJ7bnOazgz8mgz8pA9lUyrEifAhPs5y9M16wFeAyBGaRjKip4dnFBtXaw== dependencies: "@babel/code-frame" "^7.0.0" - jest-worker "^24.0.0" - serialize-javascript "^1.6.1" - terser "^3.14.1" + jest-worker "^24.6.0" + serialize-javascript "^1.7.0" + terser "^4.0.0" rollup-pluginutils@^2.6.0: version "2.6.0" @@ -6512,11 +6556,16 @@ send@0.16.2: range-parser "~1.2.0" statuses "~1.4.0" -serialize-javascript@^1.4.0, serialize-javascript@^1.6.1: +serialize-javascript@^1.4.0: version "1.6.1" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.6.1.tgz#4d1f697ec49429a847ca6f442a2a755126c4d879" integrity sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw== +serialize-javascript@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65" + integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA== + serve-static@1.13.2: version "1.13.2" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" @@ -6675,6 +6724,14 @@ source-map-support@^0.5.5, source-map-support@^0.5.9, source-map-support@~0.5.6, buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@~0.5.10: + version "0.5.12" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" + integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" @@ -7149,15 +7206,6 @@ terser-webpack-plugin@^1.2.3: webpack-sources "^1.1.0" worker-farm "^1.5.2" -terser@^3.14.1, terser@^3.8.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-3.14.1.tgz#cc4764014af570bc79c79742358bd46926018a32" - integrity sha512-NSo3E99QDbYSMeJaEk9YW2lTg3qS9V0aKGlb+PlOrei1X02r1wSBHCNX/O+yeTRFSWPKPIGj6MqvvdqV4rnVGw== - dependencies: - commander "~2.17.1" - source-map "~0.6.1" - source-map-support "~0.5.6" - terser@^3.16.1: version "3.16.1" resolved "https://registry.yarnpkg.com/terser/-/terser-3.16.1.tgz#5b0dd4fa1ffd0b0b43c2493b2c364fd179160493" @@ -7167,6 +7215,24 @@ terser@^3.16.1: source-map "~0.6.1" source-map-support "~0.5.9" +terser@^3.8.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-3.14.1.tgz#cc4764014af570bc79c79742358bd46926018a32" + integrity sha512-NSo3E99QDbYSMeJaEk9YW2lTg3qS9V0aKGlb+PlOrei1X02r1wSBHCNX/O+yeTRFSWPKPIGj6MqvvdqV4rnVGw== + dependencies: + commander "~2.17.1" + source-map "~0.6.1" + source-map-support "~0.5.6" + +terser@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.0.0.tgz#ef356f6f359a963e2cc675517f21c1c382877374" + integrity sha512-dOapGTU0hETFl1tCo4t56FN+2jffoKyER9qBGoUFyZ6y7WLoKT0bF+lAYi6B6YsILcGF3q1C2FBh8QcKSCgkgA== + dependencies: + commander "^2.19.0" + source-map "~0.6.1" + source-map-support "~0.5.10" + testcafe-browser-tools@1.6.8: version "1.6.8" resolved "https://registry.yarnpkg.com/testcafe-browser-tools/-/testcafe-browser-tools-1.6.8.tgz#74ace1ee4c21a20bd6d88238f0d9bc97c596b8fb" @@ -7714,6 +7780,17 @@ util@^0.11.0: dependencies: inherits "2.0.3" +util@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.0.tgz#bb5e3d29ba2703c7add0ad337003be3ca477798a" + integrity sha512-pPSOFl7VLhZ7LO/SFABPraZEEurkJUWSMn3MuA/r3WQZc+Z1fqou2JqLSOZbCLl73EUIxuUVX8X4jkX2vfJeAA== + dependencies: + inherits "2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + object.entries "^1.1.0" + safe-buffer "^5.1.2" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"