
capacitor-testing
Testing guide for Capacitor apps and plugins. Covers web-layer unit and component tests with Vitest and mocked Capacitor plugins (vi.mock('@capacitor/core'), registerPlugin), Playwright for the web build, Appium E2E with NATIVEAPP / WEBVIEW context switching, native plugin unit tests with Swift Testing vs XCTest (what can migrate, CAPPluginCall patterns, xcodebuild test on a simulator) and Android JUnit, plus an agent-driven verification loop on simulators and devices (build, install, launch, screenshot, UI hierarchy, tap, logs) with xcrun simctl, xcrun devicectl, adb, Xcode MCP device tools, and live reload via npx cap run --url (Capacitor 9) or -l --host --port (Capacitor 8). Use when adding tests, mocking plugins, "does it work on device", verifying a UI change on a simulator, migrating XCTest to Swift Testing, or setting up test CI. Do not use for crash log capture (ios-android-logs), WebView debugging sessions (debugging-capacitor), or build pipelines (capacitor
- Installs
- 1.3K
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/cap-go/capgo-skills --skill capacitor-testing- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads capacitor-testing automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Testing Capacitor Apps and Plugins
A Capacitor app has three layers to test: the web app (most logic), the native bridge and plugins (Swift/Kotlin), and the running app on a device. Pick the cheapest layer that can catch the bug.
When to Use
TRIGGER when:
- Adding unit, component or E2E tests to a Capacitor app
- Mocking Capacitor or plugin APIs in Vitest / Jest
- Writing or modernizing native unit tests for a plugin (Swift Testing, XCTest, JUnit)
- Verifying a change on a simulator, emulator or device ("test this", "does it work", "check on device")
- E2E tests that cannot find web elements in the app (WebView context)
- Setting up test jobs in CI
Do not use:
- Reading device or crash logs:
ios-android-logs - Safari Web Inspector / Chrome DevTools debugging:
debugging-capacitor - Build, signing and release pipelines:
capacitor-ci-cd - App Intents tests:
capacitor-app-intents(AppIntentsTesting)
Choose the layer
| What changed | Test with | Reference |
|---|---|---|
| Business logic, state, services that call plugins | Vitest with mocked plugins | references/web-unit-tests.md |
| Components (React, Vue, Angular, Svelte) | Testing Library on Vitest | references/web-unit-tests.md |
| Web flows (routing, forms) | Playwright against the dev server or dist | references/e2e.md |
| Plugin native code (Swift / Kotlin) | Swift Testing or XCTest; JUnit | references/native-plugin-tests.md |
| Full app on device, native UI, permissions, deep links | Agent verification loop; Appium or Maestro for repeatable suites | references/device-verification-loop.md, references/e2e.md |
| CI jobs | GitHub Actions matrix | references/ci.md |
Only load a reference when its layer is in play.
Facts that save time
- Plugins in jsdom run their web implementation, or throw
unimplementedwhen there is none.Capacitor.isNativePlatform()returnsfalsein tests unless you mock@capacitor/core. Mock at the plugin package boundary, not deep inside the app. - E2E tools see the WebView as one native element. Appium must switch to the
WEBVIEW_*context to find DOM elements. Capacitor makes the WebView inspectable in debug builds; for release builds setios.webContentsDebuggingEnabled/android.webContentsDebuggingEnabledincapacitor.config. Never ship release builds with it on by accident. - Detox is not an option. It targets React Native and does not drive Capacitor WebView content.
- Swift Testing cannot replace all XCTest. UI tests (XCUIApplication) and
measure {}performance tests stay XCTest. Unit tests can migrate one class at a time; a file can hold both. - iOS-only plugin packages cannot use
swift testbecause they depend on UIKit and Capacitor. Runxcodebuild test -scheme <Package> -destination 'platform=iOS Simulator,...'. - Capacitor 9 removed the deprecated Swift APIs. Tests that build calls with the old
CAPPluginCall(callbackId:options:success:error:)initializer orCAPPlugin(bridge:pluginId:pluginName:)must move toCAPPluginCall(callbackId:methodName:options:success:error:)and a plaininit(). - Live reload flags changed in Capacitor 9. Capacitor 9:
npx cap run ios --url http://<lan-ip>:5173. Capacitor 8:npx cap run ios -l --host <lan-ip> --port 5173. The Ionic CLI'sionic cap run ios -l --externalis a different tool.
Workflow
- Inspect. Read
package.json(test runner, framework,@capacitor/*versions),capacitor.config.*, existing test config (vitest.config.*,playwright.config.*,wdio.conf.*,.maestro/), and for pluginsPackage.swift, the podspec,ios/Tests/,android/src/test/. - Ask which layer the user wants if the request is general. Suggest the cheapest one that covers the risk.
- Write tests using the matching reference. Follow the project's existing runner and style; do not add a second runner.
- Run them and show the output. A test that was never run is not done.
- For UI-affecting changes, run the device verification loop (references/device-verification-loop.md) and report screenshots and findings.
Verify
# Web layer
npx vitest run
npx playwright test
# Plugin, iOS (from the plugin repo)
xcodebuild test -scheme <PluginPackageName> \
-destination "platform=iOS Simulator,name=$(xcrun simctl list devices available | grep -m1 -o 'iPhone [^(]*' | sed 's/ *$//')"
# Plugin, Android (from the plugin repo)
cd android && ./gradlew test
# App native tests, if the app has a test target
xcodebuild test -project ios/App/App.xcodeproj -scheme App -destination 'platform=iOS Simulator,name=<device>'
# CocoaPods projects: -workspace ios/App/App.xcworkspace
Report: tests added, command run, pass/fail counts, and anything that could not run locally (no simulator, no device, missing Android SDK).
Error Handling
| Symptom | Cause | Fix |
|---|---|---|
"<Plugin>" plugin is not implemented on web in Vitest | Real plugin running in jsdom | vi.mock('<plugin package>') in the setup file |
| Mock ignored, real plugin still called | Mock path differs from the import path, or the mock is registered after import | Mock the exact specifier the app imports. Put vi.mock in setupFiles or at the top of the test file |
Appium cannot find data-testid elements | Still in the NATIVE_APP context | await driver.switchContext(webviewContext) after waiting for getContexts() to list a WEBVIEW_* entry |
No WEBVIEW_* context | WebView not inspectable (release build) | Use a debug build, or enable webContentsDebuggingEnabled for the test build only |
| Android WebView context fails with a chromedriver version error | Chromedriver does not match the device WebView | Enable Appium's chromedriver autodownload (an insecure feature flag) or pin a matching chromedriver; check the Appium UiAutomator2 docs |
No such module 'Testing' | Old Xcode | Swift Testing needs the Xcode 16+ toolchain. Capacitor 9 needs Xcode 27 anyway |
error: no such module 'UIKit' from swift test | macOS host build of an iOS package | Use xcodebuild test with an iOS Simulator destination |
'init(callbackId:options:success:error:)' is deprecated / unavailable | Old test helper | Add methodName: |
Live reload: error: unknown option '-l' | Capacitor 9 CLI | Use --url http://<lan-ip>:<port> |
| Live reload app shows a blank page | Dev server bound to localhost, or wrong IP | Bind to 0.0.0.0 (Vite: --host), use the LAN IP, same Wi-Fi |
Related Skills
debugging-capacitor: inspect the WebView and native debuggersios-android-logs: stream logs during device runscapacitor-ci-cd: build and release pipelinescapacitor-ios-resizability: what to check in resized windows during device runscapacitor-plugin-upgrade-v8-to-v9: plugin API removals that affect test helpers
FAQ
What does the capacitor-testing skill do?
Testing guide for Capacitor apps and plugins. Covers web-layer unit and component tests with Vitest and mocked Capacitor plugins (vi.mock('@capacitor/core'), registerPlugin), Playwright for the web build, Appium E2E with NATIVEAPP / WEBVIEW context switching, native plugin unit tests with Swift Testing vs XCTest (what can migrate, CAPPluginCall patterns, xcodebuild test on a simulator) and Android JUnit, plus an agent-driven verification loop on simulators and devices (build, install, launch, screenshot, UI hierarchy, tap, logs) with xcrun simctl, xcrun devicectl, adb, Xcode MCP device tools, and live reload via npx cap run --url (Capacitor 9) or -l --host --port (Capacitor 8). Use when adding tests, mocking plugins, "does it work on device", verifying a UI change on a simulator, migrating XCTest to Swift Testing, or setting up test CI. Do not use for crash log capture (ios-android-logs), WebView debugging sessions (debugging-capacitor), or build pipelines (capacitor
How do I install capacitor-testing?
Run npx skills add https://github.com/cap-go/capgo-skills --skill capacitor-testing in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/capacitor-testing/ (personal) or .claude/skills/capacitor-testing/ (project).
Which AI agents can use capacitor-testing?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is capacitor-testing safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains capacitor-testing?
It is published by cap-go in cap-go/capgo-skills. It has 1,304 recorded installs.
More from cap-go/capgo-skills
capacitor-best-practices
cap-go/capgo-skills
Review and set up Capacitor apps against current best practices (Capacitor 8.5 stable, 9 alpha via @next). Use for a Capacitor codebase review, capacitor.config.ts audit, new project setup, aligning @capacitor/core/cli/ios/android and plugin majors, plugin patterns (availability checks, checkPermissions/requestPermissions, error code handling, web fallbacks), or release prep; or on " " plugin is not implemented on ios, Could not find the web assets directory, platform has not been added yet, a dev server.url shipped to production, lost edits in android/app/src/main/assets/public, SPM vs CocoaPods, or AppDelegate/UIScene drift. Do not use for security audits (capacitor-security), performance (capacitor-performance), tests (capacitor-testing), crashes (debugging-capacitor), major upgrades (capacitor-app-upgrades), SPM migration (cocoapods-to-spm), UIScene adoption (capacitor-uiscene-migration), or live updates (capgo-live-updates).
ionic-design
cap-go/capgo-skills
Builds and reviews Ionic Framework UI in Capacitor apps (Ionic 9 current, Ionic 8 still common) - page structure (ion-header/ion-content/ion-footer), lists, modern form syntax (label/labelPlacement on ion-input/ion-select), sheet modals, tabs + ion-router-outlet, CSS variable theming, dark palettes (palettes/dark.system.css, .ion-palette-dark), iOS vs MD mode, and Ionic 8 - 9 breaking changes (React Router 6, Vue Router 5, Angular 18-22 zoneless, removed ion-picker-legacy, boolean autocorrect, npx @ionic/migrate). Use when writing Ionic components, theming an Ionic app, fixing platform-mode styling, or upgrading @ionic/react, @ionic/vue, @ionic/angular. Do not use for Konsta UI (konsta-ui), Tailwind setup (tailwind-capacitor), raw safe-area CSS (safe-area-handling), keyboard resize (capacitor-keyboard), or Ionic Appflow/Enterprise migrations (ionic-appflow-migration, ionic-enterprise-sdk-migration).
capacitor-plugins
cap-go/capgo-skills
Pick, install, and wire up Capacitor plugins for native features (camera, filesystem, geolocation, biometrics, in-app purchases, social login, SQLite, calendar, contacts, health, BLE, NFC, etc.). Covers official @capacitor/ packages (Capacitor 8.5 stable, 9 alpha on next) plus the 145-package @capgo/ index, native permission keys (Info.plist, AndroidManifest, variables.gradle minSdk), npx cap sync / cap ls verification, and errors like '"Camera" plugin is not implemented on ios', 'unable to find plugin', UNIMPLEMENTED, and OS-PLUG- codes. Use for "which plugin should I use for X", adding a plugin, or a plugin call failing after install. Do not use for push setup (capacitor-push-notifications), splash assets (capacitor-splash-screen), keyboard layout (capacitor-keyboard), deep links (capacitor-deep-linking), OTA updates (capgo-live-updates), upgrading plugin source code (capacitor-plugin-upgrades), or adding SPM to a plugin (capacitor-plugin-spm-support).
debugging-capacitor
cap-go/capgo-skills
Diagnoses and fixes runtime bugs in Capacitor iOS/Android apps - white/blank screen on launch, startup crashes, "X" plugin is not implemented on ios/android, net::ERRCLEARTEXTNOTPERMITTED, App Transport Security blocks, CORS on capacitor://localhost, permission denials, live reload not connecting, and Capacitor 8.5+ UIScene regressions (appUrlOpen, universal links, pause/resume silent because AppDelegate callbacks stopped). Covers Safari Web Inspector, chrome://inspect, Xcode/LLDB, Android Studio, npx cap run --url (Capacitor 9) vs -l --host (8), xcrun simctl openurlprivacypush, xcrun devicectl device process launchopenURL, xctrace. Do not use for only reading device logs (ios-android-logs), the UIScene migration itself (capacitor-uiscene-migration), deep-link setup (capacitor-deep-linking), speed (capacitor-performance), crash SDKs (capacitor-native-observability), tests (capacitor-testing), or upgrades/build errors (capacitor-app-upgrades, cocoapods-to-spm).
safe-area-handling
cap-go/capgo-skills
Fixes notch, Dynamic Island, home indicator, display cutout, and system bar overlap in Capacitor apps. Covers viewport-fit=cover + env(safe-area-inset-), the Capacitor 8 SystemBars core plugin (insetsHandling, injected --safe-area-inset- CSS variables for Android WebView < 140, removal of android.adjustMarginsForEdgeToEdge), Android 15/16 enforced edge-to-edge (overlaysWebView and backgroundColor of @capacitor/status-bar no longer work at targetSdk 36), iOS contentInset, and insets that change at runtime on rotation, iPad/foldable resizable windows. Use when headers sit under the status bar, tab bars hide behind the gesture bar, env() returns 0 on Android, or layout broke after upgrading to Capacitor 8 / targetSdk 35+. Do not use for keyboard overlap (capacitor-keyboard), Ionic/Konsta component theming (ionic-design, konsta-ui), Tailwind utility setup (tailwind-capacitor), or iOS multi-window/resizability adoption (capacitor-ios-resizability).
capacitor-deep-linking
cap-go/capgo-skills
Implements and debugs deep links in Capacitor apps - custom URL schemes, iOS Universal Links (apple-app-site-association, Associated Domains entitlement), Android App Links (assetlinks.json, autoVerify), and routing via @capacitor/app appUrlOpen + App.getLaunchUrl(). Covers the Capacitor 8.5+ UIScene change where AppDelegate application(:open:options:) and continue userActivity stop being called and custom handling must move to SceneDelegate, plus cold vs warm launch testing. Use when links open Safari/Chrome instead of the app, appUrlOpen never fires, the launch URL is lost on cold start, or OAuth redirects do not return to the app. Do not use for the full UIScene migration (capacitor-uiscene-migration), push notification taps (capacitor-push-notifications), or social login plugin setup (capacitor-plugins).
Popular testing & qa skills
tdd
mattpocock/skills
Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.
grilling
mattpocock/skills
Grill the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their thinking, or uses any 'grill' trigger phrases.
migrate-to-shoehorn
mattpocock/skills
Migrate test files from as type assertions to @total-typescript/shoehorn. Use when user mentions shoehorn, wants to replace as in tests, or needs partial test data.
run-train
lllllllama/rigorpilot-skills
Rigor Train skill for deep learning research repositories. Use when a documented or selected training command should be run conservatively for startup verification, short-run verification, full kickoff, or resume, with command, config, seed, log, checkpoint, status, and metric evidence written to standardized trainoutputs/. Do not use for environment setup, exploratory sweeps, speculative idea implementation, or end-to-end orchestration.
test-driven-development
obra/superpowers
Use when implementing any feature or bugfix, before writing implementation code
finishing-a-development-branch
obra/superpowers
Use when implementation is complete, all tests pass, and you need to decide how to integrate the work