From 5a945c2024855b89dfb99f81a2c4d226bb39dc32 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Wed, 20 Sep 2023 19:47:56 -0700 Subject: Prefilter the mergefeed to ensure a better mix of following and custom feeds (#1498) * Prefilter the mergefeed to ensure a better mix of following and custom feeds * Test suite improvements & tests for the mergefeed (#1499) * Disable invite codes test for now * Update test sim to latest iphone * Introduce TestCtrls driver * Add mergefeed tests --- __e2e__/tests/composer.test.ts | 7 +- __e2e__/tests/home-screen.test.ts | 7 +- __e2e__/tests/invite-codes.test-skip.ts | 67 ++++++++++++++ __e2e__/tests/invite-codes.test.ts | 67 -------------- __e2e__/tests/merge-feed.test.ts | 157 ++++++++++++++++++++++++++++++++ __e2e__/tests/mute-lists.test.ts | 25 ++--- __e2e__/tests/profile-screen.test.ts | 7 +- __e2e__/tests/search-screen.test.ts | 7 +- __e2e__/tests/self-labeling.test.ts | 7 +- __e2e__/tests/shell.test.ts | 7 +- __e2e__/tests/thread-muting.test.ts | 31 ++----- __e2e__/tests/thread-screen.test.ts | 7 +- 12 files changed, 259 insertions(+), 137 deletions(-) create mode 100644 __e2e__/tests/invite-codes.test-skip.ts delete mode 100644 __e2e__/tests/invite-codes.test.ts create mode 100644 __e2e__/tests/merge-feed.test.ts (limited to '__e2e__/tests') diff --git a/__e2e__/tests/composer.test.ts b/__e2e__/tests/composer.test.ts index afc23cc13..6251ad0c8 100644 --- a/__e2e__/tests/composer.test.ts +++ b/__e2e__/tests/composer.test.ts @@ -1,18 +1,17 @@ /* eslint-env detox/detox */ -import {openApp, login, createServer, sleep} from '../util' +import {openApp, loginAsAlice, createServer, sleep} from '../util' describe('Composer', () => { - let service: string beforeAll(async () => { - service = await createServer('?users') + await createServer('?users') await openApp({ permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'}, }) }) it('Login', async () => { - await login(service, 'alice', 'hunter2') + await loginAsAlice() await element(by.id('homeScreenFeedTabs-Following')).tap() }) diff --git a/__e2e__/tests/home-screen.test.ts b/__e2e__/tests/home-screen.test.ts index 7bad3c19a..7647b55cb 100644 --- a/__e2e__/tests/home-screen.test.ts +++ b/__e2e__/tests/home-screen.test.ts @@ -1,16 +1,15 @@ /* eslint-env detox/detox */ -import {openApp, login, createServer} from '../util' +import {openApp, loginAsAlice, createServer} from '../util' describe('Home screen', () => { - let service: string beforeAll(async () => { - service = await createServer('?users&follows&posts') + await createServer('?users&follows&posts') await openApp({permissions: {notifications: 'YES'}}) }) it('Login', async () => { - await login(service, 'alice', 'hunter2') + await loginAsAlice() await element(by.id('homeScreenFeedTabs-Following')).tap() }) diff --git a/__e2e__/tests/invite-codes.test-skip.ts b/__e2e__/tests/invite-codes.test-skip.ts new file mode 100644 index 000000000..f5d2bafb3 --- /dev/null +++ b/__e2e__/tests/invite-codes.test-skip.ts @@ -0,0 +1,67 @@ +/* eslint-env detox/detox */ + +/** + * This test is being skipped until we can resolve the detox crash issue + * with the side drawer. + */ + +import {openApp, loginAsAlice, createServer} from '../util' + +describe('invite-codes', () => { + let service: string + let inviteCode = '' + beforeAll(async () => { + service = await createServer('?users&invite') + await openApp({permissions: {notifications: 'YES'}}) + }) + + it('I can fetch invite codes', async () => { + await expect(element(by.id('signInButton'))).toBeVisible() + await loginAsAlice() + await element(by.id('viewHeaderDrawerBtn')).tap() + await expect(element(by.id('drawer'))).toBeVisible() + await element(by.id('menuItemInviteCodes')).tap() + await expect(element(by.id('inviteCodesModal'))).toBeVisible() + const attrs = await element(by.id('inviteCode-0-code')).getAttributes() + inviteCode = attrs.text + await element(by.id('closeBtn')).tap() + await element(by.id('viewHeaderDrawerBtn')).tap() + await element(by.id('menuItemButton-Settings')).tap() + await element(by.id('signOutBtn')).tap() + }) + + it('I can create a new account with the invite code', async () => { + await element(by.id('createAccountButton')).tap() + await device.takeScreenshot('1- opened create account screen') + await element(by.id('otherServerBtn')).tap() + await device.takeScreenshot('2- selected other server') + await element(by.id('customServerInput')).clearText() + await element(by.id('customServerInput')).typeText(service) + await device.takeScreenshot('3- input test server URL') + await element(by.id('nextBtn')).tap() + await element(by.id('inviteCodeInput')).typeText(inviteCode) + await element(by.id('emailInput')).typeText('example@test.com') + await element(by.id('passwordInput')).typeText('hunter2') + await device.takeScreenshot('4- entered account details') + await element(by.id('nextBtn')).tap() + await element(by.id('handleInput')).typeText('e2e-test') + await device.takeScreenshot('4- entered handle') + await element(by.id('nextBtn')).tap() + await expect(element(by.id('welcomeOnboarding'))).toBeVisible() + await element(by.id('continueBtn')).tap() + await expect(element(by.id('recommendedFeedsOnboarding'))).toBeVisible() + await element(by.id('continueBtn')).tap() + await expect(element(by.id('homeScreen'))).toBeVisible() + }) + + it('I get a notification for the new user', async () => { + await loginAsAlice() + await element(by.id('menuItemButton-Notifications')).tap() + await expect(element(by.id('invitedUser'))).toBeVisible() + }) + + it('I can dismiss the new user notification', async () => { + await element(by.id('dismissBtn')).tap() + await expect(element(by.id('invitedUser'))).not.toBeVisible() + }) +}) diff --git a/__e2e__/tests/invite-codes.test.ts b/__e2e__/tests/invite-codes.test.ts deleted file mode 100644 index efe7b9d12..000000000 --- a/__e2e__/tests/invite-codes.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* eslint-env detox/detox */ - -import {openApp, login, createServer} from '../util' - -describe('invite-codes', () => { - let service: string - let inviteCode = '' - beforeAll(async () => { - service = await createServer('?users&invite') - await openApp({permissions: {notifications: 'YES'}}) - }) - - it('I can fetch invite codes', 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('menuItemInviteCodes')).tap() - await expect(element(by.id('inviteCodesModal'))).toBeVisible() - const attrs = await element(by.id('inviteCode-0-code')).getAttributes() - inviteCode = attrs.text - await element(by.id('closeBtn')).tap() - await element(by.id('viewHeaderDrawerBtn')).tap() - await element(by.id('menuItemButton-Settings')).tap() - await element(by.id('signOutBtn')).tap() - }) - - it('I can create a new account with the invite code', async () => { - await element(by.id('createAccountButton')).tap() - await device.takeScreenshot('1- opened create account screen') - await element(by.id('otherServerBtn')).tap() - await device.takeScreenshot('2- selected other server') - await element(by.id('customServerInput')).clearText() - await element(by.id('customServerInput')).typeText(service) - await device.takeScreenshot('3- input test server URL') - await element(by.id('nextBtn')).tap() - await element(by.id('inviteCodeInput')).typeText(inviteCode) - await element(by.id('emailInput')).typeText('example@test.com') - await element(by.id('passwordInput')).typeText('hunter2') - await device.takeScreenshot('4- entered account details') - await element(by.id('nextBtn')).tap() - await element(by.id('handleInput')).typeText('e2e-test') - await device.takeScreenshot('4- entered handle') - await element(by.id('nextBtn')).tap() - await expect(element(by.id('welcomeOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('recommendedFeedsOnboarding'))).toBeVisible() - await element(by.id('continueBtn')).tap() - await expect(element(by.id('homeScreen'))).toBeVisible() - await element(by.id('viewHeaderDrawerBtn')).tap() - await element(by.id('menuItemButton-Settings')).tap() - await element(by.id('signOutBtn')).tap() - }) - - it('I get a notification for the new user', async () => { - await expect(element(by.id('signInButton'))).toBeVisible() - await login(service, 'alice', 'hunter2') - await element(by.id('viewHeaderDrawerBtn')).tap() - await element(by.id('menuItemButton-Notifications')).tap() - await expect(element(by.id('invitedUser'))).toBeVisible() - }) - - it('I can dismiss the new user notification', async () => { - await element(by.id('dismissBtn')).tap() - await expect(element(by.id('invitedUser'))).not.toBeVisible() - }) -}) diff --git a/__e2e__/tests/merge-feed.test.ts b/__e2e__/tests/merge-feed.test.ts new file mode 100644 index 000000000..903e34328 --- /dev/null +++ b/__e2e__/tests/merge-feed.test.ts @@ -0,0 +1,157 @@ +/* eslint-env detox/detox */ + +import {openApp, loginAsAlice, createServer} from '../util' + +describe('Mergefeed', () => { + beforeAll(async () => { + await createServer('?mergefeed') + await openApp({permissions: {notifications: 'YES'}}) + }) + + it('Login', async () => { + await loginAsAlice() + await element(by.id('e2eToggleMergefeed')).tap() + }) + + it('Sees the expected mix of posts with default filters', async () => { + await element(by.id('followingFeedPage-feed-flatlist')).swipe( + 'down', + 'slow', + 1, + 0.5, + 0.5, + ) + // followed users + await expect( + element( + by.id('postText').withAncestor(by.id('feedItem-by-carla.test')), + ).atIndex(0), + ).toHaveText('Post 9') + await expect( + element( + by.id('postText').withAncestor(by.id('feedItem-by-bob.test')), + ).atIndex(0), + ).toHaveText('Post 9') + await element(by.id('followingFeedPage-feed-flatlist')).swipe( + 'up', + 'fast', + 1, + 0.5, + 0.5, + ) + // feed users + await expect( + element( + by.id('postText').withAncestor(by.id('feedItem-by-dan.test')), + ).atIndex(0), + ).toHaveText('Post 0') + }) + + it('Sees the expected mix of posts with replies disabled', async () => { + await element(by.id('followingFeedPage-feed-flatlist')).swipe( + 'down', + 'fast', + 1, + 0.5, + 0.5, + ) + await element(by.id('followingFeedPage-feed-flatlist')).swipe( + 'down', + 'fast', + 1, + 0.5, + 0.5, + ) + await element(by.id('viewHeaderHomeFeedPrefsBtn')).tap() + await element(by.id('toggleRepliesBtn')).tap() + await element(by.id('confirmBtn')).tap() + await element(by.id('followingFeedPage-feed-flatlist')).swipe( + 'down', + 'slow', + 1, + 0.5, + 0.5, + ) + + // followed users + await expect( + element( + by.id('postText').withAncestor(by.id('feedItem-by-carla.test')), + ).atIndex(0), + ).toHaveText('Post 9') + await expect( + element( + by.id('postText').withAncestor(by.id('feedItem-by-bob.test')), + ).atIndex(0), + ).toHaveText('Post 9') + await element(by.id('followingFeedPage-feed-flatlist')).swipe( + 'up', + 'fast', + 1, + 0.5, + 0.5, + ) + + // feed users + await expect( + element( + by.id('postText').withAncestor(by.id('feedItem-by-dan.test')), + ).atIndex(0), + ).toHaveText('Post 0') + }) + + it('Sees the expected mix of posts with no follows', async () => { + await element(by.id('followingFeedPage-feed-flatlist')).swipe( + 'down', + 'fast', + 1, + 0.5, + 0.5, + ) + + 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('unfollowBtn')).tap() + await element(by.id('profileHeaderBackBtn')).tap() + + // have to wait for the toast to clear + await waitFor(element(by.id('searchTextInputClearBtn'))) + .toBeVisible() + .withTimeout(5000) + await element(by.id('searchTextInputClearBtn')).tap() + await element(by.id('searchTextInput')).typeText('carla') + await element(by.id('searchAutoCompleteResult-carla.test')).tap() + await expect(element(by.id('profileView'))).toBeVisible() + await element(by.id('unfollowBtn')).tap() + await element(by.id('profileHeaderBackBtn')).tap() + + await element(by.id('bottomBarHomeBtn')).tap() + await element(by.id('followingFeedPage-feed-flatlist')).swipe( + 'down', + 'slow', + 1, + 0.5, + 0.5, + ) + await element(by.id('followingFeedPage-feed-flatlist')).swipe( + 'down', + 'slow', + 1, + 0.5, + 0.5, + ) + + // followed users NOT present + await expect(element(by.id('feedItem-by-carla.test'))).not.toExist() + await expect(element(by.id('feedItem-by-bob.test'))).not.toExist() + + // feed users + await expect( + element( + by.id('postText').withAncestor(by.id('feedItem-by-dan.test')), + ).atIndex(0), + ).toHaveText('Post 0') + }) +}) diff --git a/__e2e__/tests/mute-lists.test.ts b/__e2e__/tests/mute-lists.test.ts index 1fd3dc328..6c46de0ec 100644 --- a/__e2e__/tests/mute-lists.test.ts +++ b/__e2e__/tests/mute-lists.test.ts @@ -1,11 +1,10 @@ /* eslint-env detox/detox */ -import {openApp, login, createServer, sleep} from '../util' +import {openApp, loginAsAlice, loginAsBob, createServer, sleep} from '../util' describe('Mute lists', () => { - let service: string beforeAll(async () => { - service = await createServer('?users&follows&labels') + await createServer('?users&follows&labels') await openApp({ permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'}, }) @@ -13,10 +12,8 @@ describe('Mute lists', () => { 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 loginAsAlice() + await element(by.id('e2eGotoModeration')).tap() await element(by.id('mutelistsBtn')).tap() await expect(element(by.id('list-Muted Users'))).toBeVisible() await element(by.id('list-Muted Users')).tap() @@ -141,19 +138,9 @@ describe('Mute lists', () => { }) it('Can report a mute list', async () => { - await element(by.id('bottomBarHomeBtn')).tap() - // Last test leaves us in the list view so we are going back 1 screen to the lists list screen - await element(by.id('viewHeaderDrawerBtn')).tap() - // then to the moderation screen - await element(by.id('viewHeaderDrawerBtn')).tap() - // then to the home screen - await element(by.id('viewHeaderDrawerBtn')).tap() - // then open the drawer to go to settings - await element(by.id('viewHeaderDrawerBtn')).tap() - await element(by.id('menuItemButton-Settings')).tap() + await element(by.id('e2eGotoSettings')).tap() await element(by.id('signOutBtn')).tap() - await expect(element(by.id('signInButton'))).toBeVisible() - await login(service, 'bob.test', 'hunter2') + await loginAsBob() await element(by.id('bottomBarSearchBtn')).tap() await element(by.id('searchTextInput')).typeText('alice') await element(by.id('searchAutoCompleteResult-alice.test')).tap() diff --git a/__e2e__/tests/profile-screen.test.ts b/__e2e__/tests/profile-screen.test.ts index 92ed2dc65..101aaf61c 100644 --- a/__e2e__/tests/profile-screen.test.ts +++ b/__e2e__/tests/profile-screen.test.ts @@ -1,11 +1,10 @@ /* eslint-env detox/detox */ -import {openApp, login, createServer, sleep} from '../util' +import {openApp, loginAsAlice, createServer, sleep} from '../util' describe('Profile screen', () => { - let service: string beforeAll(async () => { - service = await createServer('?users&posts&feeds') + await createServer('?users&posts&feeds') await openApp({ permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'}, }) @@ -13,7 +12,7 @@ describe('Profile screen', () => { it('Login and navigate to my profile', async () => { await expect(element(by.id('signInButton'))).toBeVisible() - await login(service, 'alice', 'hunter2') + await loginAsAlice() await element(by.id('bottomBarProfileBtn')).tap() }) diff --git a/__e2e__/tests/search-screen.test.ts b/__e2e__/tests/search-screen.test.ts index 093d97c89..8b3f55b3d 100644 --- a/__e2e__/tests/search-screen.test.ts +++ b/__e2e__/tests/search-screen.test.ts @@ -1,18 +1,17 @@ /* eslint-env detox/detox */ -import {openApp, login, createServer} from '../util' +import {openApp, loginAsAlice, createServer} from '../util' describe('Search screen', () => { - let service: string beforeAll(async () => { - service = await createServer('?users') + await createServer('?users') await openApp({ permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'}, }) }) it('Login', async () => { - await login(service, 'alice', 'hunter2') + await loginAsAlice() }) it('Navigate to another user profile via autocomplete', async () => { diff --git a/__e2e__/tests/self-labeling.test.ts b/__e2e__/tests/self-labeling.test.ts index ba8d00f21..68678688d 100644 --- a/__e2e__/tests/self-labeling.test.ts +++ b/__e2e__/tests/self-labeling.test.ts @@ -1,18 +1,17 @@ /* eslint-env detox/detox */ -import {openApp, login, createServer, sleep} from '../util' +import {openApp, loginAsAlice, createServer, sleep} from '../util' describe('Self-labeling', () => { - let service: string beforeAll(async () => { - service = await createServer('?users') + await createServer('?users') await openApp({ permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'}, }) }) it('Login', async () => { - await login(service, 'alice', 'hunter2') + await loginAsAlice() await element(by.id('homeScreenFeedTabs-Following')).tap() }) diff --git a/__e2e__/tests/shell.test.ts b/__e2e__/tests/shell.test.ts index 5cfd4277f..69619dd81 100644 --- a/__e2e__/tests/shell.test.ts +++ b/__e2e__/tests/shell.test.ts @@ -1,16 +1,15 @@ /* eslint-env detox/detox */ -import {openApp, login, createServer} from '../util' +import {openApp, loginAsAlice, createServer} from '../util' describe('Shell', () => { - let service: string beforeAll(async () => { - service = await createServer('?users') + await createServer('?users') await openApp({permissions: {notifications: 'YES'}}) }) it('Login', async () => { - await login(service, 'alice', 'hunter2') + await loginAsAlice() await element(by.id('homeScreenFeedTabs-Following')).tap() }) diff --git a/__e2e__/tests/thread-muting.test.ts b/__e2e__/tests/thread-muting.test.ts index 8acd9d81f..3b2dc1221 100644 --- a/__e2e__/tests/thread-muting.test.ts +++ b/__e2e__/tests/thread-muting.test.ts @@ -1,42 +1,34 @@ /* eslint-env detox/detox */ -import {openApp, login, createServer} from '../util' +import {openApp, loginAsAlice, loginAsBob, createServer} from '../util' describe('Thread muting', () => { - let service: string beforeAll(async () => { - service = await createServer('?users&follows') + await createServer('?users&follows') await openApp({permissions: {notifications: 'YES'}}) }) it('Login, create a thread, and log out', async () => { - await login(service, 'alice', 'hunter2') + await loginAsAlice() await element(by.id('homeScreenFeedTabs-Following')).tap() await element(by.id('composeFAB')).tap() await element(by.id('composerTextInput')).typeText('Test thread') await element(by.id('composerPublishBtn')).tap() await expect(element(by.id('composeFAB'))).toBeVisible() - await element(by.id('viewHeaderDrawerBtn')).tap() - await element(by.id('menuItemButton-Settings')).tap() - await element(by.id('signOutBtn')).tap() }) it('Login, reply to the thread, and log out', async () => { - await login(service, 'bob', 'hunter2') + await loginAsBob() await element(by.id('homeScreenFeedTabs-Following')).tap() const alicePosts = by.id('feedItem-by-alice.test') await element(by.id('replyBtn').withAncestor(alicePosts)).atIndex(0).tap() await element(by.id('composerTextInput')).typeText('Reply 1') await element(by.id('composerPublishBtn')).tap() await expect(element(by.id('composeFAB'))).toBeVisible() - await element(by.id('viewHeaderDrawerBtn')).tap() - await element(by.id('menuItemButton-Settings')).tap() - await element(by.id('signOutBtn')).tap() }) it('Login, confirm notification exists, mute thread, and log out', async () => { - await login(service, 'alice', 'hunter2') - + await loginAsAlice() await element(by.id('bottomBarNotificationsBtn')).tap() const bobNotifs = by.id('feedItem-by-bob.test') await expect( @@ -50,14 +42,10 @@ describe('Thread muting', () => { await waitFor(element(by.id('viewHeaderDrawerBtn'))) .toBeVisible() .withTimeout(5000) - - await element(by.id('viewHeaderDrawerBtn')).tap() - await element(by.id('menuItemButton-Settings')).tap() - await element(by.id('signOutBtn')).tap() }) it('Login, reply to the thread twice, and log out', async () => { - await login(service, 'bob', 'hunter2') + await loginAsBob() await element(by.id('bottomBarProfileBtn')).tap() await element(by.id('selector-1')).tap() @@ -74,13 +62,10 @@ describe('Thread muting', () => { await expect(element(by.id('composeFAB'))).toBeVisible() await element(by.id('bottomBarHomeBtn')).tap() - await element(by.id('viewHeaderDrawerBtn')).tap() - await element(by.id('menuItemButton-Settings')).tap() - await element(by.id('signOutBtn')).tap() }) it('Login, confirm notifications dont exist, unmute the thread, confirm notifications exist', async () => { - await login(service, 'alice', 'hunter2') + await loginAsAlice() await element(by.id('bottomBarNotificationsBtn')).tap() const bobNotifs = by.id('feedItem-by-bob.test') @@ -93,7 +78,7 @@ describe('Thread muting', () => { await element(by.id('postDropdownBtn').withAncestor(alicePosts)) .atIndex(0) .tap() - await element(by.text('Mute thread')).tap() + await element(by.text('Unmute thread')).tap() // TODO // the swipe down to trigger PTR isnt working and I dont want to block on this diff --git a/__e2e__/tests/thread-screen.test.ts b/__e2e__/tests/thread-screen.test.ts index 0964988e9..02831d055 100644 --- a/__e2e__/tests/thread-screen.test.ts +++ b/__e2e__/tests/thread-screen.test.ts @@ -1,16 +1,15 @@ /* eslint-env detox/detox */ -import {openApp, login, createServer} from '../util' +import {openApp, loginAsAlice, createServer} from '../util' describe('Thread screen', () => { - let service: string beforeAll(async () => { - service = await createServer('?users&follows&thread') + await createServer('?users&follows&thread') await openApp({permissions: {notifications: 'YES'}}) }) it('Login & navigate to thread', async () => { - await login(service, 'alice', 'hunter2') + await loginAsAlice() await element(by.id('homeScreenFeedTabs-Following')).tap() await element(by.id('feedItem-by-bob.test')).atIndex(0).tap() await expect( -- cgit 1.4.1