fix(ci): wait for asynchronous NSIS uninstaller surface cleanup
Windows CI / verify (push) Failing after 3m46s
Windows CI / verify (push) Failing after 3m46s
The installer smoke asserted a clean registry and shortcut surface immediately after the silent uninstall returned and the installation directory disappeared. NSIS uninstallers run detached through a temporary copy, so shortcut and registry removal completes after the invoked process exits, and on current runner images the immediate check raced that cleanup and failed with leftover HKCU keys and shortcuts. The smoke now polls the exact same surface assertions until a bounded deadline, keeping a genuinely dirty uninstall failing, with contract coverage for the tolerated asynchronous cleanup and the persistent failure case.
This commit is contained in:
@@ -11,6 +11,7 @@ const {
|
||||
assertInstallerSurfaceClean,
|
||||
assertPathInside,
|
||||
assertShortcutDetails,
|
||||
waitForInstallerSurfaceClean,
|
||||
createInstallerPhases,
|
||||
readShortcutDetails,
|
||||
registryKeys
|
||||
@@ -222,6 +223,41 @@ test('clean surface contract includes both registry hives and both shortcut scop
|
||||
}), /HKLM.*Twitch VOD Manager\.lnk/i);
|
||||
});
|
||||
|
||||
test('surface wait tolerates asynchronous uninstaller cleanup before the deadline', async () => {
|
||||
const phases = createInstallerPhases('C:\\smoke', {
|
||||
commonDesktop: 'C:\\shared-desktop',
|
||||
commonPrograms: 'C:\\shared-programs',
|
||||
currentDesktop: 'C:\\user-desktop',
|
||||
currentPrograms: 'C:\\user-programs'
|
||||
});
|
||||
let sweeps = 0;
|
||||
await waitForInstallerSurfaceClean(phases, {
|
||||
keyExists: (key) => {
|
||||
if (key === registryKeys('HKCU').uninstall) sweeps += 1;
|
||||
return sweeps < 3;
|
||||
},
|
||||
pathExists: () => sweeps < 3,
|
||||
timeoutMs: 5000,
|
||||
pollIntervalMs: 5
|
||||
});
|
||||
assert.ok(sweeps >= 3);
|
||||
});
|
||||
|
||||
test('surface wait still fails when the uninstaller never cleans up', async () => {
|
||||
const phases = createInstallerPhases('C:\\smoke', {
|
||||
commonDesktop: 'C:\\shared-desktop',
|
||||
commonPrograms: 'C:\\shared-programs',
|
||||
currentDesktop: 'C:\\user-desktop',
|
||||
currentPrograms: 'C:\\user-programs'
|
||||
});
|
||||
await assert.rejects(() => waitForInstallerSurfaceClean(phases, {
|
||||
keyExists: () => true,
|
||||
pathExists: () => false,
|
||||
timeoutMs: 60,
|
||||
pollIntervalMs: 5
|
||||
}), /clean registry and shortcut surface/);
|
||||
});
|
||||
|
||||
test('recursive cleanup is limited to the dedicated runner temp directory', () => {
|
||||
assert.doesNotThrow(() => assertPathInside('C:\\runner-temp\\tvm-installer-123', 'C:\\runner-temp'));
|
||||
assert.throws(() => assertPathInside('C:\\runner-temp', 'C:\\runner-temp'), /outside its parent/i);
|
||||
|
||||
Reference in New Issue
Block a user