diff --git a/js/views/device.js b/js/views/device.js index f976e76..5cdbd32 100644 --- a/js/views/device.js +++ b/js/views/device.js @@ -140,12 +140,19 @@ export function renderDevice(el, device) { const repo = repoFor(device, channel, variant); const classic = classicInstallerFor(device, channel, variant); if (hasSerial) { - installSlot.innerHTML = ` - - - -

- Plug the device into this computer with a USB data cable, click the button, and pick the serial port.

`; + const existing = installSlot.querySelector('esp-web-install-button'); + if (existing) { + // Reuse the button; only the manifest differs between variants. Rebuilding + // it would recreate the web component and flash on every variant change. + existing.setAttribute('manifest', manifest); + } else { + installSlot.innerHTML = ` + + + +

+ Plug the device into this computer with a USB data cable, click the button, and pick the serial port.

`; + } } else { installSlot.innerHTML = `
diff --git a/tests/installer.spec.js b/tests/installer.spec.js index 106e85e..a4df985 100644 --- a/tests/installer.spec.js +++ b/tests/installer.spec.js @@ -90,6 +90,34 @@ test('channel/variant toggles rewire the install button', async ({ page }) => { } }); +test('changing variant reuses the install button instead of recreating it', async ({ page }) => { + const d = registry.devices.find((x) => Object.keys(x.firmware.stable).length > 1); + test.skip(!d, 'no multi-variant device in registry'); + // Force the WebSerial path (headless Chromium lacks navigator.serial) so the + // esp-web-install-button renders. + await page.addInitScript(() => { + if (!('serial' in navigator)) { + Object.defineProperty(navigator, 'serial', { value: {}, configurable: true }); + } + }); + await page.goto(`/#/${d.id}`); + + // Tag the initially-rendered install button so we can tell if it survives. + await page.evaluate(() => { + document.querySelector('#install-slot esp-web-install-button').dataset.tag = 'orig'; + }); + + const variants = Object.keys(d.firmware.stable); + const other = variants[1]; + await page.locator(`#variant-seg button[data-variant="${other}"]`).click(); + + // Same element must survive (tag intact) with its manifest updated in place. + await expect(page.locator('#install-slot esp-web-install-button')) + .toHaveAttribute('data-tag', 'orig'); + await expect(page.locator('#install-slot esp-web-install-button')) + .toHaveAttribute('manifest', d.firmware.stable[other]); +}); + test('manual fallback renders when WebSerial is unavailable', async ({ page }) => { await page.addInitScript(() => { Object.defineProperty(Navigator.prototype, 'serial', { get: () => undefined });