about summary refs log tree commit diff
path: root/__e2e__
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-11-01 16:15:40 -0700
committerGitHub <noreply@github.com>2023-11-01 16:15:40 -0700
commitf57a8cf8ba0cd10a54abf35d960d8fb90266fa6b (patch)
treea9da6032bcbd587d92fd1030e698aea2dbef9f72 /__e2e__
parentf9944b55e26fe6109bc2e7a25b88979111470ed9 (diff)
downloadvoidsky-f57a8cf8ba0cd10a54abf35d960d8fb90266fa6b.tar.zst
Lists updates: curate lists and blocklists (#1689)
* Add lists screen

* Update Lists screen and List create/edit modal to support curate lists

* Rework the ProfileList screen and add curatelist support

* More ProfileList progress

* Update list modals

* Rename mutelists to modlists

* Layout updates/fixes

* More layout fixes

* Modal fixes

* List list screen updates

* Update feed page to give more info

* Layout fixes to ListAddUser modal

* Layout fixes to FlatList and Feed on desktop

* Layout fix to LoadLatestBtn on Web

* Handle did resolution before showing the ProfileList screen

* Rename the CustomFeed routes to ProfileFeed for consistency

* Fix layout issues with the pager and feeds

* Factor out some common code

* Fix UIs for mobile

* Fix user list rendering

* Fix: dont bubble custom feed errors in the merge feed

* Refactor feed models to reduce usage of the SavedFeeds model

* Replace CustomFeedModel with FeedSourceModel which abstracts feed-generators and lists

* Add the ability to pin lists

* Add pinned lists to mobile

* Remove dead code

* Rework the ProfileScreenHeader to create more real-estate for action buttons

* Improve layout behavior on web mobile breakpoints

* Refactor feed & list pages to use new Tabs layout component

* Refactor to ProfileSubpageHeader

* Implement modlist block and mute

* Switch to new api and just modify state on modlist actions

* Fix some UI overflows

* Fix: dont show edit buttons on lists you dont own

* Fix alignment issue on long titles

* Improve loading and error states for feeds & lists

* Update list dropdown icons for ios

* Fetch feed display names in the mergefeed

* Improve rendering off offline feeds in the feed-listing page

* Update Feeds listing UI to react to changes in saved/pinned state

* Refresh list and feed on posts tab press

* Fix pinned feed ordering UI

* Fixes to list pinning

* Remove view=simple qp

* Add list to feed tuners

* Render richtext

* Add list href

* Add 'view avatar'

* Remove unused import

* Fix missing import

* Correctly reflect block by list state

* Replace the <Tabs> component with the more effective <PagerWithHeader> component

* Improve the responsiveness of the PagerWithHeader

* Fix visual jank in the feed loading state

* Improve performance of the PagerWithHeader

* Fix a case that would cause the header to animate too aggressively

* Add the ability to scroll to top by tapping the selected tab

* Fix unit test runner

* Update modlists test

* Add curatelist tests

* Fix: remove link behavior in ListAddUser modal

* Fix some layout jank in the PagerWithHeader on iOS

* Simplify ListItems header rendering

* Wait for the appview to recognize the list before proceeding with list creation

* Fix glitch in the onPageSelecting index of the Pager

* Fix until()

* Copy fix

Co-authored-by: Eric Bailey <git@esb.lol>

---------

Co-authored-by: Eric Bailey <git@esb.lol>
Diffstat (limited to '__e2e__')
-rw-r--r--__e2e__/tests/curate-lists.test.ts208
-rw-r--r--__e2e__/tests/mod-lists.test.ts (renamed from __e2e__/tests/mute-lists.test.ts)116
2 files changed, 280 insertions, 44 deletions
diff --git a/__e2e__/tests/curate-lists.test.ts b/__e2e__/tests/curate-lists.test.ts
new file mode 100644
index 000000000..b7c6c25c8
--- /dev/null
+++ b/__e2e__/tests/curate-lists.test.ts
@@ -0,0 +1,208 @@
+/* eslint-env detox/detox */
+
+import {openApp, loginAsAlice, loginAsBob, createServer, sleep} from '../util'
+
+describe('Curate lists', () => {
+  beforeAll(async () => {
+    await createServer('?users&follows&posts')
+    await openApp({
+      permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'},
+    })
+  })
+
+  it('Login and create a curatelists', async () => {
+    await expect(element(by.id('signInButton'))).toBeVisible()
+    await loginAsAlice()
+    await element(by.id('e2eGotoLists')).tap()
+    await element(by.id('newUserListBtn')).tap()
+    await expect(element(by.id('createOrEditListModal'))).toBeVisible()
+    await element(by.id('editNameInput')).typeText('Good Ppl')
+    await element(by.id('editDescriptionInput')).typeText('They good')
+    await element(by.id('saveBtn')).tap()
+    await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
+    await element(by.text('About')).tap()
+    await expect(element(by.id('headerTitle'))).toHaveText('Good Ppl')
+    await expect(element(by.id('listDescription'))).toHaveText('They good')
+  })
+
+  it('Edit display name and description via the edit curatelist modal', async () => {
+    await element(by.id('headerDropdownBtn')).tap()
+    await element(by.text('Edit List Details')).tap()
+    await expect(element(by.id('createOrEditListModal'))).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('createOrEditListModal'))).not.toBeVisible()
+    await expect(element(by.id('headerTitle'))).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('headerDropdownBtn')))
+      .toBeVisible()
+      .withTimeout(5000)
+  })
+
+  it('Remove description via the edit curatelist modal', async () => {
+    await element(by.id('headerDropdownBtn')).tap()
+    await element(by.text('Edit List Details')).tap()
+    await expect(element(by.id('createOrEditListModal'))).toBeVisible()
+    await element(by.id('editDescriptionInput')).clearText()
+    await element(by.id('saveBtn')).tap()
+    await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
+    await expect(element(by.id('listDescription'))).not.toBeVisible()
+    // have to wait for the toast to clear
+    await waitFor(element(by.id('headerDropdownBtn')))
+      .toBeVisible()
+      .withTimeout(5000)
+  })
+
+  it('Set avi via the edit curatelist modal', async () => {
+    await expect(element(by.id('userAvatarFallback'))).toExist()
+    await element(by.id('headerDropdownBtn')).tap()
+    await element(by.text('Edit List Details')).tap()
+    await expect(element(by.id('createOrEditListModal'))).toBeVisible()
+    await element(by.id('changeAvatarBtn')).tap()
+    await element(by.text('Library')).tap()
+    await sleep(3e3)
+    await element(by.id('saveBtn')).tap()
+    await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
+    await expect(element(by.id('userAvatarImage'))).toExist()
+    // have to wait for the toast to clear
+    await waitFor(element(by.id('headerDropdownBtn')))
+      .toBeVisible()
+      .withTimeout(5000)
+  })
+
+  it('Remove avi via the edit curatelist modal', async () => {
+    await expect(element(by.id('userAvatarImage'))).toExist()
+    await element(by.id('headerDropdownBtn')).tap()
+    await element(by.text('Edit List Details')).tap()
+    await expect(element(by.id('createOrEditListModal'))).toBeVisible()
+    await element(by.id('changeAvatarBtn')).tap()
+    await element(by.text('Remove')).tap()
+    await element(by.id('saveBtn')).tap()
+    await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
+    await expect(element(by.id('userAvatarFallback'))).toExist()
+    // have to wait for the toast to clear
+    await waitFor(element(by.id('headerDropdownBtn')))
+      .toBeVisible()
+      .withTimeout(5000)
+  })
+
+  it('Delete the curatelist', async () => {
+    await element(by.id('headerDropdownBtn')).tap()
+    await element(by.text('Delete List')).tap()
+    await element(by.id('confirmBtn')).tap()
+    await expect(element(by.id('listsEmpty'))).toBeVisible()
+  })
+
+  it('Create a new curatelist', async () => {
+    await element(by.id('newUserListBtn')).tap()
+    await expect(element(by.id('createOrEditListModal'))).toBeVisible()
+    await element(by.id('editNameInput')).typeText('Good Ppl')
+    await element(by.id('editDescriptionInput')).typeText('They good')
+    await element(by.id('saveBtn')).tap()
+    await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
+    await element(by.text('About')).tap()
+    await expect(element(by.id('headerTitle'))).toHaveText('Good Ppl')
+    await expect(element(by.id('listDescription'))).toHaveText('They good')
+  })
+
+  it('Adds users on curatelists from the list', async () => {
+    await element(by.text('About')).tap()
+    await element(by.id('addUserBtn')).tap()
+    await expect(element(by.id('listAddUserModal'))).toBeVisible()
+    await waitFor(element(by.id('user-bob.test-addBtn')))
+      .toBeVisible()
+      .withTimeout(5000)
+    await element(by.id('user-bob.test-addBtn')).tap()
+    await element(by.id('doneBtn')).tap()
+    await expect(element(by.id('listAddUserModal'))).not.toBeVisible()
+    await expect(element(by.id('user-bob.test'))).toBeVisible()
+  })
+
+  it('Shows posts by the users in the list', async () => {
+    await element(by.text('Posts')).tap()
+    await expect(element(by.id('feedItem-by-bob.test'))).toBeVisible()
+  })
+
+  it('Pins the list', async () => {
+    await element(by.id('pinBtn')).tap()
+    await element(by.id('e2eGotoHome')).tap()
+    await element(by.id('homeScreenFeedTabs-Good Ppl')).tap()
+    await expect(element(by.id('feedItem-by-bob.test'))).toBeVisible()
+
+    await element(by.id('bottomBarFeedsBtn')).tap()
+    await element(by.id('saved-feed-Good Ppl')).tap()
+    await expect(element(by.id('feedItem-by-bob.test'))).toBeVisible()
+
+    await element(by.id('unpinBtn')).tap()
+    await element(by.id('bottomBarHomeBtn')).tap()
+    await expect(
+      element(by.id('homeScreenFeedTabs-Good Ppl')),
+    ).not.toBeVisible()
+
+    await element(by.id('e2eGotoLists')).tap()
+    await element(by.id('list-Good Ppl')).tap()
+  })
+
+  it('Removes users on curatelists from the list', async () => {
+    await element(by.text('About')).tap()
+    await expect(element(by.id('user-bob.test'))).toBeVisible()
+    await element(by.id('user-bob.test-editBtn')).tap()
+    await expect(element(by.id('userAddRemoveListsModal'))).toBeVisible()
+    await element(by.id('toggleBtn-Good Ppl')).tap()
+    await element(by.id('saveBtn')).tap()
+    await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible()
+  })
+
+  it('Shows the curatelist on my profile', async () => {
+    await element(by.id('bottomBarProfileBtn')).tap()
+    await element(by.id('selector')).swipe('left')
+    await element(by.id('selector-4')).tap()
+    await element(by.id('list-Good Ppl')).tap()
+  })
+
+  it('Adds and removes users on curatelists from the profile', 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.text('Add to Lists')).tap()
+    await expect(element(by.id('userAddRemoveListsModal'))).toBeVisible()
+    await element(by.id('toggleBtn-Good Ppl')).tap()
+    await element(by.id('saveBtn')).tap()
+    await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible()
+
+    await element(by.id('profileHeaderDropdownBtn')).tap()
+    await element(by.text('Add to Lists')).tap()
+    await expect(element(by.id('userAddRemoveListsModal'))).toBeVisible()
+    await element(by.id('toggleBtn-Good Ppl')).tap()
+    await element(by.id('saveBtn')).tap()
+    await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible()
+  })
+
+  it('Can report a user list', async () => {
+    await element(by.id('e2eGotoSettings')).tap()
+    await element(by.id('signOutBtn')).tap()
+    await loginAsBob()
+    await element(by.id('bottomBarSearchBtn')).tap()
+    await element(by.id('searchTextInput')).typeText('alice')
+    await element(by.id('searchAutoCompleteResult-alice.test')).tap()
+    await element(by.id('selector')).swipe('left')
+    await element(by.id('selector-3')).tap()
+    await element(by.id('list-Good Ppl')).tap()
+    await element(by.id('headerDropdownBtn')).tap()
+    await element(by.text('Report List')).tap()
+    await expect(element(by.id('reportModal'))).toBeVisible()
+    await expect(element(by.text('Report List'))).toBeVisible()
+    await element(
+      by.id('reportReasonRadios-com.atproto.moderation.defs#reasonRude'),
+    ).tap()
+    await element(by.id('sendReportBtn')).tap()
+    await expect(element(by.id('reportModal'))).not.toBeVisible()
+  })
+})
diff --git a/__e2e__/tests/mute-lists.test.ts b/__e2e__/tests/mod-lists.test.ts
index 6c46de0ec..2b33aaed8 100644
--- a/__e2e__/tests/mute-lists.test.ts
+++ b/__e2e__/tests/mod-lists.test.ts
@@ -2,7 +2,7 @@
 
 import {openApp, loginAsAlice, loginAsBob, createServer, sleep} from '../util'
 
