NavigationView と List を使ったアプリのテスト方法を説明します。
Sponsor Link
環境&対象
- macOS Catalina 10.15.7
- Xcode 12.2
- iOS 14.2
テスト対象アプリ
struct ContentView: View {
@State private var items = ["item1", "item2", "item3"]
var body: some View {
NavigationView {
List {
ForEach(items, id:\.self) { item in
Text(item)
}
.onDelete { _ in
}
}
.accessibility(identifier: "MyList")
.toolbar{
#if os(iOS)
ToolbarItem(placement: .navigationBarLeading) {
EditButton()
.accessibility(identifier: "EditButton") // does not work
}
#endif
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
items.append("item\(Date().timeIntervalSince1970)")
}, label: {
Label("Add Item", systemImage: "plus")
})
.accessibility(identifier: "Add") // does not work
}
}
.navigationTitle("NavTitle")
}
}
}
テスト対象の要素と操作
以下をテスト対象の要素および操作とします。
対象操作
- List 表示
- 編集ボタンによる操作
- 削除操作
- 追加操作
対象要素
- NavigationLink
- List
- List の 行
- NavigationBar
- NavigationBar のボタン
- 編集モードでの削除操作
要素の取得方法
List
Accessibility ID を使って、取得することができます。
app.tables[“<ID>”] とすることで、取得可能です。
Listの行
Accessibility ID を使って、取得することは、できないようです。
table.rows とすることで、取得可能です。
個別行は、rows.element(boundBy: <index>) として取得することができます。
NavigationLink
Accessibility ID を使って、取得することができます。
app.buttons[“<ID>”] とすることで、取得可能です。
NavigationBar
Accessibility ID を使って、取得することは、できないようです。
Title をつけることで、その Title を使って取得することができます。
app.navigationBars[“<title>”] とすることで、取得可能です。
NavigationBar のボタン
Accessibility ID を使って、取得することは、できないようです。
表示順(左側)に取得することはできます。
navBar.buttons.element(boundBy: 0) とすることで、取得可能です。
編集モードでのボタン
Accessibility ID を使って、取得することは、できないようです。
特定の ID を持っているようで、
編集モードでの行の左に表示される ❌ ボタンは、”Delete ”
❌ボタン押下後に表示される Delete ボタンは、”Delete” という ID で取得できます。
サンプルコード
以下は、アプリ起動後に、Edit ボタンを押下し、削除操作することで、行数が減ることをテストするコードです。
func test_launch_withInitialData_ListShouldHaveThree() {
let app = XCUIApplication()
app.launch()
// (1)
let myList = app.tables["MyList"]
// (2)
let rows = myList.cells
XCTAssertEqual(rows.count, 3)
// (3)
let myNavBar = app.navigationBars["NavTitle"]
XCTAssertTrue(myNavBar.exists)
// (4)
let editButton = myNavBar.buttons["Edit"]
XCTAssertTrue(editButton.exists)
// (5)
let addButton = myNavBar.buttons.element(boundBy: 1)
XCTAssertTrue(addButton.exists)
//XCTAssertEqual(addButton.label, "Add Item") // does not work
// delete 2nd line
// (6)
editButton.tap()
// (7)
rows.element(boundBy: 1).buttons["Delete "].tap()
// (8)
rows.element(boundBy: 1).buttons["Delete"].tap()
XCTAssertEqual(rows.count, 2)
}
- MyList という ID を持つ List を取得
- List に含まれる行を取得
- NavTitle という Title を持つ NavigationBar を取得
- EditButton を取得
- 追加ボタンを取得
- EditButton をタップ
- 2行目の左側にある ❌ をタップ
- 2行目の右側に表示される Delete をタップ
所感
NavigationView のテストについては、動作が不安定な気がしますので、リリースごとに動作が変わることが予想されます。
まとめ:NavigationView と List を使ったアプリのテスト
- tables 経由で、List を取得する
- navigatioinBars 経由で NavigationBar を取得する
- tables.rows 経由で各行を取得する
- SwiftUI から提供されている EditButton やその後の削除操作要素の要素は、特定の ID がふられている
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
Sponsor Link