クラウド Mac で iOS のドラッグ&ドロップデータを検証する

CI/CD ·約 10 分

クラウド Mac で iOS のドラッグ&ドロップデータを検証する

リリース前、チームはリストにあるタスク番号を編集欄へドラッグしました。ドラッグ中のプレビューは正常で、ドロップ後もエラーは出ません。しかし、保存されたのは空文字列でした。原因はアニメーションではありません。ドラッグ元が宣言するデータ型、ドロップ先が受け付ける型、非同期読み込みが完了するタイミングのいずれかがかみ合わないだけで、画面上は成功したように見えてしまいます。クラウド Mac をリモートで使う場合は、まず XCTest でデータの契約を確認し、その後シミュレータで実際のジェスチャーを検証できます。どちらか一方で済ませることはできません。

ドラッグ&ドロップの取り決めを検証可能にする

ドラッグできるコンテンツごとに、プロバイダが宣言する UTType、ドロップ先が受け付ける型、読み込みに成功したときに得られるべき内容の三つを明記します。たとえば、タスク番号をテキスト欄に貼り付けるだけなら、双方で UTType.utf8PlainText を使うと決められます。送信側がプレーンテキストを登録しているのに受信側は画像型だけを照会し、「ドロップ処理が呼ばれた」ことを成功の判定に使ってはいけません。

エラー時の動作も定めます。サポートしない型なら、ドロップ可能であるかのようにハイライトしないこと。読み込みに失敗したら、空のタスクを挿入しないこと。ドラッグをキャンセルしたら、元データを変更しないこと。タスク番号以外のフィールドも保持する必要があるなら、独自のデータ形式を定義して双方で解析します。構造化データを表示用テキストに紛れ込ませてはいけません。

ドラッグ&ドロップの完了は UI イベントであり、データの確定ではありません。型が一致し、非同期読み込みに成功し、内容の検証も通った場合に限って、アプリの状態を更新します。

XCTest で型と実際のペイロードを検証する

アプリのテスト target にテストファイルを追加します。以下のプロバイダは UTF-8 テキストを登録します。テストはまず型を確認し、読み込みのコールバックを待ってから、取得したバイト列を検証します。マウスやグラフィカルデスクトップに依存しないため、ビルドパイプラインの簡易チェックとして先に実行できます。

import XCTest
import UniformTypeIdentifiers

final class DragPayloadTests: XCTestCase {
    func testPlainTextPayload() {
        let provider = NSItemProvider()
        provider.registerDataRepresentation(
            forTypeIdentifier: UTType.utf8PlainText.identifier,
            visibility: .all
        ) { completion in
            completion(Data("ticket-42".utf8), nil)
            return nil
        }

        XCTAssertTrue(provider.hasItemConformingToTypeIdentifier(
            UTType.plainText.identifier
        ))
        XCTAssertFalse(provider.hasItemConformingToTypeIdentifier(
            UTType.image.identifier
        ))

        let loaded = expectation(description: "Load drag payload")
        provider.loadDataRepresentation(
            forTypeIdentifier: UTType.utf8PlainText.identifier
        ) { data, error in
            XCTAssertNil(error)
            XCTAssertEqual(data.flatMap { String(data: $0, encoding: .utf8) },
                           "ticket-42")
            loaded.fulfill()
        }
        wait(for: [loaded], timeout: 5)
    }
}

ここでは plainText で互換性のある型を確認し、utf8PlainText で登録済みの具体的な表現を読み込んでいます。テストが通ったら、同じ型判定とデコード処理を製品コードにも適用します。テストと UI で別々の許可リストを使わないためです。製品コードではコールバック内で error、空データ、UTF-8 のデコード失敗も処理する必要があります。hasItemConformingToTypeIdentifier の結果だけで画面を更新してはいけません。

対象シミュレータを指定して実行する

まず VMCommit のコンソールで現在選べる構成を確認します。Mac の提供後に SSH で接続し、インストール済みのシミュレータを調べます。以下のプロジェクト、Scheme、デバイス ID は自分の環境の値に置き換えてください。デバイス ID は最初のコマンドで取得し、例の文字列を実際のデバイスとして扱わないでください。

xcrun simctl list devices available
xcodebuild -list -project App.xcodeproj
xcodebuild test \
  -project App.xcodeproj \
  -scheme App \
  -destination 'platform=iOS Simulator,id=YOUR_DEVICE_ID' \
  -only-testing:AppTests/DragPayloadTests

