Replace e2e tests with Maestro (#3983)
* Setup maestro tests and convert some initial tests * Remove detox * Replace all tests with maestrozio/stable
parent
5cd4ac3a34
commit
d49b93dc7e
86
.detoxrc.js
86
.detoxrc.js
|
@ -1,86 +0,0 @@
|
||||||
/** @type {Detox.DetoxConfig} */
|
|
||||||
module.exports = {
|
|
||||||
testRunner: {
|
|
||||||
args: {
|
|
||||||
$0: 'jest',
|
|
||||||
config: '__e2e__/jest.config.js',
|
|
||||||
},
|
|
||||||
jest: {
|
|
||||||
setupTimeout: 120000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
apps: {
|
|
||||||
'ios.debug': {
|
|
||||||
type: 'ios.app',
|
|
||||||
binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/bluesky.app',
|
|
||||||
build:
|
|
||||||
'xcodebuild -workspace ios/Bluesky.xcworkspace -scheme Bluesky -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build',
|
|
||||||
},
|
|
||||||
'ios.release': {
|
|
||||||
type: 'ios.app',
|
|
||||||
binaryPath:
|
|
||||||
'ios/build/Build/Products/Release-iphonesimulator/bluesky.app',
|
|
||||||
build:
|
|
||||||
'xcodebuild -workspace ios/Bluesky.xcworkspace -scheme Bluesky -configuration Release -sdk iphonesimulator -derivedDataPath ios/build',
|
|
||||||
},
|
|
||||||
'android.debug': {
|
|
||||||
type: 'android.apk',
|
|
||||||
binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk',
|
|
||||||
build:
|
|
||||||
'cd android ; ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug ; cd -',
|
|
||||||
reversePorts: [8081],
|
|
||||||
},
|
|
||||||
'android.release': {
|
|
||||||
type: 'android.apk',
|
|
||||||
binaryPath: 'android/app/build/outputs/apk/release/app-release.apk',
|
|
||||||
build:
|
|
||||||
'cd android ; ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release ; cd -',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
devices: {
|
|
||||||
simulator: {
|
|
||||||
type: 'ios.simulator',
|
|
||||||
device: {
|
|
||||||
type: 'iPhone 15 Pro',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
attached: {
|
|
||||||
type: 'android.attached',
|
|
||||||
device: {
|
|
||||||
adbName: '.*',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emulator: {
|
|
||||||
type: 'android.emulator',
|
|
||||||
device: {
|
|
||||||
avdName: 'Pixel_3a_API_30_x86',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
configurations: {
|
|
||||||
'ios.sim.debug': {
|
|
||||||
device: 'simulator',
|
|
||||||
app: 'ios.debug',
|
|
||||||
},
|
|
||||||
'ios.sim.release': {
|
|
||||||
device: 'simulator',
|
|
||||||
app: 'ios.release',
|
|
||||||
},
|
|
||||||
'android.att.debug': {
|
|
||||||
device: 'attached',
|
|
||||||
app: 'android.debug',
|
|
||||||
},
|
|
||||||
'android.att.release': {
|
|
||||||
device: 'attached',
|
|
||||||
app: 'android.release',
|
|
||||||
},
|
|
||||||
'android.emu.debug': {
|
|
||||||
device: 'emulator',
|
|
||||||
app: 'android.debug',
|
|
||||||
},
|
|
||||||
'android.emu.release': {
|
|
||||||
device: 'emulator',
|
|
||||||
app: 'android.release',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -9,7 +9,6 @@ module.exports = {
|
||||||
parser: '@typescript-eslint/parser',
|
parser: '@typescript-eslint/parser',
|
||||||
plugins: [
|
plugins: [
|
||||||
'@typescript-eslint',
|
'@typescript-eslint',
|
||||||
'detox',
|
|
||||||
'react',
|
'react',
|
||||||
'lingui',
|
'lingui',
|
||||||
'simple-import-sort',
|
'simple-import-sort',
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
flows:
|
||||||
|
- "flows/*"
|
|
@ -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"
|
|
@ -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"
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
|
@ -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"
|
|
@ -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"
|
|
@ -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
|
|
@ -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"
|
|
@ -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"
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
|
@ -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"
|
|
@ -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,
|
|
||||||
}
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
# flow.yaml
|
# flow.yaml
|
||||||
|
|
||||||
appId: xyz.blueskyweb.app
|
appId: xyz.blueskyweb.app
|
||||||
|
@ -74,4 +75,3 @@ appId: xyz.blueskyweb.app
|
||||||
- "scroll"
|
- "scroll"
|
||||||
- "scroll"
|
- "scroll"
|
||||||
- "scroll"
|
- "scroll"
|
||||||
|
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
||||||
|
// eslint-disable-next-line
|
||||||
|
http.post('http://localhost:1986/' + SERVER_PATH, {
|
||||||
|
headers: {'Content-Type': 'text/plain'},
|
||||||
|
body: '',
|
||||||
|
})
|
|
@ -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()
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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()
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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()
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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()
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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()
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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')
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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')
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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()
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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()
|
|
||||||
// })
|
|
||||||
})
|
|
|
@ -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()
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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()
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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()
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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')
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -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()
|
|
||||||
// })
|
|
||||||
})
|
|
141
__e2e__/util.ts
141
__e2e__/util.ts
|
@ -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))
|
|
|
@ -16,10 +16,6 @@
|
||||||
- Add `eval "$(rbenv init - zsh)"` to your `~/.zshrc`
|
- Add `eval "$(rbenv init - zsh)"` to your `~/.zshrc`
|
||||||
- From inside the project directory:
|
- From inside the project directory:
|
||||||
- `bundler install` (this will install Cocoapods)
|
- `bundler install` (this will install Cocoapods)
|
||||||
- Setup your environment [for e2e testing using detox](https://wix.github.io/Detox/docs/introduction/getting-started):
|
|
||||||
- `yarn global add detox-cli`
|
|
||||||
- `brew tap wix/brew`
|
|
||||||
- `brew install applesimutils`
|
|
||||||
- After initial setup:
|
- After initial setup:
|
||||||
- Copy `google-services.json.example` to `google-services.json` or provide your own `google-services.json`. (A real firebase project is NOT required)
|
- Copy `google-services.json.example` to `google-services.json` or provide your own `google-services.json`. (A real firebase project is NOT required)
|
||||||
- `npx expo prebuild` -> you will also need to run this anytime `app.json` or native `package.json` deps change
|
- `npx expo prebuild` -> you will also need to run this anytime `app.json` or native `package.json` deps change
|
||||||
|
@ -120,10 +116,7 @@ To open the [Developer Menu](https://docs.expo.dev/debugging/tools/#developer-me
|
||||||
|
|
||||||
### Running E2E Tests
|
### Running E2E Tests
|
||||||
|
|
||||||
- Make sure you've set your environment following the above
|
See [testing.md](./testing.md).
|
||||||
- Make sure Metro and the dev server are running
|
|
||||||
- Run `yarn e2e`
|
|
||||||
- Find the artifacts in the `artifact` folder
|
|
||||||
|
|
||||||
### Polyfills
|
### Polyfills
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,19 @@
|
||||||
Make sure you've copied `.env.example` to `.env.test` and provided any required
|
Make sure you've copied `.env.example` to `.env.test` and provided any required
|
||||||
values.
|
values.
|
||||||
|
|
||||||
### Using Maestro E2E tests
|
## Using Maestro
|
||||||
|
|
||||||
1. Install Maestro by following [these instructions](https://maestro.mobile.dev/getting-started/installing-maestro). This will help us run the E2E tests.
|
1. Install Maestro by following [these instructions](https://maestro.mobile.dev/getting-started/installing-maestro). This will help us run the E2E tests.
|
||||||
2. You can write Maestro tests in `__e2e__/maestro` directory by creating a new `.yaml` file or by modifying an existing one.
|
2. You can write Maestro tests in `/.maestro/flows/` directory by creating a new `.yml` file or by modifying an existing one.
|
||||||
3. You can also use [Maestro Studio](https://maestro.mobile.dev/getting-started/maestro-studio) which automatically generates commands by recording your actions on the app. Therefore, you can create realistic tests without having to manually write any code. Use the `maestro studio` command to start recording your actions.
|
3. You can also use [Maestro Studio](https://maestro.mobile.dev/getting-started/maestro-studio) which automatically generates commands by recording your actions on the app. Therefore, you can create realistic tests without having to manually write any code. Use the `maestro studio` command to start recording your actions.
|
||||||
|
|
||||||
|
### Running Maestro tests
|
||||||
|
|
||||||
### Using Flashlight for Performance Testing
|
- In one tab, run `yarn e2e:mock-server`
|
||||||
|
- In a second tab, run `yarn e2e:metro`
|
||||||
|
- In a third tab, run `yarn e2e:run`
|
||||||
|
|
||||||
|
## Using Flashlight for Performance Testing
|
||||||
1. Make sure Maestro is installed (optional: only for automated testing) by following the instructions above
|
1. Make sure Maestro is installed (optional: only for automated testing) by following the instructions above
|
||||||
2. Install Flashlight by following [these instructions](https://docs.flashlight.dev/)
|
2. Install Flashlight by following [these instructions](https://docs.flashlight.dev/)
|
||||||
3. The simplest way to get started is by running `yarn perf:measure` which will run a live preview of the performance test results. You can [see a demo here](https://github.com/bamlab/flashlight/assets/4534323/4038a342-f145-4c3b-8cde-17949bf52612)
|
3. The simplest way to get started is by running `yarn perf:measure` which will run a live preview of the performance test results. You can [see a demo here](https://github.com/bamlab/flashlight/assets/4534323/4038a342-f145-4c3b-8cde-17949bf52612)
|
||||||
|
|
|
@ -114,8 +114,7 @@ export async function createServer(
|
||||||
pdsUrl,
|
pdsUrl,
|
||||||
mocker: new Mocker(testNet, pdsUrl, pic),
|
mocker: new Mocker(testNet, pdsUrl, pic),
|
||||||
async close() {
|
async close() {
|
||||||
await testNet.pds.server.destroy()
|
await testNet.close()
|
||||||
await testNet.plc.server.destroy()
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,11 +31,10 @@
|
||||||
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx src",
|
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx src",
|
||||||
"typecheck": "tsc --project ./tsconfig.check.json",
|
"typecheck": "tsc --project ./tsconfig.check.json",
|
||||||
"e2e:mock-server": "./jest/dev-infra/with-test-redis-and-db.sh ts-node --project tsconfig.e2e.json __e2e__/mock-server.ts",
|
"e2e:mock-server": "./jest/dev-infra/with-test-redis-and-db.sh ts-node --project tsconfig.e2e.json __e2e__/mock-server.ts",
|
||||||
"e2e:metro": "NODE_ENV=test RN_SRC_EXT=e2e.ts,e2e.tsx expo run:ios",
|
"e2e:metro": "EXPO_PUBLIC_ENV=e2e NODE_ENV=test RN_SRC_EXT=e2e.ts,e2e.tsx expo run:ios",
|
||||||
"e2e:build": "NODE_ENV=test detox build -c ios.sim.debug",
|
"e2e:run": "maestro test __e2e__",
|
||||||
"e2e:run": "NODE_ENV=test detox test --configuration ios.sim.debug --take-screenshots all",
|
|
||||||
"perf:test": "NODE_ENV=test maestro test",
|
"perf:test": "NODE_ENV=test maestro test",
|
||||||
"perf:test:run": "NODE_ENV=test maestro test __e2e__/maestro/scroll.yaml",
|
"perf:test:run": "NODE_ENV=test maestro test __e2e__/perf-test.yml",
|
||||||
"perf:test:measure": "NODE_ENV=test flashlight test --bundleId xyz.blueskyweb.app --testCommand \"yarn perf:test\" --duration 150000 --resultsFilePath .perf/results.json",
|
"perf:test:measure": "NODE_ENV=test flashlight test --bundleId xyz.blueskyweb.app --testCommand \"yarn perf:test\" --duration 150000 --resultsFilePath .perf/results.json",
|
||||||
"perf:test:results": "NODE_ENV=test flashlight report .perf/results.json",
|
"perf:test:results": "NODE_ENV=test flashlight report .perf/results.json",
|
||||||
"perf:measure": "NODE_ENV=test flashlight measure",
|
"perf:measure": "NODE_ENV=test flashlight measure",
|
||||||
|
@ -239,10 +238,8 @@
|
||||||
"babel-plugin-module-resolver": "^5.0.0",
|
"babel-plugin-module-resolver": "^5.0.0",
|
||||||
"babel-plugin-react-native-web": "^0.18.12",
|
"babel-plugin-react-native-web": "^0.18.12",
|
||||||
"babel-preset-expo": "^10.0.0",
|
"babel-preset-expo": "^10.0.0",
|
||||||
"detox": "^20.14.8",
|
|
||||||
"eslint": "^8.19.0",
|
"eslint": "^8.19.0",
|
||||||
"eslint-plugin-bsky-internal": "link:./eslint",
|
"eslint-plugin-bsky-internal": "link:./eslint",
|
||||||
"eslint-plugin-detox": "^1.0.0",
|
|
||||||
"eslint-plugin-ft-flow": "^2.0.3",
|
"eslint-plugin-ft-flow": "^2.0.3",
|
||||||
"eslint-plugin-lingui": "^0.2.0",
|
"eslint-plugin-lingui": "^0.2.0",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-react": "^7.33.2",
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {Pressable, View} from 'react-native'
|
import {LogBox, Pressable, View} from 'react-native'
|
||||||
import {navigate} from '../../../Navigation'
|
|
||||||
import {useModalControls} from '#/state/modals'
|
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
import {useSessionApi} from '#/state/session'
|
|
||||||
|
import {useModalControls} from '#/state/modals'
|
||||||
import {useSetFeedViewPreferencesMutation} from '#/state/queries/preferences'
|
import {useSetFeedViewPreferencesMutation} from '#/state/queries/preferences'
|
||||||
|
import {useSessionApi} from '#/state/session'
|
||||||
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||||
|
import {navigate} from '../../../Navigation'
|
||||||
|
|
||||||
|
LogBox.ignoreAllLogs()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This utility component is only included in the test simulator
|
* This utility component is only included in the test simulator
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export function show() {}
|
48
yarn.lock
48
yarn.lock
|
@ -10719,47 +10719,6 @@ detect-port-alt@^1.1.6:
|
||||||
address "^1.0.1"
|
address "^1.0.1"
|
||||||
debug "^2.6.0"
|
debug "^2.6.0"
|
||||||
|
|
||||||
detox@^20.14.8:
|
|
||||||
version "20.14.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/detox/-/detox-20.14.8.tgz#0a550cf677fc98a68d56d162e1c5caad317de9ca"
|
|
||||||
integrity sha512-3E/0/7Cb7x+wcBsZpCxD8FykZUsFnfVT00d6PWH940boc0Mo1Kzabh+I151X/On4qZMqVdUzgwmap/z8g/kmaw==
|
|
||||||
dependencies:
|
|
||||||
ajv "^8.6.3"
|
|
||||||
bunyan "^1.8.12"
|
|
||||||
bunyan-debug-stream "^3.1.0"
|
|
||||||
caf "^15.0.1"
|
|
||||||
chalk "^4.0.0"
|
|
||||||
child-process-promise "^2.2.0"
|
|
||||||
execa "^5.1.1"
|
|
||||||
find-up "^5.0.0"
|
|
||||||
fs-extra "^11.0.0"
|
|
||||||
funpermaproxy "^1.1.0"
|
|
||||||
glob "^8.0.3"
|
|
||||||
ini "^1.3.4"
|
|
||||||
jest-environment-emit "^1.0.5"
|
|
||||||
json-cycle "^1.3.0"
|
|
||||||
lodash "^4.17.11"
|
|
||||||
multi-sort-stream "^1.0.3"
|
|
||||||
multipipe "^4.0.0"
|
|
||||||
node-ipc "9.2.1"
|
|
||||||
proper-lockfile "^3.0.2"
|
|
||||||
resolve-from "^5.0.0"
|
|
||||||
sanitize-filename "^1.6.1"
|
|
||||||
semver "^7.0.0"
|
|
||||||
serialize-error "^8.0.1"
|
|
||||||
shell-quote "^1.7.2"
|
|
||||||
signal-exit "^3.0.3"
|
|
||||||
stream-json "^1.7.4"
|
|
||||||
strip-ansi "^6.0.1"
|
|
||||||
telnet-client "1.2.8"
|
|
||||||
tempfile "^2.0.0"
|
|
||||||
trace-event-lib "^1.3.1"
|
|
||||||
which "^1.3.1"
|
|
||||||
ws "^7.0.0"
|
|
||||||
yargs "^17.0.0"
|
|
||||||
yargs-parser "^21.0.0"
|
|
||||||
yargs-unparser "^2.0.0"
|
|
||||||
|
|
||||||
didyoumean@^1.2.2:
|
didyoumean@^1.2.2:
|
||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
|
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
|
||||||
|
@ -11393,13 +11352,6 @@ eslint-module-utils@^2.8.0:
|
||||||
version "0.0.0"
|
version "0.0.0"
|
||||||
uid ""
|
uid ""
|
||||||
|
|
||||||
eslint-plugin-detox@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-detox/-/eslint-plugin-detox-1.0.0.tgz#2d9c0130e8ebc4ced56efb6eeaf0d0f5c163398d"
|
|
||||||
integrity sha512-Dd+Cwyap5IO9DBKXOKrQTE1RQk9hvSSi+qsS1cMVPZY37mojz2PvriEOfGhKj5XN1G14lJ8TArf+6Y+Np2ZsoQ==
|
|
||||||
dependencies:
|
|
||||||
requireindex "~1.1.0"
|
|
||||||
|
|
||||||
eslint-plugin-eslint-comments@^3.2.0:
|
eslint-plugin-eslint-comments@^3.2.0:
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa"
|
||||||
|
|
Loading…
Reference in New Issue