fix: gate native window reveal on renderer load

Keep BrowserWindow hidden until both ready-to-show and did-finish-load are complete, preventing the incomplete header from reaching the screen.

Render a static upload-speed baseline beneath the transparent canvas so the zero line exists independently of renderer timers.

Add regression coverage for both reveal event orders, load failures, and the script-independent header baseline.
This commit is contained in:
Sucukdeluxe
2026-08-20 13:45:02 +02:00
parent f3001828a0
commit ff1593be81
4 changed files with 61 additions and 5 deletions
+17 -1
View File
@@ -8,6 +8,7 @@ const { configureStartupRenderer, createStartupWindow, resolveStartupLanguage, c
class TestBrowserWindow extends EventEmitter {
constructor(options) {
super();
this.webContents = new EventEmitter();
this.options = options;
this.showCalls = 0;
this.startupEvents = [];
@@ -27,7 +28,7 @@ class TestBrowserWindow extends EventEmitter {
loadFile(target, options) {
this.startupEvents.push(`load:${target}`);
this.loadOptions = options;
return Promise.reject(this.loadError);
return this.loadError ? Promise.reject(this.loadError) : Promise.resolve();
}
}
@@ -78,6 +79,7 @@ test('main window uses the branded application icon', () => {
test('startup load registers visibility before navigation and shows only once', async () => {
const startup = createStartupWindow(TestBrowserWindow, {});
startup.window.loadError = null;
const loading = startup.load('renderer/index.html', () => {});
assert.deepEqual(startup.window.startupEvents, [
@@ -86,12 +88,24 @@ test('startup load registers visibility before navigation and shows only once',
]);
startup.window.emit('ready-to-show');
assert.equal(startup.window.showCalls, 0);
startup.window.webContents.emit('did-finish-load');
startup.window.emit('ready-to-show');
startup.window.webContents.emit('did-finish-load');
await loading;
assert.equal(startup.window.showCalls, 1);
});
test('startup waits for native paint readiness when renderer loading finishes first', () => {
const startup = createStartupWindow(TestBrowserWindow, {});
startup.window.webContents.emit('did-finish-load');
assert.equal(startup.window.showCalls, 0);
startup.window.emit('ready-to-show');
assert.equal(startup.window.showCalls, 1);
});
test('startup load forwards a rejected navigation to the error handler', async () => {
const startup = createStartupWindow(TestBrowserWindow, {});
let handledError;
@@ -150,4 +164,6 @@ test('header occupies its final geometry before asynchronous initialization', ()
assert.ok(firstFrameInitialization < asynchronousInitialization);
assert.match(mainSource, /createStartupQuery\([^,]+,\s*app\.getVersion\(\)\)/u);
assert.doesNotMatch(mainSource, /runAutomaticUpdateCheck\(true\);\s*\},\s*3000\)/u);
assert.match(html, /class="upload-speed-baseline"/u);
assert.match(css, /\.upload-speed-baseline\s*\{[^}]*background:\s*var\(--success\);/su);
});