-describe('Mute lists', () => {
+describe('Mod lists', () => {
   beforeAll(async () => {
     await createServer('?users&follows&labels')
     await openApp({
@@ -10,11 +10,11 @@ describe('Mute lists', () => {
     })
   })
 
-  it('Login and view my mutelists', async () => {
+  it('Login and view my modlists', async () => {
     await expect(element(by.id('signInButton'))).toBeVisible()
     await loginAsAlice()
     await element(by.id('e2eGotoModeration')).tap()
-    await element(by.id('mutelistsBtn')).tap()
+    await element(by.id('moderationlistsBtn')).tap()
     await expect(element(by.id('list-Muted Users'))).toBeVisible()
     await element(by.id('list-Muted Users')).tap()
     await expect(
@@ -22,101 +22,128 @@ describe('Mute lists', () => {
     ).toBeVisible()
   })
 
-  it('Toggle subscription', async () => {
-    await element(by.id('unsubscribeListBtn')).tap()
-    await element(by.id('subscribeListBtn')).tap()
+  it('Toggle mute subscription', async () => {
+    await element(by.id('unmuteBtn')).tap()
+    await element(by.id('subscribeBtn')).tap()
+    await element(by.text('Mute accounts')).tap()
+    await element(by.id('confirmBtn')).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()
+  it('Edit display name and description via the edit modlist modal', async () => {
+    await element(by.id('headerDropdownBtn')).tap()
+    await element(by.text('Edit List Details')).tap()
+    await expect(element(by.id('createOrEditListModal'))).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('createOrEditListModal'))).not.toBeVisible()
+    await expect(element(by.id('headerTitle'))).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')))
+    await waitFor(element(by.id('headerDropdownBtn')))
       .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()
+  it('Remove description via the edit modlist modal', async () => {
+    await element(by.id('headerDropdownBtn')).tap()
+    await element(by.text('Edit List Details')).tap()
+    await expect(element(by.id('createOrEditListModal'))).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('createOrEditListModal'))).not.toBeVisible()
     await expect(element(by.id('listDescription'))).not.toBeVisible()
     // have to wait for the toast to clear
-    await waitFor(element(by.id('editListBtn')))
+    await waitFor(element(by.id('headerDropdownBtn')))
       .toBeVisible()
       .withTimeout(5000)
   })
 
-  it('Set avi via the edit mutelist modal', async () => {
+  it('Set avi via the edit modlist 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('headerDropdownBtn')).tap()
+    await element(by.text('Edit List Details')).tap()
+    await expect(element(by.id('createOrEditListModal'))).toBeVisible()
     await element(by.id('changeAvatarBtn')).tap()
     await element(by.text('Library')).tap()
     await sleep(3e3)
     await element(by.id('saveBtn')).tap()
-    await expect(element(by.id('createOrEditMuteListModal'))).not.toBeVisible()
+    await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
     await expect(element(by.id('userAvatarImage'))).toExist()
     // have to wait for the toast to clear
-    await waitFor(element(by.id('editListBtn')))
+    await waitFor(element(by.id('headerDropdownBtn')))
       .toBeVisible()
       .withTimeout(5000)
   })
 
-  it('Remove avi via the edit mutelist modal', async () => {
+  it('Remove avi via the edit modlist 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('headerDropdownBtn')).tap()
+    await element(by.text('Edit List Details')).tap()
+    await expect(element(by.id('createOrEditListModal'))).toBeVisible()
     await element(by.id('changeAvatarBtn')).tap()
     await element(by.text('Remove')).tap()
     await element(by.id('saveBtn')).tap()
-    await expect(element(by.id('createOrEditMuteListModal'))).not.toBeVisible()
+    await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
     await expect(element(by.id('userAvatarFallback'))).toExist()
     // have to wait for the toast to clear
-    await waitFor(element(by.id('editListBtn')))
+    await waitFor(element(by.id('headerDropdownBtn')))
       .toBeVisible()
       .withTimeout(5000)
   })
 
-  it('Delete the mutelist', async () => {
-    await element(by.id('deleteListBtn')).tap()
+  it('Delete the modlist', async () => {
+    await element(by.id('headerDropdownBtn')).tap()
+    await element(by.text('Delete List')).tap()
     await element(by.id('confirmBtn')).tap()
-    await expect(element(by.id('emptyMuteLists'))).toBeVisible()
+    await expect(element(by.id('listsEmpty'))).toBeVisible()
   })
 
-  it('Create a new mutelist', async () => {
-    await element(by.id('emptyMuteLists-button')).tap()
-    await expect(element(by.id('createOrEditMuteListModal'))).toBeVisible()
+  it('Create a new modlist', async () => {
+    await element(by.id('newModListBtn')).tap()
+    await expect(element(by.id('createOrEditListModal'))).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('createOrEditListModal'))).not.toBeVisible()
+    await expect(element(by.id('headerTitle'))).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')))
+  })
+
+  it('Adds and removes users on modlists from the list', async () => {
+    await element(by.id('addUserBtn')).tap()
+    await expect(element(by.id('listAddUserModal'))).toBeVisible()
+    await waitFor(element(by.id('user-warn-posts.test-addBtn')))
       .toBeVisible()
       .withTimeout(5000)
+    await element(by.id('user-warn-posts.test-addBtn')).tap()
+    await element(by.id('doneBtn')).tap()
+    await expect(element(by.id('listAddUserModal'))).not.toBeVisible()
+    await element(by.id('listItems-flatlist')).swipe(
+      'down',
+      'slow',
+      1,
+      0.5,
+      0.5,
+    )
+    await expect(element(by.id('user-warn-posts.test'))).toBeVisible()
+    await element(by.id('user-warn-posts.test-editBtn')).tap()
+    await expect(element(by.id('userAddRemoveListsModal'))).toBeVisible()
+    await element(by.id('toggleBtn-Bad Ppl')).tap()
+    await element(by.id('saveBtn')).tap()
+    await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible()
   })
 
-  it('Shows the mutelist on my profile', async () => {
+  it('Shows the modlist on my profile', async () => {
     await element(by.id('bottomBarProfileBtn')).tap()
     await element(by.id('selector')).swipe('left')
     await element(by.id('selector-4')).tap()
     await element(by.id('list-Bad Ppl')).tap()
   })
 
-  it('Adds and removes users on mutelists', async () => {
+  it('Adds and removes users on modlists from the profile', async () => {
     await element(by.id('bottomBarSearchBtn')).tap()
     await element(by.id('searchTextInput')).typeText('bob')
     await element(by.id('searchAutoCompleteResult-bob.test')).tap()
@@ -124,17 +151,17 @@ describe('Mute lists', () => {
 
     await element(by.id('profileHeaderDropdownBtn')).tap()
     await element(by.text('Add to Lists')).tap()
-    await expect(element(by.id('listAddRemoveUserModal'))).toBeVisible()
+    await expect(element(by.id('userAddRemoveListsModal'))).toBeVisible()
     await element(by.id('toggleBtn-Bad Ppl')).tap()
     await element(by.id('saveBtn')).tap()
-    await expect(element(by.id('listAddRemoveUserModal'))).not.toBeVisible()
+    await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible()
 
     await element(by.id('profileHeaderDropdownBtn')).tap()
     await element(by.text('Add to Lists')).tap()
-    await expect(element(by.id('listAddRemoveUserModal'))).toBeVisible()
+    await expect(element(by.id('userAddRemoveListsModal'))).toBeVisible()
     await element(by.id('toggleBtn-Bad Ppl')).tap()
     await element(by.id('saveBtn')).tap()
-    await expect(element(by.id('listAddRemoveUserModal'))).not.toBeVisible()
+    await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible()
   })
 
   it('Can report a mute list', async () => {
@@ -147,7 +174,8 @@ describe('Mute lists', () => {
     await element(by.id('selector')).swipe('left')
     await element(by.id('selector-3')).tap()
     await element(by.id('list-Bad Ppl')).tap()
-    await element(by.id('reportListBtn')).tap()
+    await element(by.id('headerDropdownBtn')).tap()
+    await element(by.text('Report List')).tap()
     await expect(element(by.id('reportModal'))).toBeVisible()
     await expect(element(by.text('Report List'))).toBeVisible()
     await element(