-only-testing のパスは、プロジェクト内のテスト target とクラス名に一致させる必要があります。Scheme が存在しないと表示されたら、まず共有設定を確認します。対象デバイスが使えない場合は、別のマシンの ID を流用せず、その Mac 上で一覧を取得し直します。テストに失敗したら元の出力を残し、「シミュレータが起動しなかった」のか「ペイロードのアサーションに失敗した」のかを切り分けます。

グラフィカルセッションで実際のドロップを確認する

データ契約のテストはジェスチャー処理を経由しないため、UIDragInteraction や UIDropInteraction が正しく接続されていることまでは証明できません。グラフィカルデスクトップでシミュレータを開き、テスト対象のアプリをインストールして、次の順に一通り操作します。

  1. 有効なドラッグ元の項目を長押ししてドラッグを始め、プレビューが選択した項目と一致することを確認します。
  2. ドロップ可能な対象へ移動し、受け入れを示すフィードバックを確認します。次に、その型を受け付けない領域へ移動し、フィードバックが消えることを確認します。
  3. ドロップ後、読み込みの終了を待ち、編集欄に正しいタスク番号が一度だけ挿入されたことを確認します。
  4. もう一度ドラッグを始め、ドロップ前にキャンセルします。リストと編集欄のどちらも変わらないことを確認します。

ペイロードが大きい場合は「読み込み中」を独立した状態として扱います。重複する確定操作を無効にし、完了後に内容を更新します。失敗した場合は操作可能な状態に戻し、明確なメッセージを表示します。アニメーションを滑らかに見せるために、非同期コールバックが返る前から「インポート済み」と表示してはいけません。グラフィカルな確認ではユーザーに見える状態遷移を、XCTest では基盤となるデータを検証します。結果はそれぞれ記録してください。

失敗したらデータの流れに沿って調べる

「ドロップ先がハイライトされない」場合は、まず型を調べます。開発環境でドラッグ元が登録した識別子とドロップ先が許可する識別子を出力し、表示名の一致だけでなく、型の互換性を判定しているか確認します。「ハイライトされるのに内容が入らない」場合は、読み込みのコールバックが実行されたかを確認し、エラー、データ長、デコード結果を調べます。ペイロード全体を共有ログに書き込まないでください。タスクの内容に業務データが含まれる可能性があり、問題箇所の特定には通常、型と長さで十分です。

「ときどき二重に挿入される」場合は、ドロップ時のコールバックと読み込み完了時のコールバックの両方でモデルを更新していないか、同じプロバイダの読み込みを重複して開始していないかを確認します。ドロップごとに操作 ID を割り当て、検証に成功した後に一度だけ確定します。キャンセル時や失敗時は、確定待ちの結果を破棄します。画像など別のペイロードを扱う場合は、受け付ける型ごとにテストを書きます。プレーンテキストのテストが通っても、すべてのドラッグ&ドロップ経路が正しいとは限りません。

リリース前に二つのチェックリストを照合する

自動テストのチェックリストには、型の一致、非対応の型の拒否、バイト列の一致、空値と読み込みエラーの処理、タイムアウト時にテストが失敗することを含めます。画面操作のチェックリストには、ドラッグ元のプレビュー、ドロップ先のフィードバック、成功後の更新が一度だけであること、キャンセル後に内容が変わらないこと、失敗時のメッセージが成功と誤認させないことを含めます。前者はコミットのたびに実行するのに適しています。後者は操作部分の実装やシステムのバージョンが変わった後に重点的に確認します。

最後に、クリーンなシミュレータで操作を繰り返し、前回の実行で編集欄に残った内容に結果が左右されないことを確認します。プロジェクトが実際に受け付ける型と二つのチェックリストを一緒に残しておけば、次にドラッグ&ドロップの形式を変更したとき、問題がデータの契約、非同期読み込み、ジェスチャーのフィードバックのどこにあるか判断できます。

よくある質問

NSItemProvider のテストだけで画面操作も検証できますか?

できません。データの型と読み込みは確認できますが、プレビューやドロップ先の表示は画面で別途確認します。

受け取り側はいつデータを読み込むべきですか?

受け入れる UTType との適合を確認してから非同期で読み込みます。完了通知より前に取り込み済みとして扱わないでください。

利用期間を選んで申し込む

独占利用できる物理Mac miniで次のステップを検証

VMCommitではM4搭載の物理Mac miniを独占利用できます。日・週・月・四半期単位でレンタル可能です。モデルとロケーションを選ぶと、コンソールでリアルタイムの空き状況を確認できます。

Mac miniを今すぐレンタル