Skip to content

Commit 5fbae4f

Browse files
committed
ci(ui-tests): take a screenshot when canceled
Sometimes the logs are empty and it is highly unclear what has happened. In such a scenario, a picture is indeed worth more than a thousand words. Note that this commit is more complicated than anyone would like, for two reasons: - While PowerShell is the right tool for the job, a PowerShell step in GitHub Actions will pop up a Terminal window, _hiding_ what we want to screenshot. To work around that, I tried to run things in a Bash step. _Also_ opens a Terminal window! Node.js to the rescue. - _Of course_ it is complicated to take a screenshot. The challenge is to figure out the dimensions of the screen, which should be as easy as looking at `[System.Windows.Forms.Screen]::PrimaryScreen`'s `Bounds` attribute. Easy peasy, right? No, it's not. Most machines nowadays have a _ridiculous_ resolution which is why most setups have a _zoom factor_. Getting to that factor should be trivial, by calling `GetDeviceCaps(hDC, LOGPIXELSX)`, but that's not working in modern Windows! There is a per-monitor display scaling ("DPI"). But even _that_ is hard to get at, calling `GetDpiForMonitor()` will still return 96 DPI (i.e. 100% zoom) because PowerShell is not marked as _Per-Monitor DPI Aware_. Since we do not want to write a manifest into the same directory as `powershell.exe` resides, we have to jump through yet another hoop to get that. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent c705ade commit 5fbae4f

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

.github/workflows/ui-tests.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,63 @@ jobs:
9494
if: cancelled()
9595
working-directory: ui-tests
9696
run: type bg-hook.log
97+
- name: Take screenshot, if canceled
98+
id: take-screenshot
99+
if: cancelled() || failure()
100+
shell: powershell
101+
run: |
102+
Add-Type -TypeDefinition @"
103+
using System;
104+
using System.Runtime.InteropServices;
105+
106+
public class DpiHelper {
107+
[DllImport("user32.dll")]
108+
public static extern bool SetProcessDpiAwarenessContext(IntPtr dpiContext);
109+
110+
[DllImport("Shcore.dll")]
111+
public static extern int GetDpiForMonitor(IntPtr hmonitor, int dpiType, out uint dpiX, out uint dpiY);
112+
113+
[DllImport("User32.dll")]
114+
public static extern IntPtr MonitorFromPoint(System.Drawing.Point pt, uint dwFlags);
115+
116+
[DllImport("user32.dll")]
117+
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
118+
119+
public static uint GetDPI() {
120+
// DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = -4
121+
SetProcessDpiAwarenessContext((IntPtr)(-4));
122+
123+
uint dpiX, dpiY;
124+
IntPtr monitor = MonitorFromPoint(new System.Drawing.Point(0, 0), 2); // MONITOR_DEFAULTTONEAREST
125+
GetDpiForMonitor(monitor, 0, out dpiX, out dpiY); // MDT_EFFECTIVE_DPI
126+
return (dpiX + dpiY) / 2;
127+
}
128+
}
129+
"@ -ReferencedAssemblies "System.Drawing.dll"
130+
131+
# First, minimize the Console window in which this script is running
132+
$hwnd = (Get-Process -Id $PID).MainWindowHandle
133+
$SW_MINIMIZE = 6
134+
135+
[DpiHelper]::ShowWindow($hwnd, $SW_MINIMIZE)
136+
137+
# Now, get the DPI
138+
$dpi = [DpiHelper]::GetDPI()
139+
140+
# This function takes a screenshot and saves it as a PNG file
141+
[Reflection.Assembly]::LoadWithPartialName("System.Drawing")
142+
function screenshot([Drawing.Rectangle]$bounds, $path) {
143+
$bmp = New-Object Drawing.Bitmap $bounds.width, $bounds.height
144+
$graphics = [Drawing.Graphics]::FromImage($bmp)
145+
$graphics.CopyFromScreen($bounds.Location, [Drawing.Point]::Empty, $bounds.size)
146+
$bmp.Save($path)
147+
$graphics.Dispose()
148+
$bmp.Dispose()
149+
}
150+
Add-Type -AssemblyName System.Windows.Forms
151+
$screen = [System.Windows.Forms.Screen]::PrimaryScreen
152+
$bounds = [Drawing.Rectangle]::FromLTRB(0, 0, $screen.Bounds.Width * $dpi / 96, $screen.Bounds.Height * $dpi / 96)
153+
screenshot $bounds "ui-tests/screenshot.png"
97154
- name: Upload test results
98155
if: always()
99156
uses: actions/upload-artifact@v4

0 commit comments

Comments
 (0)