From ebcd6333863a2073278fad482981d9898c0f20ca Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 11 May 2023 16:08:21 -0500 Subject: [APP-635] Mutelists (#601) * Add lists and profilelist screens * Implement lists screen and lists-list in profiles * Add empty states to the lists screen * Switch (mostly) from blocklists to mutelists * Rework: create a new moderation screen and move everything related under it * Fix moderation screen on desktop web * Tune the empty state code * Change content moderation modal to content filtering * Add CreateMuteList modal * Implement mutelist creation * Add lists listings * Add the ability to create new mutelists * Add 'add to list' tool * Satisfy the hashtag hyphen haters * Add update/delete/subscribe/unsubscribe to lists * Show which list caused a mute * Add list un/subscribe * Add the mute override when viewing a profile's posts * Update to latest backend * Add simulation tests and tune some behaviors * Fix lint * Bump deps * Fix list refresh after creation * Mute list subscriptions -> Mute lists --- __e2e__/mock-server.ts | 24 ++++++- __e2e__/tests/mute-lists.test.ts | 141 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 __e2e__/tests/mute-lists.test.ts (limited to '__e2e__') diff --git a/__e2e__/mock-server.ts b/__e2e__/mock-server.ts index 6744f697f..6ddfe3ca0 100644 --- a/__e2e__/mock-server.ts +++ b/__e2e__/mock-server.ts @@ -91,6 +91,7 @@ async function main() { 'always-warn-profile', 'always-warn-posts', 'muted-account', + 'muted-by-list-account', ]) { await server.mocker.createUser(user) await server.mocker.follow('alice', user) @@ -258,11 +259,32 @@ async function main() { await server.mocker.createPost('muted-account', 'muted post') await server.mocker.createQuotePost( 'muted-account', - 'account quote post', + 'muted quote post', anchorPost, ) await server.mocker.createReply( 'muted-account', + 'muted reply', + anchorPost, + ) + + const list = await server.mocker.createMuteList( + 'alice', + 'Muted Users', + ) + await server.mocker.addToMuteList( + 'alice', + list, + server.mocker.users['muted-by-list-account'].did, + ) + await server.mocker.createPost('muted-by-list-account', 'muted post') + await server.mocker.createQuotePost( + 'muted-by-list-account', + 'account quote post', + anchorPost, + ) + await server.mocker.createReply( + 'muted-by-list-account', 'account reply', anchorPost, ) diff --git a/__e2e__/tests/mute-lists.test.ts b/__e2e__/tests/mute-lists.test.ts new file mode 100644 index 000000000..e93162513 --- /dev/null +++ b/__e2e__/tests/mute-lists.test.ts @@ -0,0 +1,141 @@ +/* eslint-env detox/detox */ + +import {openApp, login, createServer, sleep} from '../util' + +describe('Profile screen', () => { + let service: string + beforeAll(async () => { + service = await createServer('?users&follows&labels') + await openApp({ + permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'}, + }) + }) + + it('Login and view my mutelists', async () => { + await expect(element(by.id('signInButton'))).toBeVisible() + await login(service, 'alice', 'hunter2') + await element(by.id('viewHeaderDrawerBtn')).tap() + await expect(element(by.id('drawer'))).toBeVisible() + await element(by.id('menuItemButton-Moderation')).tap() + await element(by.id('mutelistsBtn')).tap() + await expect(element(by.id('list-Muted Users'))).toBeVisible() + await element(by.id('list-Muted Users')).tap() + await expect( + element(by.id('user-muted-by-list-account.test')), + ).toBeVisible() + }) + + it('Toggle subscription', async () => { + await element(by.id('unsubscribeListBtn')).tap() + await element(by.id('subscribeListBtn')).tap() + }) + + it('Edit display name and description via the edit mutelist modal', async () => { + await element(by.id('editListBtn')).tap() + await expect(element(by.id('createOrEditMuteListModal'))).toBeVisible() + await element(by.id('editNameInput')).clearText() + await element(by.id('editNameInput')).typeText('Bad Ppl') + await element(by.id('editDescriptionInput')).clearText() + await element(by.id('editDescriptionInput')).typeText('They bad') + await element(by.id('saveBtn')).tap() + await expect(element(by.id('createOrEditMuteListModal'))).not.toBeVisible() + await expect(element(by.id('listName'))).toHaveText('Bad Ppl') + await expect(element(by.id('listDescription'))).toHaveText('They bad') + // have to wait for the toast to clear + await waitFor(element(by.id('editListBtn'))) + .toBeVisible() + .withTimeout(5000) + }) + + it('Remove description via the edit mutelist modal', async () => { + await element(by.id('editListBtn')).tap() + await expect(element(by.id('createOrEditMuteListModal'))).toBeVisible() + await element(by.id('editDescriptionInput')).clearText() + await element(by.id('saveBtn')).tap() + await expect(element(by.id('createOrEditMuteListModal'))).not.toBeVisible() + await expect(element(by.id('listDescription'))).not.toBeVisible() + // have to wait for the toast to clear + await waitFor(element(by.id('editListBtn'))) + .toBeVisible() + .withTimeout(5000) + }) + + it('Set avi via the edit mutelist modal', async () => { + await expect(element(by.id('userAvatarFallback'))).toExist() + await element(by.id('editListBtn')).tap() + await expect(element(by.id('createOrEditMuteListModal'))).toBeVisible() + await element(by.id('changeAvatarBtn')).tap() + await element(by.id('changeAvatarLibraryBtn')).tap() + await sleep(3e3) + await element(by.id('saveBtn')).tap() + await expect(element(by.id('createOrEditMuteListModal'))).not.toBeVisible() + await expect(element(by.id('userAvatarImage'))).toExist() + // have to wait for the toast to clear + await waitFor(element(by.id('editListBtn'))) + .toBeVisible() + .withTimeout(5000) + }) + + it('Remove avi via the edit mutelist modal', async () => { + await expect(element(by.id('userAvatarImage'))).toExist() + await element(by.id('editListBtn')).tap() + await expect(element(by.id('createOrEditMuteListModal'))).toBeVisible() + await element(by.id('changeAvatarBtn')).tap() + await element(by.id('changeAvatarRemoveBtn')).tap() + await element(by.id('saveBtn')).tap() + await expect(element(by.id('createOrEditMuteListModal'))).not.toBeVisible() + await expect(element(by.id('userAvatarFallback'))).toExist() + // have to wait for the toast to clear + await waitFor(element(by.id('editListBtn'))) + .toBeVisible() + .withTimeout(5000) + }) + + it('Delete the mutelist', async () => { + await element(by.id('deleteListBtn')).tap() + await element(by.id('confirmBtn')).tap() + await expect(element(by.id('emptyMuteLists'))).toBeVisible() + }) + + it('Create a new mutelist', async () => { + await element(by.id('emptyMuteLists-button')).tap() + await expect(element(by.id('createOrEditMuteListModal'))).toBeVisible() + await element(by.id('editNameInput')).typeText('Bad Ppl') + await element(by.id('editDescriptionInput')).typeText('They bad') + await element(by.id('saveBtn')).tap() + await expect(element(by.id('createOrEditMuteListModal'))).not.toBeVisible() + await expect(element(by.id('listName'))).toHaveText('Bad Ppl') + await expect(element(by.id('listDescription'))).toHaveText('They bad') + // have to wait for the toast to clear + await waitFor(element(by.id('editListBtn'))) + .toBeVisible() + .withTimeout(5000) + }) + + it('Shows the mutelist on my profile', async () => { + await element(by.id('bottomBarProfileBtn')).tap() + await element(by.id('selector-2')).tap() + await element(by.id('list-Bad Ppl')).tap() + }) + + it('Adds and removes users on mutelists', async () => { + await element(by.id('bottomBarSearchBtn')).tap() + await element(by.id('searchTextInput')).typeText('bob') + await element(by.id('searchAutoCompleteResult-bob.test')).tap() + await expect(element(by.id('profileView'))).toBeVisible() + + await element(by.id('profileHeaderDropdownBtn')).tap() + await element(by.id('profileHeaderDropdownListAddRemoveBtn')).tap() + await expect(element(by.id('listAddRemoveUserModal'))).toBeVisible() + await element(by.id('toggleBtn-Bad Ppl')).tap() + await element(by.id('saveBtn')).tap() + await expect(element(by.id('listAddRemoveUserModal'))).not.toBeVisible() + + await element(by.id('profileHeaderDropdownBtn')).tap() + await element(by.id('profileHeaderDropdownListAddRemoveBtn')).tap() + await expect(element(by.id('listAddRemoveUserModal'))).toBeVisible() + await element(by.id('toggleBtn-Bad Ppl')).tap() + await element(by.id('saveBtn')).tap() + await expect(element(by.id('listAddRemoveUserModal'))).not.toBeVisible() + }) +}) -- cgit 1.4.1