Revit Automate Test
Use this skill to prove a Revit plugin works through the same path a user actually uses:
understand feature behavior
-> map user actions to automation primitives
-> build/deploy package
-> real Revit .addin loading mechanism
-> current deployed artifact evidence
-> Revit Journal/plugin log startup evidence
-> real ribbon/command/WPF UI entry point
-> Revit model-view mouse input when the plugin waits for user picks
-> independent result evidence
Do not replace host E2E validation with direct service calls unless the user explicitly asks for service-level testing.
Do not treat bundled scripts as the test plan. The agent must analyze each plugin feature, choose the right action sequence, execute it with the scripts, and judge the result from independent evidence.
Feature-First Workflow
- Read current plugin code, XAML, command registration, and logs for the feature under test.
- Identify the user-visible workflow: ribbon entry, WPF windows, inputs, command buttons, Revit picks, expected model or data result.
- Map each user action to a capability: UIA dump/wait/invoke/set/toggle/select, model-view click, SendKeys, deployment evidence, Journal/log collection, assembly-load smoke.
- Define pass/fail evidence before executing. Prefer Revit model state, plugin logs, Journal lines, file/database side effects, or exported evidence.
- Execute with the bundled scripts and save high-signal artifacts: UIA dump, command output, logs, hashes, model/result evidence.
- If a step fails, diagnose the broken stage instead of blindly retrying.
Read references/feature-test-design.md when planning how to automate an unfamiliar plugin feature or when converting a manual test scenario into an executable Revit/WPF E2E flow.
Bundled Scripts
Prefer these scripts before rewriting PowerShell from scratch.
scripts/Test-DotNetAssemblyLoad.ps1
Use for fast pre-Revit validation of a deployed or staged .NET plugin assembly. It catches BadImageFormatException, illegal metadata, and malformed nested-type metadata before launching Revit.
Use -ExpectedType only when the type is known to be preserved by the obfuscation rules. For obfuscated Revit plugins, assembly load success is the pre-Revit gate; Journal API_SUCCESS is the entry-type proof.
& "$skillRoot\scripts\Test-DotNetAssemblyLoad.ps1" `
-AssemblyPath "$env:APPDATA\Autodesk\Revit\Addins\2027\Finio\Finio.dll" `
-TargetFramework net10.0
scripts/Get-RevitAddinDeployment.ps1
Use before launching Revit or after MSI install/uninstall to prove the real Addins deployment state. It parses the .addin, resolves the target assembly path, prints file version/hash/timestamp, lists top-level plugin directory contents, flags runtime/runtimes directories and .pdb files, and can also summarize the shared Data root.
& "$skillRoot\scripts\Get-RevitAddinDeployment.ps1" `
-RevitYear 2027 `
-PluginName Finio `
-ExpectedAssemblyName Finio.dll `
-DataRoot "$env:APPDATA\Finio\Data" `
-RequireAssembly `
-FailOnMissing
scripts/Get-RevitPluginEvidence.ps1
Use after a Revit run to collect the latest Journal evidence and optional plugin log tail. Add -RequireSuccess when the absence of API_SUCCESS should fail the test.
& "$skillRoot\scripts\Get-RevitPluginEvidence.ps1" `
-RevitYear 2027 `
-PluginName Finio `
-PluginLogPath "$env:APPDATA\Finio\Data\Logs\Finio$(Get-Date -Format yyyyMMdd).log" `
-RequireSuccess
scripts/Start-RevitPluginSmoke.ps1
Use for a conservative real Revit startup smoke. It refuses to launch when another Revit process already exists, checks Journal/log evidence, optionally clicks trust dialogs, and closes only the process it started.
& "$skillRoot\scripts\Start-RevitPluginSmoke.ps1" `
-RevitYear 2027 `
-PluginName Finio `
-PluginLogPath "$env:APPDATA\Finio\Data\Logs\Finio$(Get-Date -Format yyyyMMdd).log"
scripts/Test-RevitTemplatePackage.ps1
Use for .NET template repositories. It packs the template, installs it into a custom hive, generates a project, builds the generated installer in Release, and runs the assembly-load smoke on the generated R27 payload.
& "$skillRoot\scripts\Test-RevitTemplatePackage.ps1" `
-NuspecPath ".\Saury.Revit.Template.nuspec" `
-ShortName saury-revit `
-ProjectName TemplateSmoke
Read references/checklist.md when designing a new end-to-end flow, adding command/ribbon interaction, or diagnosing a flaky run.
Read references/revit-wpf-ui-automation.md when testing WPF plugin windows, changing input values, clicking Revit ribbon commands, or driving Revit model-view picks.
scripts/Invoke-RevitWpfUiAutomation.ps1
Use as the default UI action runner. It can dump Revit/UIA trees, wait for windows/controls, invoke or mouse-click buttons, set WPF TextBox values, toggle checkboxes, select radio/list items, send keys, and click fixed points inside the Revit model view.
& "$skillRoot\scripts\Invoke-RevitWpfUiAutomation.ps1" `
-ProcessName Revit `
-Action Invoke `
-NameRegex "Cabinet|Create Cabinet" `
-ControlType Button `
-MouseFallback
& "$skillRoot\scripts\Invoke-RevitWpfUiAutomation.ps1" `
-ProcessName Revit `
-WindowTitleRegex "Finio.*Cabinet" `
-Action SetValue `
-AutomationId CabinetWidthInput `
-Value 1200
Test Boundary
Pick the narrowest boundary that proves the user's claim.
| Boundary |
Use when |
Evidence |
| Assembly-load smoke |
Confuser/obfuscation, bad metadata, packaged DLL loadability |
LOAD_SMOKE_OK, no BadImageFormatException |
| Deployment evidence |
MSI/build deploy state, .addin path, stale files, uninstall residue |
.addin entry, assembly version/hash/timestamp, plugin dir summary |
| Package/install smoke |
MSI output, feature selection, deployment path |
MSI exit code/log, deployed artifact hash/timestamp |
| Revit startup smoke |
.addin loading, startup exceptions, trust prompt behavior |
Journal API_SUCCESS, plugin startup log |
| WPF/UI Automation E2E |
Ribbon command, WPF parameter panel, Revit pick workflow |
UIA dump/actions plus plugin log/model/file/database side effect |
| Template smoke |
Generated project and generated installer behavior |
custom-hive generation, generated Release MSI, load smoke |
For plugin acceptance, prefer package/install smoke + Revit startup smoke + at least one WPF/UI Automation E2E path. For obfuscation changes, always run assembly-load smoke before launching Revit.
Required Facts
Before running or editing tests, identify:
- Revit year and executable path.
- Plugin loading mechanism:
.addin, Addins directory, registry, or installer feature.
- Build command and whether it deploys to the real Revit Addins location.
- Current deployed artifact path and version/hash/timestamp.
- Plugin startup log path, if the plugin has one.
- Latest Revit Journal directory.
- Real user entry point when testing behavior: ribbon button, WPF window title, command button, input AutomationId, shortcut, dialog, or model-view click.
- Current WPF locator state:
AutomationProperties.AutomationId, Name, x:Name, button Content, tab Header, and custom-control templates.
- Safety boundary: existing Revit processes, unsaved documents, paid APIs, credentials, destructive file/database changes.
Ask the user only if continuing could test the wrong plugin, wrong Revit version, wrong account, or a destructive target. Otherwise choose a conservative test path and proceed.
Standard Workflows
Obfuscated MSI Plugin
- Build the Release installer with the project's documented command.
- Confirm build logs show the intended obfuscation/protection list.
- Install the MSI with a verbose log when possible.
- Verify the
.addin, resolved assembly, version/hash/timestamp, and plugin directory with Get-RevitAddinDeployment.ps1.
- Run
Test-DotNetAssemblyLoad.ps1 on the deployed main assembly.
- Launch Revit only after deployment evidence and assembly load both succeed.
- Collect Journal and plugin log evidence with
Get-RevitPluginEvidence.ps1.
- If needed, trigger a real ribbon command using UI Automation or a documented command entry point.
If assembly-load smoke fails, do not retry Revit. Diagnose the obfuscator/protection list first.
Revit Template Repository
- Run
Test-RevitTemplatePackage.ps1 against the template .nuspec.
- Confirm the generated project name replaces assembly names, installer names, environment variable prefixes,
.addin, and output MSI names.
- Confirm the generated installer
Release build runs obfuscation for every supported Revit year.
- Run assembly-load smoke on the generated R27 payload.
Use a custom hive and temp directory so the test does not pollute the user's global template installation.
Real Revit Startup
- Check for existing
Revit processes. Do not force-close user-owned sessions unless the user clearly authorized it.
- Start Revit with the target year/language.
- Handle trust dialogs, license prompts, and modal blockers as part of the test.
- Wait by evidence, not fixed sleeps: Journal lines, plugin log, window readiness, or command UI availability.
- Close only the Revit process started by the test.
WPF UI Automation E2E
- Re-read the current plugin XAML before writing locators. Prefer
AutomationProperties.AutomationId; add stable IDs when testability changes are in scope.
- Write a feature-specific action/evidence plan before executing. Use
references/feature-test-design.md.
- Dump the Revit UIA tree with
Invoke-RevitWpfUiAutomation.ps1 -Action Dump and keep the dump as evidence.
- Invoke the Revit ribbon command by stable UIA locator. Use
-MouseFallback only when Revit exposes the button without InvokePattern.
- Wait for the plugin WPF window by title regex.
- Set WPF inputs by
AutomationId, toggle switches, select radio/list items, and invoke the plugin command button.
- When the plugin enters a Revit selection loop, click model geometry by window-relative coordinates in a fixed test RVT/view.
- Send
{ESC} after continuous pick workflows.
- Verify the downstream result through plugin logs, Journal, Revit model state, exported evidence, or database/file side effects.
Do not rely on coordinate clicks for WPF controls. Coordinates are acceptable only for the Revit model canvas, because UIA does not expose individual Revit elements/faces as controls.
Failure Triage
Diagnose by stage:
| Symptom |
Inspect first |
| Build succeeds but Revit cannot load |
Assembly-load smoke, obfuscation rules, deployed DLL hash |
| MSI says success but plugin is absent |
Get-RevitAddinDeployment.ps1, .addin root, feature selection, verbose MSI log |
| Uninstall leaves plugin files |
deployment evidence script on every supported Revit year, MSI ownership, manual leftovers |
Illegal tables in compressed metadata stream |
invalid metadata or similar metadata protection |
Enclosing type(s) not found |
constants/string protection or malformed obfuscator metadata |
| Plugin has no startup log |
.addin, Addins path, trust dialog, Journal startup exception |
Journal has API_ERROR |
exception near Starting External Application, plugin dependencies |
| Ribbon button missing |
startup/Ribbon initialization, add-in load, UIA tree dump, localized button Name |
| WPF input missing |
XAML lacks AutomationProperties.AutomationId, template hides inner control, wrong window title regex |
| Button clicked but no result |
command disabled, wrong window, pending modal dialog, missing Revit external event/log side effect |
| Revit model click misses |
unstable test model/view/window size, wrong window-relative coordinates |
| Tool-like text but no execution |
protocol leakage; require server-side call/log evidence |
Reporting Standard
Report only high-signal facts:
- Commands run and what each proved.
- Deployed artifact path/version/hash if relevant.
- Revit Journal evidence lines.
- Plugin log evidence lines.
- Whether failure was build, package, load, startup, UI invocation, or business result.
- What remains unverified.
Do not include secrets. Redact tokens, API keys, credentials, connection strings, checkout links, and paid-service details.
1---2name: revit-automate-test3description: Design, run, stabilize, and diagnose real-host automation tests for Revit plugins and Revit plugin templates. Use when Codex needs to analyze a Revit plugin feature and decide how to automate it, verify MSI deployment, .addin loading, Confuser/obfuscation output, Revit Journal evidence, plugin startup logs, Revit ribbon/command entry points, WPF plugin windows, UI Automation flows, TextBox/CheckBox/RadioButton input changes, Revit model-view mouse clicks, generated template projects, or flaky Revit plugin E2E smoke tests.4license: MIT5---67# Revit Automate Test89Use this skill to prove a Revit plugin works through the same path a user actually uses:1011```text12understand feature behavior13 -> map user actions to automation primitives14 -> build/deploy package15 -> real Revit .addin loading mechanism16 -> current deployed artifact evidence17 -> Revit Journal/plugin log startup evidence18 -> real ribbon/command/WPF UI entry point19 -> Revit model-view mouse input when the plugin waits for user picks20 -> independent result evidence21```2223Do not replace host E2E validation with direct service calls unless the user explicitly asks for service-level testing.24Do not treat bundled scripts as the test plan. The agent must analyze each plugin feature, choose the right action sequence, execute it with the scripts, and judge the result from independent evidence.2526## Feature-First Workflow27281. Read current plugin code, XAML, command registration, and logs for the feature under test.292. Identify the user-visible workflow: ribbon entry, WPF windows, inputs, command buttons, Revit picks, expected model or data result.303. Map each user action to a capability: UIA dump/wait/invoke/set/toggle/select, model-view click, SendKeys, deployment evidence, Journal/log collection, assembly-load smoke.314. Define pass/fail evidence before executing. Prefer Revit model state, plugin logs, Journal lines, file/database side effects, or exported evidence.325. Execute with the bundled scripts and save high-signal artifacts: UIA dump, command output, logs, hashes, model/result evidence.336. If a step fails, diagnose the broken stage instead of blindly retrying.3435Read `references/feature-test-design.md` when planning how to automate an unfamiliar plugin feature or when converting a manual test scenario into an executable Revit/WPF E2E flow.3637## Bundled Scripts3839Prefer these scripts before rewriting PowerShell from scratch.4041```text42scripts/Test-DotNetAssemblyLoad.ps143```4445Use for fast pre-Revit validation of a deployed or staged .NET plugin assembly. It catches `BadImageFormatException`, illegal metadata, and malformed nested-type metadata before launching Revit.46Use `-ExpectedType` only when the type is known to be preserved by the obfuscation rules. For obfuscated Revit plugins, assembly load success is the pre-Revit gate; Journal `API_SUCCESS` is the entry-type proof.4748```powershell49& "$skillRoot\scripts\Test-DotNetAssemblyLoad.ps1" `50 -AssemblyPath "$env:APPDATA\Autodesk\Revit\Addins\2027\Finio\Finio.dll" `51 -TargetFramework net10.052```5354```text55scripts/Get-RevitAddinDeployment.ps156```5758Use before launching Revit or after MSI install/uninstall to prove the real Addins deployment state. It parses the `.addin`, resolves the target assembly path, prints file version/hash/timestamp, lists top-level plugin directory contents, flags `runtime`/`runtimes` directories and `.pdb` files, and can also summarize the shared Data root.5960```powershell61& "$skillRoot\scripts\Get-RevitAddinDeployment.ps1" `62 -RevitYear 2027 `63 -PluginName Finio `64 -ExpectedAssemblyName Finio.dll `65 -DataRoot "$env:APPDATA\Finio\Data" `66 -RequireAssembly `67 -FailOnMissing68```6970```text71scripts/Get-RevitPluginEvidence.ps172```7374Use after a Revit run to collect the latest Journal evidence and optional plugin log tail. Add `-RequireSuccess` when the absence of `API_SUCCESS` should fail the test.7576```powershell77& "$skillRoot\scripts\Get-RevitPluginEvidence.ps1" `78 -RevitYear 2027 `79 -PluginName Finio `80 -PluginLogPath "$env:APPDATA\Finio\Data\Logs\Finio$(Get-Date -Format yyyyMMdd).log" `81 -RequireSuccess82```8384```text85scripts/Start-RevitPluginSmoke.ps186```8788Use for a conservative real Revit startup smoke. It refuses to launch when another Revit process already exists, checks Journal/log evidence, optionally clicks trust dialogs, and closes only the process it started.8990```powershell91& "$skillRoot\scripts\Start-RevitPluginSmoke.ps1" `92 -RevitYear 2027 `93 -PluginName Finio `94 -PluginLogPath "$env:APPDATA\Finio\Data\Logs\Finio$(Get-Date -Format yyyyMMdd).log"95```9697```text98scripts/Test-RevitTemplatePackage.ps199```100101Use for `.NET template` repositories. It packs the template, installs it into a custom hive, generates a project, builds the generated installer in `Release`, and runs the assembly-load smoke on the generated R27 payload.102103```powershell104& "$skillRoot\scripts\Test-RevitTemplatePackage.ps1" `105 -NuspecPath ".\Saury.Revit.Template.nuspec" `106 -ShortName saury-revit `107 -ProjectName TemplateSmoke108```109110Read `references/checklist.md` when designing a new end-to-end flow, adding command/ribbon interaction, or diagnosing a flaky run.111Read `references/revit-wpf-ui-automation.md` when testing WPF plugin windows, changing input values, clicking Revit ribbon commands, or driving Revit model-view picks.112113```text114scripts/Invoke-RevitWpfUiAutomation.ps1115```116117Use as the default UI action runner. It can dump Revit/UIA trees, wait for windows/controls, invoke or mouse-click buttons, set WPF TextBox values, toggle checkboxes, select radio/list items, send keys, and click fixed points inside the Revit model view.118119```powershell120& "$skillRoot\scripts\Invoke-RevitWpfUiAutomation.ps1" `121 -ProcessName Revit `122 -Action Invoke `123 -NameRegex "Cabinet|Create Cabinet" `124 -ControlType Button `125 -MouseFallback126127& "$skillRoot\scripts\Invoke-RevitWpfUiAutomation.ps1" `128 -ProcessName Revit `129 -WindowTitleRegex "Finio.*Cabinet" `130 -Action SetValue `131 -AutomationId CabinetWidthInput `132 -Value 1200133```134135## Test Boundary136137Pick the narrowest boundary that proves the user's claim.138139| Boundary | Use when | Evidence |140| --- | --- | --- |141| Assembly-load smoke | Confuser/obfuscation, bad metadata, packaged DLL loadability | `LOAD_SMOKE_OK`, no `BadImageFormatException` |142| Deployment evidence | MSI/build deploy state, `.addin` path, stale files, uninstall residue | `.addin` entry, assembly version/hash/timestamp, plugin dir summary |143| Package/install smoke | MSI output, feature selection, deployment path | MSI exit code/log, deployed artifact hash/timestamp |144| Revit startup smoke | `.addin` loading, startup exceptions, trust prompt behavior | Journal `API_SUCCESS`, plugin startup log |145| WPF/UI Automation E2E | Ribbon command, WPF parameter panel, Revit pick workflow | UIA dump/actions plus plugin log/model/file/database side effect |146| Template smoke | Generated project and generated installer behavior | custom-hive generation, generated Release MSI, load smoke |147148For plugin acceptance, prefer package/install smoke + Revit startup smoke + at least one WPF/UI Automation E2E path. For obfuscation changes, always run assembly-load smoke before launching Revit.149150## Required Facts151152Before running or editing tests, identify:153154- Revit year and executable path.155- Plugin loading mechanism: `.addin`, Addins directory, registry, or installer feature.156- Build command and whether it deploys to the real Revit Addins location.157- Current deployed artifact path and version/hash/timestamp.158- Plugin startup log path, if the plugin has one.159- Latest Revit Journal directory.160- Real user entry point when testing behavior: ribbon button, WPF window title, command button, input AutomationId, shortcut, dialog, or model-view click.161- Current WPF locator state: `AutomationProperties.AutomationId`, `Name`, `x:Name`, button `Content`, tab `Header`, and custom-control templates.162- Safety boundary: existing Revit processes, unsaved documents, paid APIs, credentials, destructive file/database changes.163164Ask the user only if continuing could test the wrong plugin, wrong Revit version, wrong account, or a destructive target. Otherwise choose a conservative test path and proceed.165166## Standard Workflows167168### Obfuscated MSI Plugin1691701. Build the Release installer with the project's documented command.1712. Confirm build logs show the intended obfuscation/protection list.1723. Install the MSI with a verbose log when possible.1734. Verify the `.addin`, resolved assembly, version/hash/timestamp, and plugin directory with `Get-RevitAddinDeployment.ps1`.1745. Run `Test-DotNetAssemblyLoad.ps1` on the deployed main assembly.1756. Launch Revit only after deployment evidence and assembly load both succeed.1767. Collect Journal and plugin log evidence with `Get-RevitPluginEvidence.ps1`.1778. If needed, trigger a real ribbon command using UI Automation or a documented command entry point.178179If assembly-load smoke fails, do not retry Revit. Diagnose the obfuscator/protection list first.180181### Revit Template Repository1821831. Run `Test-RevitTemplatePackage.ps1` against the template `.nuspec`.1842. Confirm the generated project name replaces assembly names, installer names, environment variable prefixes, `.addin`, and output MSI names.1853. Confirm the generated installer `Release` build runs obfuscation for every supported Revit year.1864. Run assembly-load smoke on the generated R27 payload.187188Use a custom hive and temp directory so the test does not pollute the user's global template installation.189190### Real Revit Startup1911921. Check for existing `Revit` processes. Do not force-close user-owned sessions unless the user clearly authorized it.1932. Start Revit with the target year/language.1943. Handle trust dialogs, license prompts, and modal blockers as part of the test.1954. Wait by evidence, not fixed sleeps: Journal lines, plugin log, window readiness, or command UI availability.1965. Close only the Revit process started by the test.197198### WPF UI Automation E2E1992001. Re-read the current plugin XAML before writing locators. Prefer `AutomationProperties.AutomationId`; add stable IDs when testability changes are in scope.2012. Write a feature-specific action/evidence plan before executing. Use `references/feature-test-design.md`.2023. Dump the Revit UIA tree with `Invoke-RevitWpfUiAutomation.ps1 -Action Dump` and keep the dump as evidence.2034. Invoke the Revit ribbon command by stable UIA locator. Use `-MouseFallback` only when Revit exposes the button without `InvokePattern`.2045. Wait for the plugin WPF window by title regex.2056. Set WPF inputs by `AutomationId`, toggle switches, select radio/list items, and invoke the plugin command button.2067. When the plugin enters a Revit selection loop, click model geometry by window-relative coordinates in a fixed test RVT/view.2078. Send `{ESC}` after continuous pick workflows.2089. Verify the downstream result through plugin logs, Journal, Revit model state, exported evidence, or database/file side effects.209210Do not rely on coordinate clicks for WPF controls. Coordinates are acceptable only for the Revit model canvas, because UIA does not expose individual Revit elements/faces as controls.211212## Failure Triage213214Diagnose by stage:215216| Symptom | Inspect first |217| --- | --- |218| Build succeeds but Revit cannot load | Assembly-load smoke, obfuscation rules, deployed DLL hash |219| MSI says success but plugin is absent | `Get-RevitAddinDeployment.ps1`, `.addin` root, feature selection, verbose MSI log |220| Uninstall leaves plugin files | deployment evidence script on every supported Revit year, MSI ownership, manual leftovers |221| `Illegal tables in compressed metadata stream` | `invalid metadata` or similar metadata protection |222| `Enclosing type(s) not found` | constants/string protection or malformed obfuscator metadata |223| Plugin has no startup log | `.addin`, Addins path, trust dialog, Journal startup exception |224| Journal has `API_ERROR` | exception near `Starting External Application`, plugin dependencies |225| Ribbon button missing | startup/Ribbon initialization, add-in load, UIA tree dump, localized button `Name` |226| WPF input missing | XAML lacks `AutomationProperties.AutomationId`, template hides inner control, wrong window title regex |227| Button clicked but no result | command disabled, wrong window, pending modal dialog, missing Revit external event/log side effect |228| Revit model click misses | unstable test model/view/window size, wrong window-relative coordinates |229| Tool-like text but no execution | protocol leakage; require server-side call/log evidence |230231## Reporting Standard232233Report only high-signal facts:234235- Commands run and what each proved.236- Deployed artifact path/version/hash if relevant.237- Revit Journal evidence lines.238- Plugin log evidence lines.239- Whether failure was build, package, load, startup, UI invocation, or business result.240- What remains unverified.241242Do not include secrets. Redact tokens, API keys, credentials, connection strings, checkout links, and paid-service details.