NavigationView と List を使ったアプリのテスト方法を説明します。
Sponsor Link
目次
環境&対象
- macOS Catalina 10.15.7
- Xcode 12.2
- iOS 14.2
テスト対象アプリ

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
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>) として取得することができます。
Accessibility ID を使って、取得することができます。
app.buttons[“<ID>”] とすることで、取得可能です。
Accessibility ID を使って、取得することは、できないようです。
Title をつけることで、その Title を使って取得することができます。
app.navigationBars[“<title>”] とすることで、取得可能です。
Accessibility ID を使って、取得することは、できないようです。
表示順(左側)に取得することはできます。
navBar.buttons.element(boundBy: 0) とすることで、取得可能です。
編集モードでのボタン
Accessibility ID を使って、取得することは、できないようです。
特定の ID を持っているようで、
編集モードでの行の左に表示される ❌ ボタンは、”Delete ”
❌ボタン押下後に表示される Delete ボタンは、”Delete” という ID で取得できます。
サンプルコード
以下は、アプリ起動後に、Edit ボタンを押下し、削除操作することで、行数が減ることをテストするコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
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 のテストについては、動作が不安定な気がしますので、リリースごとに動作が変わることが予想されます。
- tables 経由で、List を取得する
- navigatioinBars 経由で NavigationBar を取得する
- tables.rows 経由で各行を取得する
- SwiftUI から提供されている EditButton やその後の削除操作要素の要素は、特定の ID がふられている
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
Sponsor Link