本文へ移動
cccskills
無料GitHub で公開

mobile-device-matrix-toolkit

Dispatches mobile UI test runs across a 3-tier device matrix (smoke per-PR, regression per-merge, full farm at release) to control CI cost: generates per-target Appium capability configs from a central YAML, parallelises via GitHub Actions matrix strategy, and aggregates JUnit XML into a cross-device pass/fail table. Use when deciding which iOS / Android devices and OS versions to run tests on and at which stage (smoke / regression / full farm), not how to configure a specific test framework (for that, use xcuitest-suite, espresso-suite, etc.).

日本語の概要は準備中です。原文の説明を表示しています。

testland/qaスター 13(GitHub 13 + cccskills 0)
連携ツールGitHubFirebase

実行スコア 未検証

インストール方法を見る

含まれるファイル(2)

  • SKILL.md10.9 KB
  • .tessl-plugin/plugin.json694 B

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

mobile-device-matrix-toolkit

Overview

Mobile testing has a combinatorial explosion problem:

  • iOS: 5+ active OS versions × 10+ device sizes ≈ 50+ configs.
  • Android: 8+ API levels × 100+ device profiles ≈ 800+ configs.

Running every test on every config = CI cost / time disaster.

This skill is a dispatcher that picks the right subset per cadence. It wraps the per-platform test runners (xcuitest-suite, espresso-suite, appium-testing, detox-testing, maestro-flows) and orchestrates matrix execution.

When to use

  • The team's mobile suite needs cross-device / cross-OS coverage but blanket "run everywhere" is too expensive.
  • A new device support tier (foldables, larger tablets) needs to be added; the matrix should grow without exploding cost.
  • A device farm subscription (Firebase Test Lab, BrowserStack, AWS Device Farm, Sauce Labs) is paid for and the team needs a workflow to use it efficiently.

Step 1 - Define the three-tier matrix

# .matrix/devices.yaml
tier_smoke:
  description: "Per-PR - every commit. Cheap, fast feedback."
  ios:
    - { device: "iPhone 15", os: "17.4" }
  android:
    - { device: "Pixel 7", api: 34 }

tier_regression:
  description: "Per-merge to main. Wider coverage."
  ios:
    - { device: "iPhone 15", os: "17.4" }
    - { device: "iPhone SE 3rd", os: "16.0" }
    - { device: "iPad Pro 12.9", os: "17.4" }
  android:
    - { device: "Pixel 7", api: 34 }
    - { device: "Pixel 5", api: 31 }
    - { device: "Galaxy Tab S8", api: 34 }

tier_release:
  description: "Pre-release. Full matrix; runs on device farm."
  ios:
    - device: "iPhone 15", os: "17.4"
    - device: "iPhone 15 Pro Max", os: "17.4"
    - device: "iPhone 14", os: "17.0"
    - device: "iPhone 13", os: "16.0"
    - device: "iPhone SE 3rd", os: "15.0"
    - device: "iPad Pro 12.9", os: "17.4"
    - device: "iPad Mini", os: "16.0"
  android:
    - { device: "Pixel 8 Pro", api: 34 }
    - { device: "Pixel 7", api: 34 }
    - { device: "Pixel 5", api: 31 }
    - { device: "Galaxy S23", api: 33 }
    - { device: "Galaxy A54", api: 33 }
    - { device: "Pixel 4a", api: 30 }
    - { device: "Galaxy Tab S8", api: 34 }

Per-tier guidance:

TierWheniOS / Android countWall timeCost (est)
SmokeEvery PR push1 / 1~5 minlocal sim
RegressionMerge to main3 / 3~20 minlocal sim
ReleasePre-release tag7 / 7~60 minfarm

Step 2 - Generate per-target capabilities

# scripts/gen-matrix.py
import yaml, json, sys

cfg = yaml.safe_load(open(sys.argv[1]))
tier = sys.argv[2]   # smoke | regression | release

targets = []
for ios in cfg[f'tier_{tier}']['ios']:
    targets.append({
        'name': f"ios-{ios['device'].replace(' ', '-')}-{ios['os']}",
        'platform': 'iOS',
        'capabilities': {
            'platformName': 'iOS',
            'appium:deviceName': ios['device'],
            'appium:platformVersion': ios['os'],
            'appium:automationName': 'XCUITest',
        },
    })
for and_ in cfg[f'tier_{tier}']['android']:
    targets.append({
        'name': f"android-{and_['device'].replace(' ', '-')}-api{and_['api']}",
        'platform': 'Android',
        'capabilities': {
            'platformName': 'Android',
            'appium:deviceName': and_['device'],
            'appium:platformVersion': str(and_['api']),
            'appium:automationName': 'UiAutomator2',
        },
    })

print(json.dumps(targets))

CI uses this output as a matrix:

