mirror of
https://github.com/alexhopeoconnor/WiFiManager.git
synced 2026-10-04 02:48:13 +10:00
fix: flush portal OTA response before reboot
This commit is contained in:
@@ -1004,8 +1004,12 @@ void WiFiManagerHandlers::handleUpdateDone(AsyncWebServerRequest *request) {
|
||||
}
|
||||
|
||||
sendApiJson(request, 200, jsonApiOtaUpdateSuccess());
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
// AsyncWebServer queues this response; restarting from the request callback
|
||||
// tears down its TCP connection before the client can receive the success
|
||||
// JSON. Let the application's regular process() call perform the same
|
||||
// delayed restart path used by the other restart-capable portal endpoints.
|
||||
_wm->_rebootScheduled = true;
|
||||
_wm->_rebootTime = millis() + _wm->REBOOT_DELAY_MS;
|
||||
}
|
||||
|
||||
void WiFiManagerHandlers::sendApiJson(AsyncWebServerRequest *request, int code, const String& json) {
|
||||
|
||||
@@ -46,6 +46,47 @@ async function requireRestartOutage(request) {
|
||||
throw new Error('The portal never became unavailable after a successful OTA response.');
|
||||
}
|
||||
|
||||
function waitForOtaResponse(page) {
|
||||
// `waitForResponse()` alone waits until the enclosing test timeout when an
|
||||
// embedded server resets the upload connection. Treat that as an immediate
|
||||
// transport failure so a hardware artifact names the real fault instead of
|
||||
// implying that the rendered form never submitted.
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
cleanup();
|
||||
reject(new Error('Timed out waiting for the portal OTA POST /u response.'));
|
||||
}, 90_000);
|
||||
|
||||
const isOtaRequest = (request) => {
|
||||
const requestPath = new URL(request.url()).pathname;
|
||||
return requestPath === '/u' && request.method() === 'POST';
|
||||
};
|
||||
const cleanup = () => {
|
||||
clearTimeout(timeout);
|
||||
page.off('response', onResponse);
|
||||
page.off('requestfailed', onRequestFailed);
|
||||
};
|
||||
const onResponse = (response) => {
|
||||
if (!isOtaRequest(response.request())) {
|
||||
return;
|
||||
}
|
||||
cleanup();
|
||||
resolve(response);
|
||||
};
|
||||
const onRequestFailed = (request) => {
|
||||
if (!isOtaRequest(request)) {
|
||||
return;
|
||||
}
|
||||
cleanup();
|
||||
const failure = request.failure();
|
||||
reject(new Error(`Portal OTA POST /u failed before a response: ${failure ? failure.errorText : 'unknown error'}`));
|
||||
};
|
||||
|
||||
page.on('response', onResponse);
|
||||
page.on('requestfailed', onRequestFailed);
|
||||
});
|
||||
}
|
||||
|
||||
test.describe('portal HTTP OTA contract', () => {
|
||||
test('uploads B through the rendered portal form, requires automatic reboot, and observes B twice', async ({ page, request }) => {
|
||||
test.skip(!firmware, 'OTA firmware is mounted only for portal-hardware ota.');
|
||||
@@ -67,10 +108,7 @@ test.describe('portal HTTP OTA contract', () => {
|
||||
await expect(input).toBeVisible();
|
||||
await input.setInputFiles(firmware);
|
||||
|
||||
const updateResponse = page.waitForResponse((response) => {
|
||||
const requestPath = new URL(response.url()).pathname;
|
||||
return requestPath === '/u' && response.request().method() === 'POST';
|
||||
});
|
||||
const updateResponse = waitForOtaResponse(page);
|
||||
await page.locator('#wm-ota-form button[type="submit"]').click();
|
||||
|
||||
const response = await updateResponse;
|
||||
|
||||
Reference in New Issue
Block a user