diff options
author | Paul Frazee <pfrazee@gmail.com> | 2024-05-13 08:43:13 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-13 08:43:13 -0700 |
commit | d49b93dc7e77962c143e4798344c8e35ab8a637e (patch) | |
tree | b893fa4388413cbd1cf139c4cd848c91d1cc13b0 /__e2e__ | |
parent | 5cd4ac3a34f629945ccb86e451fbf20dd06e6863 (diff) | |
download | voidsky-d49b93dc7e77962c143e4798344c8e35ab8a637e.tar.zst |
Replace e2e tests with Maestro (#3983)
* Setup maestro tests and convert some initial tests * Remove detox * Replace all tests with maestro
Diffstat (limited to '__e2e__')
32 files changed, 859 insertions, 1571 deletions
diff --git a/__e2e__/config.yml b/__e2e__/config.yml new file mode 100644 index 000000000..b36b0ef60 --- /dev/null +++ b/__e2e__/config.yml @@ -0,0 +1,2 @@ +flows: + - "flows/*" \ No newline at end of file diff --git a/__e2e__/flows/composer-self-label.yml b/__e2e__/flows/composer-self-label.yml new file mode 100644 index 000000000..cc38b1d99 --- /dev/null +++ b/__e2e__/flows/composer-self-label.yml @@ -0,0 +1,30 @@ +appId: xyz.blueskyweb.app +--- +- runScript: + file: ../setupServer.js + env: + SERVER_PATH: ?users +- runFlow: + file: ../setupApp.yml +- tapOn: + id: "e2eSignInAlice" + +# Post an image with the porn label +- tapOn: + id: "composeFAB" +- inputText: "Post with an image" +- tapOn: + id: "openGalleryBtn" +- tapOn: + id: "labelsBtn" +- tapOn: + label: "Tap on porn" + point: 78%,67% +- tapOn: + label: "Tap on confirm" + point: 51%,92% +- tapOn: + id: "composerPublishBtn" +- tapOn: + id: "e2eRefreshHome" +- assertVisible: "Adult Content" \ No newline at end of file diff --git a/__e2e__/flows/composer.yml b/__e2e__/flows/composer.yml new file mode 100644 index 000000000..f6d760ea5 --- /dev/null +++ b/__e2e__/flows/composer.yml @@ -0,0 +1,87 @@ +appId: xyz.blueskyweb.app +--- +- runScript: + file: ../setupServer.js + env: + SERVER_PATH: ?users +- runFlow: + file: ../setupApp.yml +- tapOn: + id: "e2eSignInAlice" +- tapOn: + id: "composeFAB" +- inputText: "Post text only" +- tapOn: + id: "composerPublishBtn" +- assertVisible: + id: "composeFAB" +- tapOn: + id: "composeFAB" +- inputText: "Post with an image" +- tapOn: + id: "openGalleryBtn" +- tapOn: + id: "composerPublishBtn" +- assertVisible: + id: "composeFAB" +- tapOn: + id: "composeFAB" +- inputText: "Post with a https://example.com link card" +- tapOn: + id: "composerPublishBtn" +- assertVisible: + id: "composeFAB" +- tapOn: + id: "e2eRefreshHome" +- tapOn: + id: "replyBtn" +- inputText: "Reply text only" +- tapOn: + id: "composerPublishBtn" +- assertVisible: + id: "composeFAB" +- tapOn: + id: "replyBtn" +- inputText: "Reply with an image" +- tapOn: + id: "openGalleryBtn" +- tapOn: + id: "composerPublishBtn" +- assertVisible: + id: "composeFAB" +- tapOn: + id: "replyBtn" +- inputText: "Reply with a https://example.com link card" +- tapOn: + id: "composerPublishBtn" +- assertVisible: + id: "composeFAB" +- tapOn: + id: "repostBtn" +- tapOn: + id: "quoteBtn" +- inputText: "QP text only" +- tapOn: + id: "composerPublishBtn" +- assertVisible: + id: "composeFAB" +- tapOn: + id: "repostBtn" +- tapOn: + id: "quoteBtn" +- inputText: "QP with an image" +- tapOn: + id: "openGalleryBtn" +- tapOn: + id: "composerPublishBtn" +- assertVisible: + id: "composeFAB" +- tapOn: + id: "repostBtn" +- tapOn: + id: "quoteBtn" +- inputText: "QP with a https://example.com link card" +- tapOn: + id: "composerPublishBtn" +- assertVisible: + id: "composeFAB" diff --git a/__e2e__/flows/create-account.yml b/__e2e__/flows/create-account.yml new file mode 100644 index 000000000..99ac1371a --- /dev/null +++ b/__e2e__/flows/create-account.yml @@ -0,0 +1,37 @@ +appId: xyz.blueskyweb.app +--- +- runScript: + file: ../setupServer.js + env: + SERVER_PATH: "" +- runFlow: + file: ../setupApp.yml +- tapOn: + id: "e2eOpenLoggedOutView" +- tapOn: + id: "createAccountButton" +- tapOn: + id: "selectServiceButton" +- tapOn: + id: "customSelectBtn" +- tapOn: + id: "customServerTextInput" +- inputText: "http://localhost:3000" +- pressKey: Enter +- tapOn: + id: "doneBtn" +- tapOn: + id: "emailInput" +- inputText: "example@test.com" +- tapOn: + id: "passwordInput" +- inputText: "hunter2" +- pressKey: Enter +- tapOn: + id: "nextBtn" +- tapOn: + id: "handleInput" +- inputText: "e2e-test" +- tapOn: + id: "nextBtn" + diff --git a/__e2e__/flows/curate-lists.yml b/__e2e__/flows/curate-lists.yml new file mode 100644 index 000000000..35f4f800d --- /dev/null +++ b/__e2e__/flows/curate-lists.yml @@ -0,0 +1,208 @@ +appId: xyz.blueskyweb.app +--- +- runScript: + file: ../setupServer.js + env: + SERVER_PATH: "?users&follows&posts" +- runFlow: + file: ../setupApp.yml +- tapOn: + id: "e2eSignInAlice" + +- tapOn: + label: "Create a curate list" + id: "e2eGotoLists" +- tapOn: + id: "newUserListBtn" +- assertVisible: + id: "createOrEditListModal" +- tapOn: + id: "editNameInput" +- inputText: "Good Ppl" +- tapOn: + id: "editDescriptionInput" +- inputText: "They good" +- tapOn: "Save" +- tapOn: "Save" +- assertNotVisible: + id: "createOrEditListModal" +- tapOn: "About" +- assertVisible: "Good Ppl" +- assertVisible: "They good" + +- tapOn: + label: "Edit display name and description via the edit curatelist modal" + point: "90%,9%" +- tapOn: "Edit list details" +- assertVisible: + id: "createOrEditListModal" +- tapOn: + id: "editNameInput" +- eraseText +- inputText: "Bad Ppl" +- hideKeyboard +- tapOn: + id: "editDescriptionInput" +- eraseText +- inputText: "They bad" +- tapOn: "Save" +- tapOn: "Save" +- assertNotVisible: + id: "createOrEditListModal" +- assertVisible: Bad Ppl +- assertVisible: They bad + +- tapOn: + label: "Remove description via the edit curatelist modal" + point: "90%,9%" +- tapOn: "Edit list details" +- assertVisible: + id: "createOrEditListModal" +- tapOn: + id: "editDescriptionInput" +- eraseText +- tapOn: "Save" +- tapOn: "Save" +- assertNotVisible: + id: "createOrEditListModal" +- assertNotVisible: + id: "listDescription" + +- tapOn: + label: "Delete the curatelist" + point: "90%,9%" +- tapOn: "Delete List" +- tapOn: + id: "confirmBtn" +- assertVisible: + id: "listsEmpty" + +- tapOn: + label: "Create a new curatelist" + id: "e2eGotoLists" +- tapOn: + id: "newUserListBtn" +- assertVisible: + id: "createOrEditListModal" +- tapOn: + id: "editNameInput" +- inputText: "Good Ppl" +- tapOn: + id: "editDescriptionInput" +- inputText: "They good" +- tapOn: "Save" +- tapOn: "Save" +- assertNotVisible: + id: "createOrEditListModal" +- tapOn: "About" +- assertVisible: "Good Ppl" +- assertVisible: "They good" +- tapOn: "About" + +- tapOn: + label: "Adds users on curatelists from the list" + id: "addUserBtn" +- assertVisible: + id: "listAddUserModal" +- tapOn: + id: "searchInput" +- inputText: "b" +- pressKey: Enter +- tapOn: + id: "user-bob.test-addBtn" +- tapOn: + id: "doneBtn" +- assertNotVisible: + id: "listAddUserModal" +- assertVisible: + id: "user-bob.test" + +- tapOn: "Posts" +- assertVisible: + label: "Shows posts by the users in the list" + id: "feedItem-by-bob.test" + +- tapOn: + label: "Pins the list" + id: "pinBtn" +- tapOn: + id: "e2eGotoHome" +- tapOn: "Good Ppl" +- assertVisible: + id: "feedItem-by-bob.test" +- tapOn: + id: "bottomBarFeedsBtn" +- tapOn: + id: "saved-feed-Good Ppl" +- assertVisible: + id: "feedItem-by-bob.test" +- tapOn: + id: "unpinBtn" +- tapOn: + id: "bottomBarHomeBtn" +- assertNotVisible: + id: "homeScreenFeedTabs-Good Ppl" +- tapOn: + id: "e2eGotoLists" +- tapOn: + id: "list-Good Ppl" + +- tapOn: "About" +- assertVisible: + label: "Removes users on curatelists from the list" + id: "user-bob.test" +- tapOn: + point: "90%,43%" +- assertVisible: + id: "userAddRemoveListsModal" +- tapOn: + id: "user-bob.test-addBtn" +- tapOn: + id: "doneBtn" +- assertNotVisible: + id: "userAddRemoveListsModal" + +- tapOn: + label: "Shows the curatelist on my profile" + id: "bottomBarProfileBtn" +- swipe: + from: + id: "profilePager-selector" + direction: LEFT +- tapOn: + id: "profilePager-selector-5" +- tapOn: + id: "list-Good Ppl" + +- tapOn: + label: "Adds and removes users on curatelists from the profile" + id: "bottomBarSearchBtn" +- tapOn: + id: "searchTextInput" +- inputText: "bob" +- tapOn: + id: "searchAutoCompleteResult-bob.test" +- assertVisible: + id: "profileView" +- tapOn: + id: "profileHeaderDropdownBtn" +- tapOn: "Add to Lists" +- assertVisible: + id: "userAddRemoveListsModal" +- tapOn: + id: "user-bob.test-addBtn" +- tapOn: + id: "doneBtn" +- assertNotVisible: + id: "userAddRemoveListsModal" +- tapOn: + id: "profileHeaderDropdownBtn" +- tapOn: "Add to Lists" +- assertVisible: + id: "userAddRemoveListsModal" +- tapOn: + id: "user-bob.test-addBtn" +- tapOn: + id: "doneBtn" +- assertNotVisible: + id: "userAddRemoveListsModal" diff --git a/__e2e__/flows/home-screen.yml b/__e2e__/flows/home-screen.yml new file mode 100644 index 000000000..69a1fe37f --- /dev/null +++ b/__e2e__/flows/home-screen.yml @@ -0,0 +1,63 @@ +appId: xyz.blueskyweb.app +--- +- runScript: + file: ../setupServer.js + env: + SERVER_PATH: ?users&follows&posts&feeds +- runFlow: + file: ../setupApp.yml +- tapOn: + id: "e2eSignInAlice" + +- tapOn: + label: "Can go to feeds page using feeds button in tab bar" + text: "Feeds ✨" +- assertVisible: "Discover New Feeds" + +- tapOn: + label: "Feeds button disappears after pinning a feed" + id: "bottomBarProfileBtn" +- swipe: + from: + id: "profilePager-selector" + direction: LEFT +- tapOn: + id: "profilePager-selector-4" +- tapOn: + id: "feed-alice-favs" +- tapOn: "Pin to Home" +- tapOn: + id: "bottomBarHomeBtn" +- assertNotVisible: "Feeds ✨" + +- tapOn: + label: "Can like posts" + id: "likeBtn" +- assertVisible: + id: "likeCount" + text: "1" +- tapOn: + id: "likeBtn" +- assertNotVisible: + id: "likeCount" + +- tapOn: + label: "Can repost posts" + id: "repostBtn" +- tapOn: "Repost" +- assertVisible: + id: "repostCount" + text: "1" +- tapOn: + id: "repostBtn" +- tapOn: "Undo repost" +- assertNotVisible: + id: "repostCount" + +- tapOn: + label: "Can delete posts" + id: "postDropdownBtn" + childOf: + id: "feedItem-by-alice.test" +- tapOn: "Delete post" +- tapOn: "Delete" diff --git a/__e2e__/flows/login.yml b/__e2e__/flows/login.yml new file mode 100644 index 000000000..f1001f78d --- /dev/null +++ b/__e2e__/flows/login.yml @@ -0,0 +1,26 @@ +appId: xyz.blueskyweb.app +--- +- runScript: + file: ../setupServer.js + env: + SERVER_PATH: "?users" +- runFlow: + file: ../setupApp.yml +- tapOn: + id: "e2eOpenLoggedOutView" +- tapOn: "Sign in" +- tapOn: + id: "selectServiceButton" +- tapOn: "Custom" +- tapOn: + id: "customServerTextInput" +- inputText: "http://localhost:3000" +- tapOn: "Done" +- tapOn: + id: "loginUsernameInput" +- inputText: "Alice" +- tapOn: + id: "loginPasswordInput" +- inputText: "hunter2" +- pressKey: Enter +- assertVisible: "Following" \ No newline at end of file diff --git a/__e2e__/flows/mod-lists.yml b/__e2e__/flows/mod-lists.yml new file mode 100644 index 000000000..75ee100a8 --- /dev/null +++ b/__e2e__/flows/mod-lists.yml @@ -0,0 +1,45 @@ +appId: xyz.blueskyweb.app +--- +- runScript: + file: ../setupServer.js + env: + SERVER_PATH: "?users&follows&labels" +- runFlow: + file: ../setupApp.yml +- tapOn: + id: "e2eSignInAlice" + +# create a modlist +- tapOn: + id: "e2eGotoModeration" +- tapOn: + id: "moderationlistsBtn" +- tapOn: "New" +- tapOn: + id: "editNameInput" +- inputText: "Muted Users" +- tapOn: + id: "editDescriptionInput" +- inputText: "Shhh" +- tapOn: "Save" +- tapOn: "Save" + +# view modlist +- assertVisible: "Muted Users" +- assertVisible: "Shhh" + +# toggle mute subscription +- tapOn: + point: "70%,9%" +- tapOn: "Mute accounts" +- tapOn: "Mute list" +- tapOn: "Unmute" + +# toggle block subscription +- tapOn: + point: "70%,9%" +- tapOn: "Block accounts" +- tapOn: "Block list" +- tapOn: "Unblock" + + # the rest of the behaviors are tested in curate-lists.yml \ No newline at end of file diff --git a/__e2e__/flows/profile-screen-edit.yml b/__e2e__/flows/profile-screen-edit.yml new file mode 100644 index 000000000..602cc6688 --- /dev/null +++ b/__e2e__/flows/profile-screen-edit.yml @@ -0,0 +1,119 @@ +appId: xyz.blueskyweb.app +--- +- runScript: + file: ../setupServer.js + env: + SERVER_PATH: "?users&posts&feeds" +- runFlow: + file: ../setupApp.yml +- tapOn: + id: "e2eSignInAlice" + + +# Navigate to my profile +- tapOn: + id: "bottomBarProfileBtn" + +# Can see feeds +- swipe: + from: + id: "profilePager-selector" + direction: LEFT +- tapOn: + id: "profilePager-selector-4" +- assertVisible: + id: "feed-alice-favs" +- swipe: + from: + id: "profilePager-selector" + direction: RIGHT +- tapOn: + id: "profilePager-selector-0" + +# Open and close edit profile modal +- tapOn: + id: "profileHeaderEditProfileButton" +- assertVisible: + id: "editProfileModal" +- tapOn: + id: "editProfileCancelBtn" +- assertNotVisible: + id: "editProfileModal" + +# Edit display name and description via the edit profile modal +- tapOn: + id: "profileHeaderEditProfileButton" +- assertVisible: + id: "editProfileModal" +- tapOn: + id: "editProfileDisplayNameInput" +- eraseText +- inputText: "Alicia" +- tapOn: + id: "editProfileDescriptionInput" +- eraseText +- inputText: "One cool hacker" +- tapOn: "Description" +- tapOn: + id: "editProfileSaveBtn" +- assertNotVisible: + id: "editProfileModal" +- assertVisible: "Alicia" +- assertVisible: "One cool hacker" + +# Remove display name and description via the edit profile modal +- tapOn: + id: "profileHeaderEditProfileButton" +- assertVisible: + id: "editProfileModal" +- tapOn: + id: "editProfileDisplayNameInput" +- eraseText +- tapOn: + id: "editProfileDescriptionInput" +- eraseText +- tapOn: "Description" +- tapOn: + id: "editProfileSaveBtn" +- assertNotVisible: + id: "editProfileModal" +- assertVisible: "alice.test" +- assertNotVisible: "One cool hacker" + +# Set avi and banner via the edit profile modal +- assertVisible: + id: "userBannerFallback" +- tapOn: + id: "profileHeaderEditProfileButton" +- assertVisible: + id: "editProfileModal" +- tapOn: + id: "changeBannerBtn" +- tapOn: "Upload from Library" +- tapOn: + id: "changeAvatarBtn" +- tapOn: "Upload from Library" +- tapOn: + id: "editProfileSaveBtn" +- assertNotVisible: + id: "editProfileModal" +- assertVisible: + id: "userBannerImage" + +# # Remove avi and banner via the edit profile modal +- tapOn: + id: "profileHeaderEditProfileButton" +- assertVisible: + id: "editProfileModal" +- tapOn: + id: "changeBannerBtn" +- tapOn: "Remove Banner" +- tapOn: + id: "changeAvatarBtn" +- tapOn: "Remove Avatar" +- tapOn: + id: "editProfileSaveBtn" +- assertNotVisible: + id: "editProfileModal" +- assertVisible: + id: "userBannerFallback" diff --git a/__e2e__/flows/profile-screen.yml b/__e2e__/flows/profile-screen.yml new file mode 100644 index 000000000..7d2d43dee --- /dev/null +++ b/__e2e__/flows/profile-screen.yml @@ -0,0 +1,37 @@ +appId: xyz.blueskyweb.app +--- +- runScript: + file: ../setupServer.js + env: + SERVER_PATH: "?users&posts&feeds" +- runFlow: + file: ../setupApp.yml +- tapOn: + id: "e2eSignInAlice" + +# Navigate to another user profile +- tapOn: + id: "bottomBarSearchBtn" +- tapOn: + id: "searchTextInput" +- inputText: "b" +- tapOn: + id: "searchAutoCompleteResult-bob.test" +- assertVisible: + id: "profileView" + +# Can follow/unfollow another user +- tapOn: + id: "followBtn" +- tapOn: + id: "unfollowBtn" + +# Can mute/unmute another user +- tapOn: + id: "profileHeaderDropdownBtn" +- tapOn: "Mute Account" +- assertVisible: "Account Muted" +- tapOn: + id: "profileHeaderDropdownBtn" +- tapOn: "Unmute Account" +- assertNotVisible: "Account Muted" \ No newline at end of file diff --git a/__e2e__/flows/search-screen.yml b/__e2e__/flows/search-screen.yml new file mode 100644 index 000000000..0d31d03fb --- /dev/null +++ b/__e2e__/flows/search-screen.yml @@ -0,0 +1,22 @@ +appId: xyz.blueskyweb.app +--- +- runScript: + file: ../setupServer.js + env: + SERVER_PATH: "?users" +- runFlow: + file: ../setupApp.yml +- tapOn: + id: "e2eSignInAlice" + +# Navigate to another user profile via autocomplete +- tapOn: + id: "bottomBarSearchBtn" +- tapOn: + id: "searchTextInput" +- inputText: "b" +- tapOn: + id: "searchAutoCompleteResult-bob.test" +- assertVisible: + id: "profileView" + diff --git a/__e2e__/flows/thread-muting.yml b/__e2e__/flows/thread-muting.yml new file mode 100644 index 000000000..316389a79 --- /dev/null +++ b/__e2e__/flows/thread-muting.yml @@ -0,0 +1,82 @@ +appId: xyz.blueskyweb.app +--- +- runScript: + file: ../setupServer.js + env: + SERVER_PATH: "?users&follows" +- runFlow: + file: ../setupApp.yml + + +# Login, create a thread, and log out +- tapOn: + id: "e2eSignInAlice" +- tapOn: + id: "composeFAB" +- inputText: "Test thread" +- tapOn: + id: "composerPublishBtn" + +# Login, reply to the thread, and log out +- tapOn: + id: "e2eSignInBob" +- tapOn: + id: "replyBtn" +- inputText: "Reply 1" +- tapOn: + id: "composerPublishBtn" + +# Login, confirm notification exists, mute thread, and log out +- tapOn: + id: "e2eSignInAlice" +- tapOn: + id: "bottomBarNotificationsBtn" +- assertVisible: + id: "feedItem-by-bob.test" +- tapOn: + id: "feedItem-by-bob.test" +- tapOn: + id: "postDropdownBtn" + childOf: + id: "postThreadItem-by-bob.test" +- tapOn: "Mute thread" + +# Login, reply to the thread twice, and log out +- tapOn: + id: "e2eSignInBob" +- tapOn: + id: "bottomBarProfileBtn" +- tapOn: + id: "profilePager-selector-1" +- tapOn: + id: "replyBtn" +- inputText: "Reply 2" +- tapOn: + id: "composerPublishBtn" +- tapOn: + id: "replyBtn" +- inputText: "Reply 3" +- tapOn: + id: "composerPublishBtn" + + +# Login, confirm notifications dont exist, unmute the thread, confirm notifications exist +- tapOn: + id: "e2eSignInAlice" +- tapOn: + id: "bottomBarNotificationsBtn" +- assertNotVisible: + id: "feedItem-by-bob.test" +- tapOn: + id: "bottomBarHomeBtn" +- tapOn: + id: "postDropdownBtn" +- tapOn: "Unmute thread" +- tapOn: + id: "bottomBarNotificationsBtn" +- swipe: + from: + id: "notifsFeed" + direction: DOWN +- assertVisible: + id: "feedItem-by-bob.test" diff --git a/__e2e__/flows/thread-screen.yml b/__e2e__/flows/thread-screen.yml new file mode 100644 index 000000000..22f71345d --- /dev/null +++ b/__e2e__/flows/thread-screen.yml @@ -0,0 +1,84 @@ +appId: xyz.blueskyweb.app +--- +- runScript: + file: ../setupServer.js + env: + SERVER_PATH: "?users&follows&thread" +- runFlow: + file: ../setupApp.yml +- tapOn: + id: "e2eSignInAlice" + + +# Navigate to thread +- tapOn: "Thread root" +- assertVisible: "Thread reply" + +# Can like the root post +- tapOn: + id: "likeBtn" + childOf: + id: "postThreadItem-by-bob.test" +- assertVisible: + id: "likeCount-expanded" +- tapOn: + id: "likeBtn" + childOf: + id: "postThreadItem-by-bob.test" +- assertNotVisible: + id: "likeCount-expanded" + +# Can like a reply post +- tapOn: + id: "likeBtn" + childOf: + id: "postThreadItem-by-carla.test" +- assertVisible: + id: "likeCount" + childOf: + id: "postThreadItem-by-carla.test" +- tapOn: + id: "likeBtn" + childOf: + id: "postThreadItem-by-carla.test" +- assertNotVisible: + id: "likeCount" + childOf: + id: "postThreadItem-by-carla.test" + +# Can repost the root post +- tapOn: + id: "repostBtn" + childOf: + id: "postThreadItem-by-bob.test" +- tapOn: "Repost" +- assertVisible: + id: "repostCount-expanded" +- tapOn: + id: "repostBtn" + childOf: + id: "postThreadItem-by-bob.test" +- tapOn: "Undo repost" +- assertNotVisible: + id: "repostCount-expanded" + + +# Can repost a reply post +- tapOn: + id: "repostBtn" + childOf: + id: "postThreadItem-by-carla.test" +- tapOn: "Repost" +- assertVisible: + id: "repostCount" + childOf: + id: "postThreadItem-by-carla.test" +- tapOn: + id: "repostBtn" + childOf: + id: "postThreadItem-by-carla.test" +- tapOn: "Undo repost" +- assertNotVisible: + id: "repostCount" + childOf: + id: "postThreadItem-by-carla.test" diff --git a/__e2e__/jest.config.js b/__e2e__/jest.config.js deleted file mode 100644 index 80c2ad5b3..000000000 --- a/__e2e__/jest.config.js +++ /dev/null @@ -1,12 +0,0 @@ -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - rootDir: '..', - testMatch: ['<rootDir>/__e2e__/**/*.test.ts'], - testTimeout: 120000, - maxWorkers: 1, - globalSetup: 'detox/runners/jest/globalSetup', - globalTeardown: 'detox/runners/jest/globalTeardown', - reporters: ['detox/runners/jest/reporter'], - testEnvironment: 'detox/runners/jest/testEnvironment', - verbose: true, -} diff --git a/__e2e__/maestro/scroll.yaml b/__e2e__/perf-test.yml index 2d32793eb..7a7b7a18c 100644 --- a/__e2e__/maestro/scroll.yaml +++ b/__e2e__/perf-test.yml @@ -1,3 +1,4 @@ + # flow.yaml appId: xyz.blueskyweb.app @@ -74,4 +75,3 @@ appId: xyz.blueskyweb.app - "scroll" - "scroll" - "scroll" - diff --git a/__e2e__/setupApp.yml b/__e2e__/setupApp.yml new file mode 100644 index 000000000..8c3ffd2d3 --- /dev/null +++ b/__e2e__/setupApp.yml @@ -0,0 +1,11 @@ +appId: xyz.blueskyweb.app +--- +- launchApp: + appId: "xyz.blueskyweb.app" + clearState: true +- waitForAnimationToEnd +- tapOn: "http://localhost:8081" +- waitForAnimationToEnd +- swipe: + from: "Bluesky" + direction: DOWN diff --git a/__e2e__/setupServer.js b/__e2e__/setupServer.js new file mode 100644 index 000000000..7b1fb9574 --- /dev/null +++ b/__e2e__/setupServer.js @@ -0,0 +1,5 @@ +// eslint-disable-next-line +http.post('http://localhost:1986/' + SERVER_PATH, { + headers: {'Content-Type': 'text/plain'}, + body: '', +}) diff --git a/__e2e__/tests/composer.test.ts b/__e2e__/tests/composer.test.ts deleted file mode 100644 index 06781410f..000000000 --- a/__e2e__/tests/composer.test.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* eslint-env detox/detox */ - -import {beforeAll, describe, it} from '@jest/globals' -import {expect} from 'detox' - -import {createServer, loginAsAlice, openApp, sleep} from '../util' - -describe('Composer', () => { - beforeAll(async () => { - await createServer('?users') - await openApp({ - permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'}, - }) - }) - - it('Login', async () => { - await loginAsAlice() - await element(by.id('homeScreenFeedTabs-Following')).tap() - }) - - it('Post text only', async () => { - await element(by.id('composeFAB')).tap() - await device.takeScreenshot('1- opened composer') - await element(by.id('composerTextInput')).typeText('Post text only') - await device.takeScreenshot('2- entered text') - await element(by.id('composerPublishBtn')).tap() - await device.takeScreenshot('3- opened general section') - await expect(element(by.id('composeFAB'))).toBeVisible() - }) - - it('Post with an image', async () => { - await element(by.id('composeFAB')).tap() - await element(by.id('composerTextInput')).typeText('Post with an image') - await element(by.id('openGalleryBtn')).tap() - await sleep(1e3) - await element(by.id('composerPublishBtn')).tap() - await expect(element(by.id('composeFAB'))).toBeVisible() - }) - - it('Post with a link card', async () => { - await element(by.id('composeFAB')).tap() - await element(by.id('composerTextInput')).typeText( - 'Post with a https://example.com link card', - ) - await element(by.id('composerPublishBtn')).tap() - await expect(element(by.id('composeFAB'))).toBeVisible() - }) - - it('Reply text only', async () => { - await element(by.id('e2eRefreshHome')).tap() - - const post = by.id('feedItem-by-alice.test') - await element(by.id('replyBtn').withAncestor(post)).atIndex(0).tap() - await element(by.id('composerTextInput')).typeText('Reply text only') - await element(by.id('composerPublishBtn')).tap() - await expect(element(by.id('composeFAB'))).toBeVisible() - }) - - it('Reply with an image', async () => { - const post = by.id('feedItem-by-alice.test') - await element(by.id('replyBtn').withAncestor(post)).atIndex(0).tap() - await element(by.id('composerTextInput')).typeText('Reply with an image') - await element(by.id('openGalleryBtn')).tap() - await sleep(1e3) - await element(by.id('composerPublishBtn')).tap() - await expect(element(by.id('composeFAB'))).toBeVisible() - }) - - it('Reply with a link card', async () => { - const post = by.id('feedItem-by-alice.test') - await element(by.id('replyBtn').withAncestor(post)).atIndex(0).tap() - await element(by.id('composerTextInput')).typeText( - 'Reply with a https://example.com link card', - ) - await element(by.id('composerPublishBtn')).tap() - await expect(element(by.id('composeFAB'))).toBeVisible() - }) - - it('QP text only', async () => { - const post = by.id('feedItem-by-alice.test') - await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap() - await element(by.id('quoteBtn').withAncestor(by.id('repostModal'))).tap() - await element(by.id('composerTextInput')).typeText('QP text only') - await element(by.id('composerPublishBtn')).tap() - await expect(element(by.id('composeFAB'))).toBeVisible() - }) - - it('QP with an image', async () => { - const post = by.id('feedItem-by-alice.test') - await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap() - await element(by.id('quoteBtn').withAncestor(by.id('repostModal'))).tap() - await element(by.id('composerTextInput')).typeText('QP with an image') - await element(by.id('openGalleryBtn')).tap() - await sleep(1e3) - await element(by.id('composerPublishBtn')).tap() - await expect(element(by.id('composeFAB'))).toBeVisible() - }) - - it('QP with a link card', async () => { - const post = by.id('feedItem-by-alice.test') - await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap() - await element(by.id('quoteBtn').withAncestor(by.id('repostModal'))).tap() - await element(by.id('composerTextInput')).typeText( - 'QP with a https://example.com link card', - ) - await element(by.id('composerPublishBtn')).tap() - await expect(element(by.id('composeFAB'))).toBeVisible() - }) -}) diff --git a/__e2e__/tests/create-account.test.ts b/__e2e__/tests/create-account.test.ts deleted file mode 100644 index 9c56c914e..000000000 --- a/__e2e__/tests/create-account.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* eslint-env detox/detox */ - -import {describe, beforeAll, it} from '@jest/globals' -import {expect} from 'detox' -import {openApp, createServer} from '../util' - -describe('Create account', () => { - let service: string - beforeAll(async () => { - service = await createServer('') - await openApp({permissions: {notifications: 'YES'}}) - }) - - it('I can create a new account', async () => { - await element(by.id('e2eOpenLoggedOutView')).tap() - - await element(by.id('createAccountButton')).tap() - await device.takeScreenshot('1- opened create account screen') - await element(by.id('selectServiceButton')).tap() - await device.takeScreenshot('2- selected other server') - await element(by.id('customSelectBtn')).tap() - await element(by.id('customServerTextInput')).typeText(service) - await element(by.id('customServerTextInput')).tapReturnKey() - await element(by.id('doneBtn')).tap() - await device.takeScreenshot('3- input test server URL') - 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('5- entered handle') - - await element(by.id('nextBtn')).tap() - - await expect(element(by.id('onboardingInterests'))).toBeVisible() - }) -}) diff --git a/__e2e__/tests/curate-lists.test.ts b/__e2e__/tests/curate-lists.test.ts deleted file mode 100644 index 635357b8d..000000000 --- a/__e2e__/tests/curate-lists.test.ts +++ /dev/null @@ -1,213 +0,0 @@ -/* eslint-env detox/detox */ - -import {beforeAll, describe, it} from '@jest/globals' -import {expect} from 'detox' - -import {createServer, loginAsAlice, loginAsBob, openApp, 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 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('Upload from 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 Avatar')).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('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('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 element(by.id('searchInput')).typeText('b') - 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 expect(element(by.id('pinBtn'))).toBeVisible() - 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('user-bob.test-addBtn')).tap() - await element(by.id('doneBtn')).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('profilePager-selector')).swipe('left') - await element(by.id('profilePager-selector-5')).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('user-bob.test-addBtn')).tap() - await element(by.id('doneBtn')).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('user-bob.test-addBtn')).tap() - await element(by.id('doneBtn')).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('profilePager-selector')).swipe('left') - await element(by.id('profilePager-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/home-screen.test.ts b/__e2e__/tests/home-screen.test.ts deleted file mode 100644 index b594c4697..000000000 --- a/__e2e__/tests/home-screen.test.ts +++ /dev/null @@ -1,110 +0,0 @@ -/* eslint-env detox/detox */ - -import {beforeAll, describe, it} from '@jest/globals' -import {expect} from 'detox' - -import {createServer, loginAsAlice, openApp} from '../util' - -describe('Home screen', () => { - beforeAll(async () => { - await createServer('?users&follows&posts&feeds') - await openApp({permissions: {notifications: 'YES'}}) - }) - - it('Login', async () => { - await loginAsAlice() - await element(by.id('homeScreenFeedTabs-Following')).tap() - }) - - it('Can go to feeds page using feeds button in tab bar', async () => { - await element(by.id('homeScreenFeedTabs-Feeds ✨')).tap() - await expect(element(by.text('Discover New Feeds'))).toBeVisible() - }) - - it('Feeds button disappears after pinning a feed', async () => { - await element(by.id('bottomBarProfileBtn')).tap() - await element(by.id('profilePager-selector')).swipe('left') - await element(by.id('profilePager-selector-4')).tap() - await element(by.id('feed-alice-favs')).tap() - await element(by.id('pinBtn')).tap() - await element(by.id('bottomBarHomeBtn')).tap() - await expect( - element(by.id('homeScreenFeedTabs-Feeds ✨')), - ).not.toBeVisible() - }) - - it('Can like posts', async () => { - const carlaPosts = by.id('feedItem-by-carla.test') - await expect( - element(by.id('likeCount').withAncestor(carlaPosts)).atIndex(0), - ).not.toExist() - await element(by.id('likeBtn').withAncestor(carlaPosts)).atIndex(0).tap() - await expect( - element(by.id('likeCount').withAncestor(carlaPosts)).atIndex(0), - ).toHaveText('1') - await element(by.id('likeBtn').withAncestor(carlaPosts)).atIndex(0).tap() - await expect( - element(by.id('likeCount').withAncestor(carlaPosts)).atIndex(0), - ).not.toExist() - }) - - it('Can repost posts', async () => { - const carlaPosts = by.id('feedItem-by-carla.test') - await expect( - element(by.id('repostCount').withAncestor(carlaPosts)).atIndex(0), - ).not.toExist() - await element(by.id('repostBtn').withAncestor(carlaPosts)).atIndex(0).tap() - await expect(element(by.id('repostModal'))).toBeVisible() - await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap() - await expect(element(by.id('repostModal'))).not.toBeVisible() - await expect( - element(by.id('repostCount').withAncestor(carlaPosts)).atIndex(0), - ).toHaveText('1') - await element(by.id('repostBtn').withAncestor(carlaPosts)).atIndex(0).tap() - await expect(element(by.id('repostModal'))).toBeVisible() - await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap() - await expect(element(by.id('repostModal'))).not.toBeVisible() - await expect( - element(by.id('repostCount').withAncestor(carlaPosts)).atIndex(0), - ).not.toExist() - }) - - // TODO skipping because the test env PDS isnt setup correctly to handle the report -prf - // it('Can report posts', async () => { - // const carlaPosts = by.id('feedItem-by-carla.test') - // await element(by.id('postDropdownBtn').withAncestor(carlaPosts)) - // .atIndex(0) - // .tap() - // await element(by.text('Report post')).tap() - // await element(by.id('com.atproto.moderation.defs#reasonSpam')).tap() - // await element(by.id('sendReportBtn')).tap() - // }) - - it('Can swipe between feeds', async () => { - await element(by.id('homeScreen')).swipe('left', 'fast', 0.75) - await expect(element(by.id('customFeedPage'))).toBeVisible() - await element(by.id('homeScreen')).swipe('right', 'fast', 0.75) - await expect(element(by.id('followingFeedPage'))).toBeVisible() - }) - - it('Can tap between feeds', async () => { - await element(by.id('homeScreenFeedTabs-alice-favs')).tap() - await expect(element(by.id('customFeedPage'))).toBeVisible() - await element(by.id('homeScreenFeedTabs-Following')).tap() - await expect(element(by.id('followingFeedPage'))).toBeVisible() - }) - - it('Can delete posts', async () => { - const alicePosts = by.id('feedItem-by-alice.test') - await expect(element(alicePosts.withDescendant(by.text('Post')))).toExist() - await element(by.id('postDropdownBtn').withAncestor(alicePosts)) - .atIndex(0) - .tap() - await element(by.text('Delete post')).tap() - await expect(element(by.id('confirmModal'))).toBeVisible() - await element(by.id('confirmBtn')).tap() - await expect( - element(alicePosts.withDescendant(by.text('Post'))), - ).not.toExist() - }) -}) diff --git a/__e2e__/tests/invite-codes.test.skip.ts b/__e2e__/tests/invite-codes.test.skip.ts deleted file mode 100644 index 9f00f0525..000000000 --- a/__e2e__/tests/invite-codes.test.skip.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* eslint-env detox/detox */ - -import {beforeAll, describe, it} from '@jest/globals' -import {expect} from 'detox' - -import {createServer, loginAsAlice, openApp} 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 loginAsAlice() - await element(by.id('e2eOpenInviteCodesModal')).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('e2eSignOut')).tap() - }) - - it('I can create a new account with the invite code', async () => { - await element(by.id('e2eOpenLoggedOutView')).tap() - await element(by.id('createAccountButton')).tap() - await device.takeScreenshot('1- opened create account screen') - await element(by.id('selectServiceButton')).tap() - await device.takeScreenshot('2- selected other server') - await element(by.id('customSelectBtn')).tap() - await element(by.id('customServerTextInput')).typeText(service) - await element(by.id('customServerTextInput')).tapReturnKey() - await element(by.id('doneBtn')).tap() - await device.takeScreenshot('3- input test server URL') - 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('onboardingInterests'))).toBeVisible() - }) -}) diff --git a/__e2e__/tests/login.test.ts b/__e2e__/tests/login.test.ts deleted file mode 100644 index b4cedef6c..000000000 --- a/__e2e__/tests/login.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-env detox/detox */ - -import {describe, beforeAll, it} from '@jest/globals' -import {expect} from 'detox' -import {openApp, login, createServer} from '../util' - -describe('Login', () => { - let service: string - beforeAll(async () => { - service = await createServer('?users') - await openApp({permissions: {notifications: 'YES'}}) - }) - - it('As Alice, I can login', async () => { - await element(by.id('e2eOpenLoggedOutView')).tap() - - await expect(element(by.id('signInButton'))).toBeVisible() - await login(service, 'alice', 'hunter2', { - takeScreenshots: true, - }) - await device.takeScreenshot('5- opened home screen') - }) -}) diff --git a/__e2e__/tests/merge-feed.test.skip.ts b/__e2e__/tests/merge-feed.test.skip.ts deleted file mode 100644 index 4a8b3cbce..000000000 --- a/__e2e__/tests/merge-feed.test.skip.ts +++ /dev/null @@ -1,163 +0,0 @@ -/* eslint-env detox/detox */ - -import {describe, beforeAll, it} from '@jest/globals' -import {expect} from 'detox' -import {openApp, loginAsAlice, createServer} from '../util' - -describe('Mergefeed', () => { - beforeAll(async () => { - await createServer('?mergefeed') - await openApp({permissions: {notifications: 'YES'}}) - }) - - it('Login', async () => { - await element(by.id('e2eOpenLoggedOutView')).tap() - await loginAsAlice() - await element(by.id('e2eToggleMergefeed')).tap() - await element(by.id('bottomBarFeedsBtn')).tap() - await element(by.id('feed-alice-favs-toggleSave')).tap() - await element(by.id('e2eGotoHome')).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/mod-lists.test.ts b/__e2e__/tests/mod-lists.test.ts deleted file mode 100644 index c3d4149e0..000000000 --- a/__e2e__/tests/mod-lists.test.ts +++ /dev/null @@ -1,189 +0,0 @@ -/* eslint-env detox/detox */ - -import {describe, beforeAll, it} from '@jest/globals' -import {expect} from 'detox' -import {openApp, loginAsAlice, loginAsBob, createServer} from '../util' - -describe('Mod lists', () => { - beforeAll(async () => { - await createServer('?users&follows&labels') - await openApp({ - permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'}, - }) - }) - - it('Login and view my modlists', async () => { - await loginAsAlice() - await element(by.id('e2eGotoModeration')).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( - element(by.id('user-muted-by-list-account.test')), - ).toBeVisible() - }) - - 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 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('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 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('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) - }) - - // DISABLED e2e environment is real finicky about avatar uploads -prf - // it('Set avi via the edit modlist 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 modlist 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 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('listsEmpty'))).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('createOrEditListModal'))).not.toBeVisible() - await expect(element(by.id('headerTitle'))).toHaveText('Bad Ppl') - await expect(element(by.id('listDescription'))).toHaveText('They bad') - }) - - 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('user-warn-posts.test-addBtn')).tap() - await element(by.id('doneBtn')).tap() - await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible() - }) - - it('Shows the modlist on my profile', async () => { - await element(by.id('bottomBarProfileBtn')).tap() - await element(by.id('profilePager-selector')).swipe('left') - await element(by.id('profilePager-selector-5')).tap() - await element(by.id('list-Bad Ppl')).tap() - }) - - 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() - 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('user-bob.test-addBtn')).tap() - await element(by.id('doneBtn')).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('user-bob.test-addBtn')).tap() - await element(by.id('doneBtn')).tap() - await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible() - }) - - it('Can report a mute 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('profilePager-selector')).swipe('left') - await element(by.id('profilePager-selector-3')).tap() - await element(by.id('list-Bad 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/profile-screen.test.ts b/__e2e__/tests/profile-screen.test.ts deleted file mode 100644 index 7c3207ec8..000000000 --- a/__e2e__/tests/profile-screen.test.ts +++ /dev/null @@ -1,196 +0,0 @@ -/* eslint-env detox/detox */ - -import {beforeAll, describe, it} from '@jest/globals' -import {expect} from 'detox' - -import {createServer, loginAsAlice, openApp, sleep} from '../util' - -describe('Profile screen', () => { - beforeAll(async () => { - await createServer('?users&posts&feeds') - await openApp({ - permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'}, - }) - }) - - it('Login and navigate to my profile', async () => { - await loginAsAlice() - await element(by.id('bottomBarProfileBtn')).tap() - }) - - it('Can see feeds', async () => { - await element(by.id('profilePager-selector')).swipe('left') - await element(by.id('profilePager-selector-4')).tap() - await expect(element(by.id('feed-alice-favs'))).toBeVisible() - await element(by.id('profilePager-selector')).swipe('right') - await element(by.id('profilePager-selector-0')).tap() - }) - - it('Open and close edit profile modal', async () => { - await element(by.id('profileHeaderEditProfileButton')).tap() - await expect(element(by.id('editProfileModal'))).toBeVisible() - await element(by.id('editProfileCancelBtn')).tap() - await expect(element(by.id('editProfileModal'))).not.toBeVisible() - }) - - it('Edit display name and description via the edit profile modal', async () => { - await element(by.id('profileHeaderEditProfileButton')).tap() - await expect(element(by.id('editProfileModal'))).toBeVisible() - await element(by.id('editProfileDisplayNameInput')).clearText() - await element(by.id('editProfileDisplayNameInput')).typeText('Alicia') - await element(by.id('editProfileDescriptionInput')).clearText() - await element(by.id('editProfileDescriptionInput')).typeText( - 'One cool hacker', - ) - await element(by.id('editProfileSaveBtn')).tap() - await expect(element(by.id('editProfileModal'))).not.toBeVisible() - await expect(element(by.id('profileHeaderDisplayName'))).toHaveText( - 'Alicia', - ) - await expect(element(by.id('profileHeaderDescription'))).toHaveText( - 'One cool hacker', - ) - }) - - it('Remove display name and description via the edit profile modal', async () => { - await element(by.id('profileHeaderEditProfileButton')).tap() - await expect(element(by.id('editProfileModal'))).toBeVisible() - await element(by.id('editProfileDisplayNameInput')).clearText() - await element(by.id('editProfileDescriptionInput')).clearText() - await element(by.id('editProfileSaveBtn')).tap() - await expect(element(by.id('editProfileModal'))).not.toBeVisible() - await expect(element(by.id('profileHeaderDisplayName'))).toHaveText( - 'alice.test', - ) - await expect(element(by.id('profileHeaderDescription'))).not.toExist() - }) - - it('Set avi and banner via the edit profile modal', async () => { - await expect(element(by.id('userBannerFallback'))).toExist() - await expect(element(by.id('userAvatarFallback'))).toExist() - await element(by.id('profileHeaderEditProfileButton')).tap() - await expect(element(by.id('editProfileModal'))).toBeVisible() - await element(by.id('changeBannerBtn')).tap() - await element(by.text('Upload from Library')).tap() - await sleep(3e3) - await element(by.id('changeAvatarBtn')).tap() - await element(by.text('Upload from Library')).tap() - await sleep(3e3) - await element(by.id('editProfileSaveBtn')).tap() - await expect(element(by.id('editProfileModal'))).not.toBeVisible() - await expect(element(by.id('userBannerImage'))).toExist() - await expect(element(by.id('userAvatarImage'))).toExist() - }) - - it('Remove avi and banner via the edit profile modal', async () => { - await expect(element(by.id('userBannerImage'))).toExist() - await expect(element(by.id('userAvatarImage'))).toExist() - await element(by.id('profileHeaderEditProfileButton')).tap() - await expect(element(by.id('editProfileModal'))).toBeVisible() - await element(by.id('changeBannerBtn')).tap() - await element(by.text('Remove Banner')).tap() - await element(by.id('changeAvatarBtn')).tap() - await element(by.text('Remove Avatar')).tap() - await element(by.id('editProfileSaveBtn')).tap() - await expect(element(by.id('editProfileModal'))).not.toBeVisible() - await expect(element(by.id('userBannerFallback'))).toExist() - await expect(element(by.id('userAvatarFallback'))).toExist() - }) - - it('Navigate to another user profile', async () => { - await element(by.id('bottomBarSearchBtn')).tap() - // have to wait for the toast to clear - await waitFor(element(by.id('searchTextInput'))) - .toBeVisible() - .withTimeout(5000) - await element(by.id('searchTextInput')).typeText('bob') - await element(by.id('searchAutoCompleteResult-bob.test')).tap() - await expect(element(by.id('profileView'))).toBeVisible() - }) - - it('Can follow/unfollow another user', async () => { - await element(by.id('followBtn')).tap() - await expect(element(by.id('unfollowBtn'))).toBeVisible() - await element(by.id('unfollowBtn')).tap() - await expect(element(by.id('followBtn'))).toBeVisible() - }) - - it('Can mute/unmute another user', async () => { - await expect(element(by.id('profileHeaderAlert'))).not.toExist() - await element(by.id('profileHeaderDropdownBtn')).tap() - await element(by.text('Mute Account')).tap() - await expect(element(by.id('profileHeaderAlert'))).toBeVisible() - await element(by.id('profileHeaderDropdownBtn')).tap() - await element(by.text('Unmute Account')).tap() - await expect(element(by.id('profileHeaderAlert'))).not.toExist() - }) - - // TODO skipping because the test env PDS isnt setup correctly to handle the report -prf - // it('Can report another user', async () => { - // await element(by.id('profileHeaderDropdownBtn')).tap() - // await element(by.text('Report Account')).tap() - // await expect(element(by.id('reportModal'))).toBeVisible() - // await element( - // by.id('reportReasonRadios-com.atproto.moderation.defs#reasonSpam'), - // ).tap() - // await element(by.id('sendReportBtn')).tap() - // await expect(element(by.id('reportModal'))).not.toBeVisible() - // }) - - it('Can like posts', async () => { - await element(by.id('postsFeed-flatlist')).swipe( - 'down', - 'slow', - 1, - 0.5, - 0.5, - ) - - const posts = by.id('feedItem-by-bob.test') - await expect( - element(by.id('likeCount').withAncestor(posts)).atIndex(0), - ).not.toExist() - await element(by.id('likeBtn').withAncestor(posts)).atIndex(0).tap() - await expect( - element(by.id('likeCount').withAncestor(posts)).atIndex(0), - ).toHaveText('1') - await element(by.id('likeBtn').withAncestor(posts)).atIndex(0).tap() - await expect( - element(by.id('likeCount').withAncestor(posts)).atIndex(0), - ).not.toExist() - }) - - it('Can repost posts', async () => { - const posts = by.id('feedItem-by-bob.test') - await expect( - element(by.id('repostCount').withAncestor(posts)).atIndex(0), - ).not.toExist() - await element(by.id('repostBtn').withAncestor(posts)).atIndex(0).tap() - await expect(element(by.id('repostModal'))).toBeVisible() - await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap() - await expect(element(by.id('repostModal'))).not.toBeVisible() - await expect( - element(by.id('repostCount').withAncestor(posts)).atIndex(0), - ).toHaveText('1') - await element(by.id('repostBtn').withAncestor(posts)).atIndex(0).tap() - await expect(element(by.id('repostModal'))).toBeVisible() - await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap() - await expect(element(by.id('repostModal'))).not.toBeVisible() - await expect( - element(by.id('repostCount').withAncestor(posts)).atIndex(0), - ).not.toExist() - }) - - // TODO skipping because the test env PDS isnt setup correctly to handle the report -prf - // it('Can report posts', async () => { - // const posts = by.id('feedItem-by-bob.test') - // await element(by.id('postDropdownBtn').withAncestor(posts)).atIndex(0).tap() - // await element(by.text('Report post')).tap() - // await expect(element(by.id('reportModal'))).toBeVisible() - // await element( - // by.id('reportReasonRadios-com.atproto.moderation.defs#reasonSpam'), - // ).tap() - // await element(by.id('sendReportBtn')).tap() - // await expect(element(by.id('reportModal'))).not.toBeVisible() - // }) -}) diff --git a/__e2e__/tests/search-screen.test.ts b/__e2e__/tests/search-screen.test.ts deleted file mode 100644 index 1dbb3cbfa..000000000 --- a/__e2e__/tests/search-screen.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* eslint-env detox/detox */ - -import {describe, beforeAll, it} from '@jest/globals' -import {expect} from 'detox' -import {openApp, loginAsAlice, createServer} from '../util' - -describe('Search screen', () => { - beforeAll(async () => { - await createServer('?users') - await openApp({ - permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'}, - }) - }) - - it('Login', async () => { - await loginAsAlice() - }) - - it('Navigate to another user profile via autocomplete', 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() - }) -}) diff --git a/__e2e__/tests/self-labeling.test.ts b/__e2e__/tests/self-labeling.test.ts deleted file mode 100644 index bba8ed484..000000000 --- a/__e2e__/tests/self-labeling.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* eslint-env detox/detox */ - -import {describe, beforeAll, it} from '@jest/globals' -import {expect} from 'detox' -import {openApp, loginAsAlice, createServer, sleep} from '../util' - -describe('Self-labeling', () => { - beforeAll(async () => { - await createServer('?users') - await openApp({ - permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'}, - }) - }) - - it('Login', async () => { - await loginAsAlice() - await element(by.id('homeScreenFeedTabs-Following')).tap() - }) - - it('Post an image with the porn label', async () => { - await element(by.id('composeFAB')).tap() - await element(by.id('composerTextInput')).typeText('Post with an image') - await element(by.id('openGalleryBtn')).tap() - await sleep(3e3) - await element(by.id('labelsBtn')).tap() - await element(by.id('pornLabelBtn')).tap() - await element(by.id('confirmBtn')).tap() - await element(by.id('composerPublishBtn')).tap() - await expect(element(by.id('composeFAB'))).toBeVisible() - const posts = by.id('feedItem-by-alice.test') - await element(by.id('e2eRefreshHome')).tap() - await expect( - element(by.id('contentHider-embed').withAncestor(posts)).atIndex(0), - ).toExist() - }) -}) diff --git a/__e2e__/tests/shell.test.skip.ts b/__e2e__/tests/shell.test.skip.ts deleted file mode 100644 index 69619dd81..000000000 --- a/__e2e__/tests/shell.test.skip.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* eslint-env detox/detox */ - -import {openApp, loginAsAlice, createServer} from '../util' - -describe('Shell', () => { - beforeAll(async () => { - await createServer('?users') - await openApp({permissions: {notifications: 'YES'}}) - }) - - it('Login', async () => { - await loginAsAlice() - await element(by.id('homeScreenFeedTabs-Following')).tap() - }) - - it('Can swipe the shelf open', async () => { - await element(by.id('homeScreen')).swipe('right', 'fast', 0.75) - await expect(element(by.id('drawer'))).toBeVisible() - await element(by.id('drawer')).swipe('left', 'fast', 0.75) - await expect(element(by.id('drawer'))).not.toBeVisible() - }) - - it('Can open the shelf by pressing the header avi', async () => { - await element(by.id('viewHeaderDrawerBtn')).tap() - await expect(element(by.id('drawer'))).toBeVisible() - }) - - it('Can navigate using the shelf', async () => { - await element(by.id('menuItemButton-Notifications')).tap() - await expect(element(by.id('drawer'))).not.toBeVisible() - await expect(element(by.id('notificationsScreen'))).toBeVisible() - }) -}) diff --git a/__e2e__/tests/thread-muting.test.ts b/__e2e__/tests/thread-muting.test.ts deleted file mode 100644 index ae62f93dc..000000000 --- a/__e2e__/tests/thread-muting.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* eslint-env detox/detox */ - -import {describe, beforeAll, it} from '@jest/globals' -import {expect} from 'detox' -import {openApp, loginAsAlice, loginAsBob, createServer} from '../util' - -describe('Thread muting', () => { - beforeAll(async () => { - await createServer('?users&follows') - await openApp({permissions: {notifications: 'YES'}}) - }) - - it('Login, create a thread, and log out', async () => { - 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() - }) - - it('Login, reply to the thread, and log out', async () => { - 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() - }) - - it('Login, confirm notification exists, mute thread, and log out', async () => { - await loginAsAlice() - await element(by.id('bottomBarNotificationsBtn')).tap() - const bobNotifs = by.id('feedItem-by-bob.test') - await expect( - element(by.id('postText').withAncestor(bobNotifs)).atIndex(0), - ).toHaveText('Reply 1') - await element(by.id('postDropdownBtn').withAncestor(bobNotifs)) - .atIndex(0) - .tap() - await element(by.text('Mute thread')).tap() - // have to wait for the toast to clear - await waitFor(element(by.id('viewHeaderDrawerBtn'))) - .toBeVisible() - .withTimeout(5000) - }) - - it('Login, reply to the thread twice, and log out', async () => { - await loginAsBob() - - await element(by.id('bottomBarProfileBtn')).tap() - await element(by.id('profilePager-selector-1')).tap() - const bobPosts = by.id('feedItem-by-bob.test') - await element(by.id('replyBtn').withAncestor(bobPosts)).atIndex(0).tap() - await element(by.id('composerTextInput')).typeText('Reply 2') - await element(by.id('composerPublishBtn')).tap() - await expect(element(by.id('composeFAB'))).toBeVisible() - - 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 3') - await element(by.id('composerPublishBtn')).tap() - await expect(element(by.id('composeFAB'))).toBeVisible() - - await element(by.id('bottomBarHomeBtn')).tap() - }) - - it('Login, confirm notifications dont exist, unmute the thread, confirm notifications exist', async () => { - await loginAsAlice() - - await element(by.id('bottomBarNotificationsBtn')).tap() - const bobNotifs = by.id('feedItem-by-bob.test') - await expect( - element(by.id('postText').withAncestor(bobNotifs)).atIndex(0), - ).not.toExist() - - await element(by.id('bottomBarHomeBtn')).tap() - const alicePosts = by.id('feedItem-by-alice.test') - await element(by.id('postDropdownBtn').withAncestor(alicePosts)) - .atIndex(0) - .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 - // -prf - // await element(by.id('bottomBarNotificationsBtn')).tap() - // await element(by.id('notifsFeed')).swipe('down', 'fast') - // await waitFor(element(by.id('postText').withAncestor(bobNotifs))) - // .toBeVisible() - // .withTimeout(5000) - // await expect( - // element(by.id('postText').withAncestor(bobNotifs)).atIndex(0), - // ).toHaveText('Reply 2') - // await expect( - // element(by.id('postText').withAncestor(bobNotifs)).atIndex(1), - // ).toHaveText('Reply 3') - // await expect( - // element(by.id('postText').withAncestor(bobNotifs)).atIndex(2), - // ).toHaveText('Reply 1') - }) -}) diff --git a/__e2e__/tests/thread-screen.test.ts b/__e2e__/tests/thread-screen.test.ts deleted file mode 100644 index b99da11a6..000000000 --- a/__e2e__/tests/thread-screen.test.ts +++ /dev/null @@ -1,131 +0,0 @@ -/* eslint-env detox/detox */ - -import {beforeAll, describe, it} from '@jest/globals' -import {expect} from 'detox' - -import {createServer, loginAsAlice, openApp} from '../util' - -describe('Thread screen', () => { - beforeAll(async () => { - await createServer('?users&follows&thread') - await openApp({permissions: {notifications: 'YES'}}) - }) - - it('Login & navigate to thread', async () => { - await loginAsAlice() - await element(by.id('homeScreenFeedTabs-Following')).tap() - await element(by.id('feedItem-by-bob.test')).atIndex(0).tap() - await expect( - element( - by - .id('postThreadItem-by-bob.test') - .withDescendant(by.text('Thread root')), - ), - ).toBeVisible() - await expect( - element( - by - .id('postThreadItem-by-carla.test') - .withDescendant(by.text('Thread reply')), - ), - ).toBeVisible() - }) - - it('Can like the root post', async () => { - const post = by.id('postThreadItem-by-bob.test') - await expect( - element(by.id('likeCount-expanded').withAncestor(post)).atIndex(0), - ).not.toExist() - await element(by.id('likeBtn').withAncestor(post)).atIndex(0).tap() - await expect( - element(by.id('likeCount-expanded').withAncestor(post)).atIndex(0), - ).toHaveText('1 like') - await element(by.id('likeBtn').withAncestor(post)).atIndex(0).tap() - await expect( - element(by.id('likeCount-expanded').withAncestor(post)).atIndex(0), - ).not.toExist() - }) - - it('Can like a reply post', async () => { - const post = by.id('postThreadItem-by-carla.test') - await expect( - element(by.id('likeCount').withAncestor(post)).atIndex(0), - ).not.toExist() - await element(by.id('likeBtn').withAncestor(post)).atIndex(0).tap() - await expect( - element(by.id('likeCount').withAncestor(post)).atIndex(0), - ).toHaveText('1') - await element(by.id('likeBtn').withAncestor(post)).atIndex(0).tap() - await expect( - element(by.id('likeCount').withAncestor(post)).atIndex(0), - ).not.toExist() - }) - - it('Can repost the root post', async () => { - const post = by.id('postThreadItem-by-bob.test') - await expect( - element(by.id('repostCount-expanded').withAncestor(post)).atIndex(0), - ).not.toExist() - await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap() - await expect(element(by.id('repostModal'))).toBeVisible() - await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap() - await expect(element(by.id('repostModal'))).not.toBeVisible() - await expect( - element(by.id('repostCount-expanded').withAncestor(post)).atIndex(0), - ).toHaveText('1 repost') - await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap() - await expect(element(by.id('repostModal'))).toBeVisible() - await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap() - await expect(element(by.id('repostModal'))).not.toBeVisible() - await expect( - element(by.id('repostCount-expanded').withAncestor(post)).atIndex(0), - ).not.toExist() - }) - - it('Can repost a reply post', async () => { - const post = by.id('postThreadItem-by-carla.test') - await expect( - element(by.id('repostCount').withAncestor(post)).atIndex(0), - ).not.toExist() - await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap() - await expect(element(by.id('repostModal'))).toBeVisible() - await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap() - await expect(element(by.id('repostModal'))).not.toBeVisible() - await expect( - element(by.id('repostCount').withAncestor(post)).atIndex(0), - ).toHaveText('1') - await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap() - await expect(element(by.id('repostModal'))).toBeVisible() - await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap() - await expect(element(by.id('repostModal'))).not.toBeVisible() - await expect( - element(by.id('repostCount').withAncestor(post)).atIndex(0), - ).not.toExist() - }) - - // TODO skipping because the test env PDS isnt setup correctly to handle the report -prf - // it('Can report the root post', async () => { - // const post = by.id('postThreadItem-by-bob.test') - // await element(by.id('postDropdownBtn').withAncestor(post)).atIndex(0).tap() - // await element(by.text('Report post')).tap() - // await expect(element(by.id('reportModal'))).toBeVisible() - // await element( - // by.id('reportReasonRadios-com.atproto.moderation.defs#reasonSpam'), - // ).tap() - // await element(by.id('sendReportBtn')).tap() - // await expect(element(by.id('reportModal'))).not.toBeVisible() - // }) - - // TODO skipping because the test env PDS isnt setup correctly to handle the report -prf - // it('Can report a reply post', async () => { - // const post = by.id('postThreadItem-by-carla.test') - // await element(by.id('postDropdownBtn').withAncestor(post)).atIndex(0).tap() - // await element(by.text('Report post')).tap() - // await expect(element(by.id('reportModal'))).toBeVisible() - // await element( - // by.id('reportReasonRadios-com.atproto.moderation.defs#reasonSpam'), - // ).tap() - // await element(by.id('sendReportBtn')).tap() - // await expect(element(by.id('reportModal'))).not.toBeVisible() - // }) -}) diff --git a/__e2e__/util.ts b/__e2e__/util.ts deleted file mode 100644 index 70fbdb601..000000000 --- a/__e2e__/util.ts +++ /dev/null @@ -1,141 +0,0 @@ -import {execSync} from 'child_process' -import {resolveConfig} from 'detox/internals' -import http from 'http' - -const platform = device.getPlatform() - -export async function openApp(opts: any) { - opts = opts || {} - const config = await resolveConfig() - - if (device.getPlatform() === 'ios') { - // disable password autofill - execSync( - `plutil -replace restrictedBool.allowPasswordAutoFill.value -bool NO ~/Library/Developer/CoreSimulator/Devices/${device.id}/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles/Library/ConfigurationProfiles/UserSettings.plist`, - ) - execSync( - `plutil -replace restrictedBool.allowPasswordAutoFill.value -bool NO ~/Library/Developer/CoreSimulator/Devices/${device.id}/data/Library/UserConfigurationProfiles/EffectiveUserSettings.plist`, - ) - execSync( - `plutil -replace restrictedBool.allowPasswordAutoFill.value -bool NO ~/Library/Developer/CoreSimulator/Devices/${device.id}/data/Library/UserConfigurationProfiles/PublicInfo/PublicEffectiveUserSettings.plist`, - ) - } - if (config.configurationName.split('.').includes('debug')) { - return await openAppForDebugBuild(platform, opts) - } else { - return await device.launchApp({ - ...opts, - newInstance: true, - }) - } -} - -export async function isVisible(id: string) { - try { - await expect(element(by.id(id))).toBeVisible() - return true - } catch (e) { - return false - } -} - -export async function login( - service: string, - username: string, - password: string, - {takeScreenshots} = {takeScreenshots: false}, -) { - await element(by.id('signInButton')).tap() - if (takeScreenshots) { - await device.takeScreenshot('1- opened sign-in screen') - } - if (await isVisible('chooseAccountForm')) { - await element(by.id('chooseNewAccountBtn')).tap() - } - await element(by.id('selectServiceButton')).tap() - if (takeScreenshots) { - await device.takeScreenshot('2- opened service selector') - } - await element(by.id('customSelectBtn')).tap() - await element(by.id('customServerTextInput')).typeText(service) - await element(by.id('customServerTextInput')).tapReturnKey() - await element(by.id('doneBtn')).tap() - if (takeScreenshots) { - await device.takeScreenshot('3- input custom service') - } - await element(by.id('loginUsernameInput')).typeText(username) - await element(by.id('loginPasswordInput')).typeText(password) - if (takeScreenshots) { - await device.takeScreenshot('4- entered username and password') - } - await element(by.id('loginNextButton')).tap() -} - -export async function loginAsAlice() { - await element(by.id('e2eSignInAlice')).tap() -} - -export async function loginAsBob() { - await element(by.id('e2eSignInBob')).tap() -} - -async function openAppForDebugBuild(platform: string, opts: any) { - const deepLinkUrl = // Local testing with packager - /*process.env.EXPO_USE_UPDATES - ? // Testing latest published EAS update for the test_debug channel - getDeepLinkUrl(getLatestUpdateUrl()) - : */ getDeepLinkUrl(getDevLauncherPackagerUrl(platform)) - - if (platform === 'ios') { - await device.launchApp({ - ...opts, - newInstance: true, - }) - sleep(3000) - await device.openURL({ - url: deepLinkUrl, - }) - } else { - await device.launchApp({ - ...opts, - newInstance: true, - url: deepLinkUrl, - }) - } - - await sleep(3000) -} - -export async function createServer(path = ''): Promise<string> { - return new Promise(function (resolve, reject) { - var req = http.request( - { - method: 'POST', - host: 'localhost', - port: 1986, - path: `/${path}`, - }, - function (res) { - const body: Buffer[] = [] - res.on('data', chunk => body.push(chunk)) - res.on('end', function () { - try { - resolve(Buffer.concat(body).toString()) - } catch (e) { - reject(e) - } - }) - }, - ) - req.on('error', reject) - req.end() - }) -} - -const getDeepLinkUrl = (url: string) => - `expo+bluesky://expo-development-client/?url=${encodeURIComponent(url)}` - -const getDevLauncherPackagerUrl = (platform: string) => - `http://localhost:8081/index.bundle?platform=${platform}&dev=true&minify=false&disableOnboarding=1` - -export const sleep = (t: number) => new Promise(res => setTimeout(res, t)) |