jobs:
  generate-matrix:
    outputs:
      targets: ${{ steps.gen.outputs.targets }}
    steps:
      - id: gen
        run: |
          targets=$(python scripts/gen-matrix.py .matrix/devices.yaml ${{ inputs.tier }})
          echo "targets=$targets" >> "$GITHUB_OUTPUT"

  test:
    needs: generate-matrix
    strategy:
      fail-fast: false
      matrix:
        target: ${{ fromJSON(needs.generate-matrix.outputs.targets) }}
    runs-on: ${{ matrix.target.platform == 'iOS' && 'macos-15' || 'ubuntu-latest' }}
    name: ${{ matrix.target.name }}
    steps:
      - run: ./scripts/run-tests.sh ${{ matrix.target.name }} '${{ toJSON(matrix.target.capabilities) }}'

Step 3 - Per-tier dispatch

# .github/workflows/mobile-tests.yml
on:
  pull_request:
    paths: ['mobile/**']
  push:
    branches: [main]
  release:
    types: [created]

jobs:
  smoke:
    if: github.event_name == 'pull_request'
    uses: ./.github/workflows/run-matrix.yml
    with:
      tier: smoke

  regression:
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    uses: ./.github/workflows/run-matrix.yml
    with:
      tier: regression

  release:
    if: github.event_name == 'release'
    uses: ./.github/workflows/run-matrix.yml
    with:
      tier: release

Step 4 - Aggregate per-target results

Before trusting the roll-up: a shard that fails to upload its JUnit XML (device timeout, farm hiccup) reads as 0 tests, not failure - detect shards with a missing or empty report, re-run only those shards, then re-aggregate. Each matrix shard uploads its JUnit XML; an aggregator job combines:

# scripts/aggregate-matrix.py
import xml.etree.ElementTree as ET
from collections import defaultdict
import sys

per_target = defaultdict(lambda: {'tests': 0, 'failures': 0, 'errors': 0, 'time': 0.0})

for f in sys.argv[1:]:
    target = f.split('/')[-2]   # extract from path
    tree = ET.parse(f)
    for ts in tree.iter('testsuite'):
        per_target[target]['tests'] += int(ts.get('tests', 0))
        per_target[target]['failures'] += int(ts.get('failures', 0))
        per_target[target]['errors'] += int(ts.get('errors', 0))
        per_target[target]['time'] += float(ts.get('time', 0))

# Render matrix
print('| Target | Tests | Pass | Fail | Time |')
print('|--------|------:|-----:|-----:|-----:|')
for target, m in sorted(per_target.items()):
    pass_ = m['tests'] - m['failures'] - m['errors']
    print(f"| {target} | {m['tests']} | {pass_} | {m['failures']+m['errors']} | {m['time']:.1f}s |")

Output:

| Target                          | Tests | Pass | Fail | Time   |
|---------------------------------|------:|-----:|-----:|-------:|
| ios-iPhone-15-17.4               |   42  |   42 |    0 | 320.4s |
| ios-iPhone-SE-3rd-16.0           |   42  |   41 |    1 | 295.1s |   ← Pixel 5 only
| android-Pixel-7-api34            |   42  |   42 |    0 | 280.5s |
| android-Galaxy-Tab-S8-api34      |   42  |   40 |    2 | 290.0s |   ← tablet layout issues

Step 5 - Device-farm vs local emulator decision

Use device farm whenUse local emulator/simulator when
Real-device behavior matters (camera, sensors)UI logic only
Specific OEM device under test (Samsung, foldable)Stock OS suffices
iOS testing on Linux CImacOS CI runner available
Release-tier matrix (cost amortizes over fewer runs)Per-PR (cost per run too high)
Regulatory / certification testingRapid iteration

Per-farm wiring:

# Firebase Test Lab (Android)
- run: |
    gcloud firebase test android run \
      --type instrumentation \
      --app app/build/outputs/apk/debug/app-debug.apk \
      --test app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
      --device model=Pixel7,version=34,locale=en \
      --device model=GalaxyS23,version=33,locale=en

# BrowserStack (iOS + Android)
- run: |
    npx browserstack-runner --config browserstack.json

Anti-patterns

Anti-patternWhy it failsFix
Same matrix for every commitCI cost explosion; team disables.Three-tier dispatch (Step 1, 3).
Single device per platformMisses tablet / older-OS regressions until release.Regression tier covers 3 / 3 (Step 1).
Device-farm runs on every PRPer-minute cost; budget exhausts mid-month.Farm only for release tier.
fail-fast: true on the matrixOne failing target cancels others; lose coverage signal.fail-fast: false (Step 2).
Hard-coded device list in CI yamlDevices added / OS versions deprecated → manual yaml updates everywhere.Centralized .matrix/devices.yaml (Step 1).
No aggregated reportPer-target results buried in CI logs; reviewer can't see the matrix.Aggregator job (Step 4).

