test-native-extension
Validate a third-party control repo across four automated layers plus one printed manual recipe. Layer 1 asserts native-source structure (Android getName() and iOS +moduleName to manifest nativeModule; @ReactMethod / RCT_EXPORT_METHOD to methods; no @ReactModule) plus load/init readiness (ReactPackage public no-arg constructor, iOS [cls new] no-arg init, requiresMainQueueSetup NO, non-throwing eager construction), so launch-time crashes surface before any build. Layer 2 validates the committed `./manifest.json` against the ppmplugin-format rules. Layer 3 asserts request/response/error-code agreement across native and PCF. Layer 4 compiles the PCF (auto-skipped if absent). Layer 5 prints a device end-to-end recipe. Native compile belongs to /build-android-binary and /build-ios-binary — this is the cheap structural pre-flight before those slow builds. Reports pass/fail per layer with a fix hint and updates .extension-state.md.
git clone --depth 1 https://github.com/microsoft/power-platform-skills /tmp/test-native-extension && cp -r /tmp/test-native-extension/plugins/power-apps-mobile-extension/skills/test-native-extension ~/.claude/skills/test-native-extensionSKILL.md
# /test-native-extension
Runs the 4-layer validation ladder for a third-party control repo — the one that ships as a `.ppmplugin` binary bundle, not as a TypeScript extension. Layers 1–4 are automated; Layer 5 is interactive (requires a real device or simulator and the Companion PCF deployed to a test environment).
| Layer | What | Mode | Speed | Requires |
|---|---|---|---|---|
| 0 | Holistic contract consistency (native ↔ manifest ↔ PCF cross-check) | Automated, **warn-only** | seconds | at least a native module on disk |
| 1 | Native-source structure asserts (Android `getName()` ↔ iOS `+moduleName` ↔ manifest) | Automated, grep/parse | seconds | `android/` and/or `ios/` |
| 2 | Manifest validation (`ppmplugin-format §4` rules) | Automated | seconds (skipped only if no manifest on disk) | `./manifest.json` (committed; else staged copy) |
| 3 | Native-source contract asserts (request/response/error grep cross-check) | Automated | seconds | native module(s) |
| 4 | PCF compile (`npm run build` in `pcf/<Pascal>PCF/`) | Automated | seconds (after first install) | `pcf/<Pascal>PCF/` must exist (skipped otherwise) |
| 5 | Manual device / simulator end-to-end | **Recipe-only — skill prints, user runs on own time** | 5–10m, off-skill | `pcf/` must exist + PCF deployed |
Run order is layer-by-layer for Layers 1–4. **Stop on the first failure** in the automated layers. Layer 5 is **not** gated by the skill — it prints the device recipe and exits; the user runs it on their own time and updates `.extension-state.md` manually.
> **What this skill does NOT validate:** native code compilation into a loadable DEX / framework. That's the job of [`/build-android-binary`](../build-android-binary/SKILL.md) and [`/build-ios-binary`](../build-ios-binary/SKILL.md) — they run the real Gradle / xcodebuild toolchain against the pinned RN version and surface the real compiler error. Standalone `pod lib lint` and `./gradlew assembleDebug` from this skill would give false-confidence (they resolve dependencies from public CDN/maven, not against the wrap host's pinned versions). This skill is the **structural** pre-flight that runs in seconds with no toolchain — it asserts the native source is *shaped* correctly (right base class, right symbols, the Android `getName()` ↔ iOS `+moduleName` ↔ manifest agreement) so the build skills don't fail late on a fixable-in-seconds mistake. There is **no TypeScript / `INativeExtension` layer** in this track to type-check — a native-only `.ppmplugin` bundle dispatches straight to `NativeModules.<nativeModule>.<method>` ([`ppmplugin-format §2`](../../shared/ppmplugin-format.md) — *Runtime dispatch contract*).
---
## Step 1 — Read the shared docs and PRD
1. Read [`shared/shared-instructions.md`](../../shared/shared-instructions.md), [`shared/naming-conventions.md`](../../shared/naming-conventions.md), [`shared/ppmplugin-format.md`](../../shared/ppmplugin-format.md).
2. Apply the **per-skill minimal prereq policy** ([`shared-instructions.md §1.5`](../../shared/shared-instructions.md)). Layers 1–3 need **no toolchain** (pure read + grep + validate against the working tree). Layer 4 needs **Node + npm** only when a PCF is present — and only for the *first* run (to `npm install` the PCF's own deps from the public npm registry). This track is self-contained and requires no package-feed or source-control authentication ([`shared-instructions §0a`](../../shared/shared-instructions.md)). Run the **`/test-native-extension` check** from [`prereq-check.md`](../../shared/prereq-check.md) (Layers 0–3 need nothing; Node + npm only if a PCF is present for Layer 4 — there is no "baseline" check in this self-contained track).
**Print the prereq status as a visible block per `shared-instructions.md §9.2`** before continuing:
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Prereq check — /test-native-extension
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🟢 ✓ git installed
🟢 ✓ Node 20+ installed (only needed for Layer 4 — PCF compile)
🟢 ✓ npm installed (only needed for Layer 4 — PCF compile)
🟢 3 checks passed. Ready to proceed.
```
If no `pcf/` is present, Node/npm aren't needed at all — note them as `n/a (no PCF)` rather than failing. Layers 1–3 always run regardless. If any check fails, print the `→ Fix:` line for that check and STOP.
3. Read `./PRD.md`. If missing, the Layer 3 contract asserts fall back to the native source itself as source-of-truth (it's still useful) — note it and continue rather than STOP.
4. Read `./.extension-state.md`. If Phase is below `manifest` (no native module on disk yet), STOP — there's nothing scaffolded to test.
---
> **OS-neutral — run these checks with the built-in Read/Grep tools, not a shell.** Every extraction/assert in this skill (the `find` / `grep` / `sed` / `awk` snippets below) is shown in **bash for readability only** — it describes *what to match*, not a shell to execute. RUN them with the agent's built-in **Read** and **Grep** tools (plus your own parsing), which behave identically on macOS, Linux, and **Windows PowerShell**. Do **NOT** shell out to `grep`/`sed`/`awk`/`sort`/`find` — they aren't on a stock Windows box, and Layers 0–3 are deliberately pure read+parse (no toolchain) so they run everywhere. Layer 4's `npm run build` is the only real command, and npm is cross-platform.
## Step 2 — Confirm scope with the user
First, **auto-detect** whether the PCF companion is on disk — use the **Grep tool** (`glob: pcf/**/ControlManifest.Input.xml`) so case differences and minor layout variations don't trip the check. (Illustrative bash — *don't* run it verbatim on Windows):
```bash
PCF_MANIFEST=$(find pcf -type f -name "ControlManifest.Input.xml" 2>/dev/null | head -1)
[ -n "$PCF_MANIFEST" ] && PCF_PROJECT_ROOT=$(dirname $(dirname "$PCF_MANIFEST"))
```
If `$PCF_MANIFEST` is set, the PCF is scaffolded; use `$PCF_PROJECT_ROOT` (e.g. `pcf/<Pascal>PCF`)Guide the user to add a data source, connection, or API connector to a Canvas App via Power Apps Studio, then verify and continue. USE WHEN the user asks to add a data source, add a connection, add an API, add a connector, connect to SharePoint / Dataverse / SQL / Excel / OneDrive / Teams / Office 365, or any similar request to make new data available to the app. DO NOT USE WHEN the user is asking to list or describe existing data sources — call list_data_sources or list_apis directly instead.
Creates or edits a Power Apps Canvas App through the Canvas Authoring MCP coauthoring session. Handles new app generation, direct targeted edits, complex multi-screen changes, responsive layout, per-screen self-QA, and compile-error convergence. Trigger on requests to create, build, generate, modify, update, change, fix, or edit a Canvas App or .pa.yaml files.
Configure the Canvas Authoring MCP server for the current coauthoring session. USE WHEN "configure MCP", "set up MCP server", "MCP not working", "connect Canvas Apps MCP", "canvas-authoring not available", "MCP not configured", "set up canvas apps".
[DEPRECATED — use canvas-app instead] Generate a complete Power Apps canvas app.
>
Adds Azure DevOps connector to a Power Apps code app. Use when querying work items, creating bugs, managing pipelines, or making ADO API calls.
Use when adding a Power Platform connector to an Expo/React Native Power Apps mobile app and no dedicated mobile connector skill exists.
Use when adding an unspecified data source to an Expo/React Native Power Apps mobile app; routes to Dataverse, SharePoint, or another connector.