Installers, setup wizards and packaged applications
How SPART-Desk drives what installs an application and what the install leaves behind: an installer's own wizard (NSIS, Windows Installer), a ClickOnce deployment and its maintenance dialog, and a packaged (MSIX) application started by its app ID. For anyone whose tests install the application they test, or test the installer itself.
The kinds supported:
- NSIS (Modern UI 2) installers and their uninstallers.
- Windows Installer packages (MSI, WixUI_InstallDir dialogs).
- ClickOnce deployments: the security dialog, the installed application, the maintenance dialog.
- MSIX / packaged applications, a packaged WinUI 3 application among them, registered and started by their app ID.
Launch, or attach
An installer's wizard is the window of the process the launch spawned, found as any launched program's window is:
- NSIS:
launch({ executable: "setup.exe" }); the uninstaller is launched from where it lies with_?=<folder>, so that the process the test started is the one showing the wizard rather than a copy in%TEMP%. - Windows Installer:
launch({ executable: "msiexec.exe", args: ["/i", package] }). The client process shows the dialogs; the install itself runs in the Windows Installer service, and the Completed dialog follows by itself.desktop.run("msiexec.exe", ["/x", package, "/qn"])removes a package silently, its exit code the result. - ClickOnce: the ClickOnce service (
dfsvc.exe) shows every dialog and starts the application in a process of its own, so the launch names what it looks for:launch({ executable: "rundll32.exe", args: ["dfshim.dll,ShOpenVerbApplication", deployment], target: { processName: "dfsvc", windowTitle: "Application Install - Security Warning" }, joinExisting: true })opens a deployment manifest as a double click does (the service lingers after an operation, hencejoinExisting); after Install,desktop.attach({ processName })reaches the application. The Start menu reference the install makes (.appref-ms) is launched as an executable with the application's process named:launch({ executable: appref, target: { processName: "ClickOnceForm" } }); one that names no process is refused at once, and the sandbox refuses the reference as it refuses a shortcut. The deployment is removed through its maintenance dialog (rundll32.exe dfshim.dll,ShArpMaintain <identity>, theUninstallStringClickOnce registers underHKCU\…\Uninstall): "Remove the application from this computer", OK. There is no silent uninstall. - Packaged applications:
launch({ appId }), withargs;launch({ uri, appId })for a protocol the package declares. Registering a package is the test's business, not the engine's.
The dialogs
NSIS and Windows Installer draw their wizards with Win32 dialogs and common
controls: buttons by their names (Next, Back, Install, Finish, NSIS's
I Agree), a licence as a rich edit or a check box ("I accept the terms in the
License Agreement", WixUI), the folder as the one text box of the Destination
Folder dialog (Windows Installer appends a backslash), components as a check
box tree (NSIS), the log as a list view. Windows Installer's dialogs are
titled <ProductName> Setup. ClickOnce's dialogs are the service's: the
security warning names the application and its publisher ("Unknown Publisher"
for a certificate the machine does not trust), with Install and Don't Install; the maintenance dialog has two radio buttons and OK.
Elevation and scope
SPART-Desk never elevates (elevated.md). An installer that asks
for elevation (a per-machine MSI, an NSIS script with
RequestExecutionLevel admin) raises the consent prompt on the secure
desktop, which no automation reaches: run the test runner elevated for it.
Install per user where you can: NSIS under %LOCALAPPDATA%, an MSI with
Scope="perUser" (a registry value under HKCU as its component's key path),
ClickOnce in the user's ClickOnce store, an MSIX layout registered for the
user. Leave the machine as the test found it: remove what was installed,
before and after a run, whatever happened.
close() on a wizard
app.close() asks the window to close, as the close button does, and stops
the process when it is still there three seconds later. An NSIS wizard
closes; Windows Installer's client answers with "Are you sure you want to
cancel?", keeps its window, and is stopped: the service rolls the install back
and nothing is left installed. A ClickOnce dialog belongs to the service,
which is never stopped: close() on a dialog joined with joinExisting
stops nothing, and the dialog is left to its own buttons.
In the Windows Sandbox
The Windows Sandbox runtime may change in minor versions until its prerequisites are validated.
An installer's executable is copied into the guest and run there as any
program is (runtime-windows-sandbox.md); an MSI
is run through desktop.run("msiexec.exe", ["/i", …]) from a folder a launch
copied in, and its dialogs attached to by their title. A .appref-ms names a
deployment installed for this machine's user, and is refused in the guest as a
shortcut is. A packaged application is registered in the guest by the test
and started by its app ID.