Limitations

  • Cost-coverage trade-off. Even the release tier doesn't cover every config. Choose representative devices per OS family.
  • Per-platform CI runner availability. GitHub Actions macOS runners are paid (after free quota); large iOS matrix is expensive even on local sims.
  • Farm SLA varies. Farms have queue times; release tier may take 1-3 hours wall-time even with parallelism.
  • Device-farm flakiness. Real devices on shared infrastructure have intermittent issues; pair with retries (cautiously) and per-device flake tracking.

References

  • xcuitest-suite, espresso-suite, appium-testing, detox-testing, maestro-flows - per-platform runners this dispatcher orchestrates.
  • junit-xml-analysis (in the qa-test-reporting plugin) - parser for the per-target JUnit XML aggregation.
  • Per Mike Cohn's test pyramid (cited in test-pyramid-balancer), mobile UI tests are the most expensive layer; matrix dispatch is the cost-management discipline.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

コメント

ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。

まだコメントはありません。最初のコメントを書いてみませんか。

送信するとすぐに公開されます。メールアドレスや電話番号などの個人情報は書かないでください。URL は 2 つまでです。

0 / 1000 文字

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

同じリポジトリのスキル

Builds a CI gate that fails the build on **new** WCAG / a11y violations introduced by a PR while grandfathering pre-existing violations on a per-rule / per-page baseline. Aggregates verdicts from axe-core / pa11y / Lighthouse a11y / WAVE / IBM Equal Access scans. Use when a project has accumulated a11y debt and a strict "zero violations" gate would block every PR - the ratchet pattern lets the team ship while preventing regressions.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

Workflow skill that builds an A/B-test validity checklist from an experiment proposal, walking the canonical design-correctness gates - pre-registered OEC/power/guardrails, randomization unit + SRM check, assignment integrity, telemetry, peeking discipline, novelty/primacy, post-experiment SRM re-check - into a per-experiment checklist + sign-off form. Use when launching, auditing, or governing an experiment. For pitfall mechanics (guardrails, peeking) see experiment-results-interpreter's references; to read an already-valid result use experiment-results-interpreter; for per-SDK harness tests use experiment-sdk-testing - this gates DESIGN, not SDK code.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

The single install-flow skill: the reference contract for the PWA install flow (installability gate fields, `beforeinstallprompt` handshake, per-platform paths - Android WebAPK / iOS Share menu / Firefox no-op - and the `display-mode` post-install signal, in references/install-flow-reference.md) plus the build-an-X workflow that emits the Add-to-Home-Screen suite. Walks the four-stage timeline, emitting one test per gate cell per [web.dev/articles/install-criteria][install-criteria], the deferred-prompt → `prompt()` → `userChoice` chain per [web.dev/articles/customize-install][customize-install], the iOS Safari manual-metadata branch (`apple-touch-icon`) per [web.dev/learn/pwa/installation][learn-pwa], and the post-install `(display-mode: standalone)` MQ assertion. Output: a Playwright spec with per-stage cells plus a coverage matrix. Use when a PWA's manifest, icons, or install handler change, when install conversion drops at an unknown stage, or when triaging a flaky install assertion.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

Build-an-X workflow that uses an LLM to map existing tests to spec sections - given a spec doc + the test suite, the LLM identifies which tests cover which sections, surfaces uncovered sections (gap), and recommends specific tests to add. Output is a coverage matrix per spec ID. Scope is mapping tests that already exist and naming the gaps, not authoring tests for new acceptance criteria. Use when a spec doc and a test suite both exist but nobody can say which requirements are actually covered - before a release sign-off, an audit, or a decision about where to spend the next round of test effort.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

Generates tests from natural-language specs (acceptance criteria, user stories, requirements) using an LLM, with confidence scoring per test case (LLM self-assessment plus heuristics: assertion quality, naming, completeness), batching uncertain cases for human review, and integration with the team's existing test framework. Use when the user asks to generate unit tests from acceptance criteria, convert user stories to test cases, automate test creation from requirements, or augment a spec-driven test suite with AI-generated stubs that are then curated before merge.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

Configures Allure Report (test-runner adapter install, `allure-results` directory wiring, `categories.json` for failure classification, `history-trend.json` retention via the copy-history-between-runs pattern), runs the Allure CLI to convert `allure-results` to a static HTML site, and uploads the report as a CI artifact. Use when the team needs richer test reporting than JUnit XML - step-level attachments, per-test history, retry tracking, and severity / epic / feature labeling across framework-agnostic adapters (pytest, Jest, JUnit, TestNG, NUnit, Mocha). As a rich static HTML report generator, it is the open-source alternative to the sunset ExtentReports (JVM/.NET per-test HTML narrative); for hosted cross-run flakiness analytics rather than a static per-run report use currents-integration.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

testland のスキルをすべて見る

このスキルの問題を報告する