feat: add snapshot UITest and document
This commit is contained in:
parent
37f4bc1fc9
commit
f2f71e7102
|
@ -14,7 +14,7 @@
|
||||||
"testTargets" : [
|
"testTargets" : [
|
||||||
{
|
{
|
||||||
"selectedTests" : [
|
"selectedTests" : [
|
||||||
"MastodonUISnapshotTests\/testSnapshot()"
|
"MastodonUISnapshotTests\/testSmoke()"
|
||||||
],
|
],
|
||||||
"target" : {
|
"target" : {
|
||||||
"containerPath" : "container:Mastodon.xcodeproj",
|
"containerPath" : "container:Mastodon.xcodeproj",
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
# Mastodon App Store Snapshot Guide
|
||||||
|
This documentation is a guide to create snapshots for App Store. The outer contributor could ignore this.
|
||||||
|
|
||||||
|
## Prepare toolkit
|
||||||
|
The app use the Xcode UITest generate snapshots attachments. Then use the `xcparse` tool extract the snapshots.
|
||||||
|
|
||||||
|
```zsh
|
||||||
|
# install xcparse from Homebrew
|
||||||
|
brew install chargepoint/xcparse/xcparse
|
||||||
|
```
|
||||||
|
## Take Snapshots
|
||||||
|
We use `xcodebuild` CLI tool to trigger UITest. To change device for snapshot.
|
||||||
|
|
||||||
|
Replace the `name` in `-destinatio` option to change device. For example:
|
||||||
|
`-destination 'platform=iOS Simulator,name=iPad Pro (12.9-inch) (5th generation)' \`
|
||||||
|
|
||||||
|
```zsh
|
||||||
|
# list the destinations
|
||||||
|
xcodebuild \
|
||||||
|
test \
|
||||||
|
-showdestinations \
|
||||||
|
-derivedDataPath '~/Downloads/MastodonBuild/Derived' \
|
||||||
|
-workspace Mastodon.xcworkspace \
|
||||||
|
-scheme 'Mastodon - Snapshot'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Auto-Login before make snapshots
|
||||||
|
This script trigger the `MastodonUITests/MastodonUISnapshotTests/testSignInAccount` test case to sign-in the account. The test case may wait for 2FA code or email code. Please input it if needed. Also, you can skip this and sign-in the test account manually.
|
||||||
|
|
||||||
|
Replace the `<Email>` and `<Password>` for test account.
|
||||||
|
```zsh
|
||||||
|
# build and run test case for auto sign-in
|
||||||
|
TEST_RUNNER_email='<Email>' \
|
||||||
|
TEST_RUNNER_password='<Password>' \
|
||||||
|
xcodebuild \
|
||||||
|
test \
|
||||||
|
-derivedDataPath '~/Downloads/MastodonBuild/Derived' \
|
||||||
|
-workspace Mastodon.xcworkspace \
|
||||||
|
-scheme 'Mastodon - Snapshot' \
|
||||||
|
-sdk iphonesimulator \
|
||||||
|
-destination 'platform=iOS Simulator,name=iPhone 13 Pro Max' \
|
||||||
|
-testPlan 'AppStoreSnapshotTestPlan' \
|
||||||
|
-only-testing:MastodonUITests/MastodonUISnapshotTests/testSignInAccount
|
||||||
|
```
|
||||||
|
|
||||||
|
Note:
|
||||||
|
UITest may running silent. Open the Simulator.app to make the device display.
|
||||||
|
|
||||||
|
#### Take and extract snapshots
|
||||||
|
```zsh
|
||||||
|
# take snapshots
|
||||||
|
TEST_RUNNER_username_snapshot='Gargron' \
|
||||||
|
xcodebuild \
|
||||||
|
test \
|
||||||
|
-derivedDataPath '~/Downloads/MastodonBuild/Derived' \
|
||||||
|
-workspace Mastodon.xcworkspace \
|
||||||
|
-scheme 'Mastodon - Snapshot' \
|
||||||
|
-sdk iphonesimulator \
|
||||||
|
-destination 'platform=iOS Simulator,name=iPhone 13 Pro Max' \
|
||||||
|
-testPlan 'AppStoreSnapshotTestPlan' \
|
||||||
|
-only-testing:MastodonUITests/MastodonUISnapshotTests/testSnapshot
|
||||||
|
|
||||||
|
# output:
|
||||||
|
Test session results, code coverage, and logs:
|
||||||
|
/Users/Me/Downloads/MastodonBuild/Derived/Logs/Test/Test-Mastodon - Snapshot-2022.03.03_18-00-38-+0800.xcresult
|
||||||
|
|
||||||
|
** TEST SUCCEEDED **
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `xcparse screenshots <path_for_xcresult> <path_for_destination>` extracts snapshots.
|
||||||
|
|
||||||
|
```zsh
|
||||||
|
# scresult path for previous test case
|
||||||
|
xcparse screenshots '<path_for_xcresult>' ~/Downloads/MastodonBuild/Screenshots/
|
||||||
|
|
||||||
|
# output
|
||||||
|
100% [============]
|
||||||
|
🎊 Export complete! 🎊
|
||||||
|
```
|
|
@ -7,7 +7,7 @@
|
||||||
<key>AppShared.xcscheme_^#shared#^_</key>
|
<key>AppShared.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>21</integer>
|
<integer>20</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
|
@ -102,7 +102,7 @@
|
||||||
<key>MastodonIntent.xcscheme_^#shared#^_</key>
|
<key>MastodonIntent.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>23</integer>
|
<integer>21</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>MastodonIntents.xcscheme_^#shared#^_</key>
|
<key>MastodonIntents.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>24</integer>
|
<integer>19</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>SuppressBuildableAutocreation</key>
|
<key>SuppressBuildableAutocreation</key>
|
||||||
|
|
|
@ -51,6 +51,7 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media
|
||||||
let barButtonItem = UIBarButtonItem()
|
let barButtonItem = UIBarButtonItem()
|
||||||
barButtonItem.tintColor = ThemeService.tintColor
|
barButtonItem.tintColor = ThemeService.tintColor
|
||||||
barButtonItem.image = UIImage(systemName: "gear")?.withRenderingMode(.alwaysTemplate)
|
barButtonItem.image = UIImage(systemName: "gear")?.withRenderingMode(.alwaysTemplate)
|
||||||
|
barButtonItem.accessibilityLabel = L10n.Common.Controls.Actions.settings
|
||||||
return barButtonItem
|
return barButtonItem
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -58,6 +59,7 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media
|
||||||
let barButtonItem = UIBarButtonItem()
|
let barButtonItem = UIBarButtonItem()
|
||||||
barButtonItem.tintColor = ThemeService.tintColor
|
barButtonItem.tintColor = ThemeService.tintColor
|
||||||
barButtonItem.image = UIImage(systemName: "square.and.pencil")?.withRenderingMode(.alwaysTemplate)
|
barButtonItem.image = UIImage(systemName: "square.and.pencil")?.withRenderingMode(.alwaysTemplate)
|
||||||
|
barButtonItem.accessibilityLabel = L10n.Common.Controls.Actions.compose
|
||||||
return barButtonItem
|
return barButtonItem
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -39,80 +39,78 @@ extension MastodonUISnapshotTests {
|
||||||
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
|
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
|
||||||
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
|
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension MastodonUISnapshotTests {
|
extension MastodonUISnapshotTests {
|
||||||
|
|
||||||
|
private func tapTab(app: XCUIApplication, tab: String) {
|
||||||
|
let searchTab = app.tabBars.buttons[tab]
|
||||||
|
if searchTab.exists { searchTab.tap() }
|
||||||
|
|
||||||
|
let searchCell = app.collectionViews.cells[tab]
|
||||||
|
if searchCell.exists { searchCell.tap() }
|
||||||
|
}
|
||||||
|
|
||||||
func testSnapshot() async throws {
|
func testSnapshot() async throws {
|
||||||
let app = XCUIApplication()
|
let app = XCUIApplication()
|
||||||
app.launch()
|
app.launch()
|
||||||
|
|
||||||
try await snapshotHome()
|
try await testSnapshotHome()
|
||||||
try await snapshotSearch()
|
try await testSnapshotSearch()
|
||||||
try await snapshotProfile()
|
try await testSnapshotProfile()
|
||||||
|
try await testSnapshotCompose()
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapshotHome() async throws {
|
func testSnapshotHome() async throws {
|
||||||
let app = XCUIApplication()
|
let app = XCUIApplication()
|
||||||
app.launch()
|
app.launch()
|
||||||
|
|
||||||
func tapTab() {
|
tapTab(app: app, tab: "Home")
|
||||||
XCTAssert(app.tabBars.buttons["Home"].exists)
|
|
||||||
app.tabBars.buttons["Home"].tap()
|
|
||||||
}
|
|
||||||
|
|
||||||
tapTab()
|
|
||||||
try await Task.sleep(nanoseconds: .second * 3)
|
try await Task.sleep(nanoseconds: .second * 3)
|
||||||
takeSnapshot(name: "Home - 1")
|
takeSnapshot(name: "Home - 1")
|
||||||
|
|
||||||
tapTab()
|
tapTab(app: app, tab: "Home")
|
||||||
try await Task.sleep(nanoseconds: .second * 3)
|
try await Task.sleep(nanoseconds: .second * 3)
|
||||||
takeSnapshot(name: "Home - 2")
|
takeSnapshot(name: "Home - 2")
|
||||||
|
|
||||||
tapTab()
|
tapTab(app: app, tab: "Home")
|
||||||
try await Task.sleep(nanoseconds: .second * 3)
|
try await Task.sleep(nanoseconds: .second * 3)
|
||||||
takeSnapshot(name: "Home - 3")
|
takeSnapshot(name: "Home - 3")
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapshotSearch() async throws {
|
func testSnapshotSearch() async throws {
|
||||||
let app = XCUIApplication()
|
let app = XCUIApplication()
|
||||||
app.launch()
|
app.launch()
|
||||||
|
|
||||||
func tapTab() {
|
tapTab(app: app, tab: "Search")
|
||||||
XCTAssert(app.tabBars.buttons["Search"].exists)
|
|
||||||
app.tabBars.buttons["Search"].tap()
|
|
||||||
}
|
|
||||||
|
|
||||||
tapTab()
|
|
||||||
try await Task.sleep(nanoseconds: .second * 3)
|
try await Task.sleep(nanoseconds: .second * 3)
|
||||||
takeSnapshot(name: "Search - 1")
|
takeSnapshot(name: "Search - 1")
|
||||||
|
|
||||||
tapTab()
|
tapTab(app: app, tab: "Search")
|
||||||
try await Task.sleep(nanoseconds: .second * 3)
|
try await Task.sleep(nanoseconds: .second * 3)
|
||||||
takeSnapshot(name: "Search - 2")
|
takeSnapshot(name: "Search - 2")
|
||||||
|
|
||||||
tapTab()
|
tapTab(app: app, tab: "Search")
|
||||||
try await Task.sleep(nanoseconds: .second * 3)
|
try await Task.sleep(nanoseconds: .second * 3)
|
||||||
takeSnapshot(name: "Search - 3")
|
takeSnapshot(name: "Search - 3")
|
||||||
}
|
}
|
||||||
|
|
||||||
func snapshotProfile() async throws {
|
func testSnapshotProfile() async throws {
|
||||||
|
let username = ProcessInfo.processInfo.environment["username_snapshot"] ?? "Gargron"
|
||||||
|
|
||||||
let app = XCUIApplication()
|
let app = XCUIApplication()
|
||||||
app.launch()
|
app.launch()
|
||||||
|
|
||||||
// Go to Search tab
|
// Go to Search tab
|
||||||
XCTAssert(app.tabBars.buttons["Search"].exists)
|
tapTab(app: app, tab: "Search")
|
||||||
app.tabBars.buttons["Search"].tap()
|
|
||||||
|
|
||||||
// Tap and search user
|
// Tap and search user
|
||||||
let searchField = app.navigationBars.searchFields.firstMatch
|
let searchField = app.navigationBars.searchFields.firstMatch
|
||||||
XCTAssert(searchField.waitForExistence(timeout: 5))
|
XCTAssert(searchField.waitForExistence(timeout: 5))
|
||||||
searchField.tap()
|
searchField.tap()
|
||||||
searchField.typeText("@dentaku@fnordon.de")
|
searchField.typeText(username)
|
||||||
|
|
||||||
// Tap the cell and display user profile
|
// Tap the cell and display user profile
|
||||||
let cell = app.tables.cells.firstMatch
|
let cell = app.tables.cells.firstMatch
|
||||||
|
@ -124,12 +122,206 @@ extension MastodonUISnapshotTests {
|
||||||
takeSnapshot(name: "Profile")
|
takeSnapshot(name: "Profile")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testSnapshotCompose() async throws {
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launch()
|
||||||
|
|
||||||
|
// open Compose scene
|
||||||
|
let composeBarButtonItem = app.navigationBars.buttons["Compose"].firstMatch
|
||||||
|
let composeCollectionViewCell = app.collectionViews.cells["Compose"]
|
||||||
|
if composeBarButtonItem.waitForExistence(timeout: 5) {
|
||||||
|
composeBarButtonItem.tap()
|
||||||
|
} else if composeCollectionViewCell.waitForExistence(timeout: 5) {
|
||||||
|
composeCollectionViewCell.tap()
|
||||||
|
} else {
|
||||||
|
XCTFail()
|
||||||
|
}
|
||||||
|
|
||||||
|
// type text
|
||||||
|
let textView = app.textViews.firstMatch
|
||||||
|
XCTAssert(textView.waitForExistence(timeout: 5))
|
||||||
|
textView.tap()
|
||||||
|
textView.typeText("Look at that view! #Athens ")
|
||||||
|
|
||||||
|
// tap Add Attachment toolbar button
|
||||||
|
let addAttachmentButton = app.buttons["Add Attachment"].firstMatch
|
||||||
|
XCTAssert(addAttachmentButton.waitForExistence(timeout: 5))
|
||||||
|
addAttachmentButton.tap()
|
||||||
|
|
||||||
|
// tap Photo Library menu action
|
||||||
|
let photoLibraryButton = app.buttons["Photo Library"].firstMatch
|
||||||
|
XCTAssert(photoLibraryButton.waitForExistence(timeout: 5))
|
||||||
|
photoLibraryButton.tap()
|
||||||
|
|
||||||
|
// select photo
|
||||||
|
let photo = app.images["Photo, August 09, 2012, 2:52 AM"].firstMatch
|
||||||
|
XCTAssert(photo.waitForExistence(timeout: 5))
|
||||||
|
photo.tap()
|
||||||
|
|
||||||
|
// tap Add barButtonItem
|
||||||
|
let addBarButtonItem = app.navigationBars.buttons["Add"].firstMatch
|
||||||
|
XCTAssert(addBarButtonItem.waitForExistence(timeout: 5))
|
||||||
|
addBarButtonItem.tap()
|
||||||
|
|
||||||
|
try await Task.sleep(nanoseconds: .second * 10)
|
||||||
|
takeSnapshot(name: "Compose - 1")
|
||||||
|
|
||||||
|
try await Task.sleep(nanoseconds: .second * 10)
|
||||||
|
takeSnapshot(name: "Compose - 2")
|
||||||
|
|
||||||
|
try await Task.sleep(nanoseconds: .second * 10)
|
||||||
|
takeSnapshot(name: "Compose - 3")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MastodonUISnapshotTests {
|
||||||
|
|
||||||
|
// Please check the Documentation/Snapshot.md and run this test case in the command line
|
||||||
|
func testSignInAccount() async throws {
|
||||||
|
guard let email = ProcessInfo.processInfo.environment["email"] else {
|
||||||
|
fatalError("env 'email' missing")
|
||||||
|
}
|
||||||
|
guard let password = ProcessInfo.processInfo.environment["password"] else {
|
||||||
|
fatalError("env 'password' missing")
|
||||||
|
}
|
||||||
|
try await signInApplication(email: email, password: password)
|
||||||
|
}
|
||||||
|
|
||||||
|
func signInApplication(
|
||||||
|
email: String,
|
||||||
|
password: String
|
||||||
|
) async throws {
|
||||||
|
let app = XCUIApplication()
|
||||||
|
app.launch()
|
||||||
|
|
||||||
|
// check in Onboarding or not
|
||||||
|
let loginButton = app.buttons["Log In"].firstMatch
|
||||||
|
let loginButtonExists = loginButton.waitForExistence(timeout: 5)
|
||||||
|
|
||||||
|
// goto Onboarding scene if already sign-in
|
||||||
|
if !loginButtonExists {
|
||||||
|
let profileTabBarButton = app.tabBars.buttons["Profile"]
|
||||||
|
XCTAssert(profileTabBarButton.waitForExistence(timeout: 3))
|
||||||
|
profileTabBarButton.press(forDuration: 2)
|
||||||
|
|
||||||
|
let addAccountCell = app.cells.containing(.staticText, identifier: "Add Account").firstMatch
|
||||||
|
XCTAssert(addAccountCell.waitForExistence(timeout: 3))
|
||||||
|
addAccountCell.tap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tap login button
|
||||||
|
XCTAssert(loginButtonExists)
|
||||||
|
loginButton.tap()
|
||||||
|
|
||||||
|
// type domain
|
||||||
|
let domainTextField = app.textFields.firstMatch
|
||||||
|
XCTAssert(domainTextField.waitForExistence(timeout: 5))
|
||||||
|
domainTextField.tap()
|
||||||
|
// Skip system keyboard swipe input guide
|
||||||
|
skipKeyboardSwipeInputGuide(app: app)
|
||||||
|
domainTextField.typeText("mastodon.social")
|
||||||
|
XCUIApplication().keyboards.buttons["Done"].firstMatch.tap()
|
||||||
|
|
||||||
|
// wait searching
|
||||||
|
try await Task.sleep(nanoseconds: .second * 3)
|
||||||
|
|
||||||
|
// tap server
|
||||||
|
let cell = app.cells.containing(.staticText, identifier: "mastodon.social").firstMatch
|
||||||
|
XCTAssert(cell.waitForExistence(timeout: 5))
|
||||||
|
cell.tap()
|
||||||
|
|
||||||
|
// add system alert monitor
|
||||||
|
// A. The monitor not works
|
||||||
|
// addUIInterruptionMonitor(withDescription: "Authentication Alert") { alert in
|
||||||
|
// alert.buttons["Continue"].firstMatch.tap()
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
|
||||||
|
// tap next button
|
||||||
|
let nextButton = app.buttons.matching(NSPredicate(format: "enabled == true")).matching(identifier: "Next").firstMatch
|
||||||
|
XCTAssert(nextButton.waitForExistence(timeout: 3))
|
||||||
|
nextButton.tap()
|
||||||
|
|
||||||
|
// wait authentication alert display
|
||||||
|
try await Task.sleep(nanoseconds: .second * 3)
|
||||||
|
|
||||||
|
// B. Workaround
|
||||||
|
let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
|
||||||
|
let continueButton = springboard.buttons["Continue"].firstMatch
|
||||||
|
XCTAssert(continueButton.waitForExistence(timeout: 3))
|
||||||
|
continueButton.tap()
|
||||||
|
|
||||||
|
// wait OAuth webpage display
|
||||||
|
try await Task.sleep(nanoseconds: .second * 10)
|
||||||
|
|
||||||
|
let webview = app.webViews.firstMatch
|
||||||
|
XCTAssert(webview.waitForExistence(timeout: 10))
|
||||||
|
|
||||||
|
func tapAuthorizeButton() async throws -> Bool {
|
||||||
|
let authorizeButton = webview.buttons["AUTHORIZE"].firstMatch
|
||||||
|
if authorizeButton.exists {
|
||||||
|
authorizeButton.tap()
|
||||||
|
try await Task.sleep(nanoseconds: .second * 5)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let isAuthorized = try await tapAuthorizeButton()
|
||||||
|
if !isAuthorized {
|
||||||
|
let emailTextField = webview.textFields["E-mail address"].firstMatch
|
||||||
|
XCTAssert(emailTextField.waitForExistence(timeout: 10))
|
||||||
|
emailTextField.tap()
|
||||||
|
emailTextField.typeText(email)
|
||||||
|
|
||||||
|
let passwordTextField = webview.secureTextFields["Password"].firstMatch
|
||||||
|
XCTAssert(passwordTextField.waitForExistence(timeout: 3))
|
||||||
|
passwordTextField.tap()
|
||||||
|
passwordTextField.typeText(password)
|
||||||
|
|
||||||
|
let goKeyboardButton = XCUIApplication().keyboards.buttons["Go"].firstMatch
|
||||||
|
XCTAssert(goKeyboardButton.waitForExistence(timeout: 3))
|
||||||
|
goKeyboardButton.tap()
|
||||||
|
|
||||||
|
var retry = 0
|
||||||
|
let retryLimit = 20
|
||||||
|
while webview.exists {
|
||||||
|
guard retry < retryLimit else {
|
||||||
|
fatalError("Cannot complete OAuth process")
|
||||||
|
}
|
||||||
|
retry += 1
|
||||||
|
|
||||||
|
// will break due to webview dismiss
|
||||||
|
_ = try await tapAuthorizeButton()
|
||||||
|
|
||||||
|
print("Please enter the sign-in confirm code. Retry in 5s")
|
||||||
|
try await Task.sleep(nanoseconds: .second * 5)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Done
|
||||||
|
}
|
||||||
|
|
||||||
|
print("OAuth finish")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func skipKeyboardSwipeInputGuide(app: XCUIApplication) {
|
||||||
|
let swipeInputLabel = app.staticTexts["Speed up your typing by sliding your finger across the letters to compose a word."].firstMatch
|
||||||
|
guard swipeInputLabel.waitForExistence(timeout: 3) else { return }
|
||||||
|
let continueButton = app.buttons["Continue"]
|
||||||
|
continueButton.tap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension MastodonUISnapshotTests {
|
extension MastodonUISnapshotTests {
|
||||||
func takeSnapshot(name: String) {
|
func takeSnapshot(name: String) {
|
||||||
let snapshot = XCUIScreen.main.screenshot()
|
let snapshot = XCUIScreen.main.screenshot()
|
||||||
let attachment = XCTAttachment(screenshot: snapshot)
|
let attachment = XCTAttachment(
|
||||||
|
uniformTypeIdentifier: "public.png",
|
||||||
|
name: "Screenshot-\(name)-\(UIDevice.current.name).png",
|
||||||
|
payload: snapshot.pngRepresentation,
|
||||||
|
userInfo: nil
|
||||||
|
)
|
||||||
attachment.lifetime = .keepAlways
|
attachment.lifetime = .keepAlways
|
||||||
add(attachment)
|
add(attachment)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue