From 66e6088bf1dba39ce37ece11931d941cf31fe9f1 Mon Sep 17 00:00:00 2001
From: Alex Hope-O'Connor
Date: Sat, 2 May 2026 20:19:44 +1000
Subject: [PATCH] Portal: request-scoped shell bundle, SPA connect poll fix,
test tidy
- Use per-request PortalShellRenderBundle and one root shell template; drop
server-side template registry and simplify WiFiManagerServer.
- PortalAppJS: centralize chrome/form binding; fix WiFi connect polling by
stopping previous timers on view change and before new polls.
- processPortalConnect honors _cleanConnect like connectWifi.
- Remove brittle full-JSON API tests; trim test harness surface.
- README: small doc touch-up for the shell/portal flow.
---
README.md | 7 +-
lib/WiFiManager/include/WiFiManagerHandlers.h | 9 +++
lib/WiFiManager/include/WiFiManagerServer.h | 22 ------
.../include/templates/PortalAppJS.h | 73 +++++++++++++++----
lib/WiFiManager/include/templates/RootShell.h | 4 +
lib/WiFiManager/src/WiFiManager.cpp | 3 +
lib/WiFiManager/src/WiFiManagerHandlers.cpp | 64 ++++++++--------
lib/WiFiManager/src/WiFiManagerServer.cpp | 71 ++++--------------
test/test_wifimanager/test_main.cpp | 2 -
test/test_wifimanager/test_main.h | 2 -
.../tests/test_api_json_and_captive.cpp | 38 ----------
11 files changed, 127 insertions(+), 168 deletions(-)
diff --git a/README.md b/README.md
index 85d7639..71bc322 100644
--- a/README.md
+++ b/README.md
@@ -31,10 +31,11 @@ This fork currently includes the following architectural improvements:
- **Data-first JSON generation** for portal APIs, including info/device/about data, instead of HTML-to-JSON parsing.
- **Capability-driven UI flags** in bootstrap/API payloads so features like info, update, erase, and action visibility can be controlled by backend state.
- **SPA-native feedback UX** using in-DOM dialog/toast behavior rather than page-based action flows.
-- A **single shell render contract** with default shell placeholders (`%PAGE_TITLE%`, `%STYLES%`) plus embedded runtime payloads (`%BOOTSTRAP_JSON%`, `%PORTAL_APP_JS%`).
+- **Request-scoped shell rendering**: the root portal page is built for each `GET /` from `WM_ROOT_SHELL_TEMPLATE` using a fresh placeholder registry. Shell inputs are only `%PAGE_TITLE%`, `%STYLES%`, `%BOOTSTRAP_JSON%`, and `%PORTAL_APP_JS%` — filled in `WiFiManagerHandlers` from WiFiManager state and embedded assets (not from a server-wide template registry).
+- **Customization via WiFiManager APIs** (`setTitle`, `setShowInfo`, `setParamsPage`, bootstrap-facing flags, etc.), not by exposing placeholder-registry mutation to consumers.
- A clearer separation between:
- - shell rendering
- - API responses
+ - shell rendering (handlers + SPA bootstrap)
+ - JSON API responses
- captive portal behavior
- OTA handling
- Updated tests focused on the **shell contract**, **bootstrap payloads**, and **API JSON shapes** rather than removed legacy portal pages.
diff --git a/lib/WiFiManager/include/WiFiManagerHandlers.h b/lib/WiFiManager/include/WiFiManagerHandlers.h
index 132058c..8d8cb95 100644
--- a/lib/WiFiManager/include/WiFiManagerHandlers.h
+++ b/lib/WiFiManager/include/WiFiManagerHandlers.h
@@ -16,6 +16,14 @@
#include
#include "WiFiManager.h"
+#ifndef WM_TEMPLATE_REGISTRY_CAPACITY
+#define WM_TEMPLATE_REGISTRY_CAPACITY 16
+#endif
+
+// Portal UI customization is driven by WiFiManager state and helpers such as setTitle(), setShowInfo(),
+// setParamsPage(), setShowInfoUpdate(), etc., surfaced through bootstrap/API JSON — not by mutating template
+// placeholder registries.
+
// -----------------------------------------------------------------------------------------------
// FORM FIELD NAMES (for IP configuration forms)
@@ -79,6 +87,7 @@ class WiFiManagerHandlers {
String buildApiWifiConnectStatusJson();
/** Fixed JSON bodies for POST action endpoints (single source for handlers + tests). */
+ static String jsonApiWifiScanAccepted();
static String jsonApiDeviceRestartScheduled();
static String jsonApiParamsSaveOk();
static String jsonApiPortalCloseOk();
diff --git a/lib/WiFiManager/include/WiFiManagerServer.h b/lib/WiFiManager/include/WiFiManagerServer.h
index 58578cd..79def1f 100644
--- a/lib/WiFiManager/include/WiFiManagerServer.h
+++ b/lib/WiFiManager/include/WiFiManagerServer.h
@@ -37,12 +37,6 @@
#include
#include
-#include
-
-#ifndef WM_TEMPLATE_REGISTRY_CAPACITY
-#define WM_TEMPLATE_REGISTRY_CAPACITY 16
-#endif
-
class WiFiManager;
class WiFiManagerHandlers;
@@ -74,21 +68,9 @@ const char R_updatedone[] PROGMEM = "/u";
class WiFiManagerServer {
public:
- static WiFiManagerServer* instance();
-
WiFiManagerServer(WiFiManager* wm);
~WiFiManagerServer();
- void setupTemplateEngine();
- PlaceholderRegistry* getPlaceholderRegistry() { return _tplRegistry.get(); }
-
- static const char* tplGetPageTitle();
-
- void registerDefaultStyles(PlaceholderRegistry& reg);
- void registerDefaultPageTitle(PlaceholderRegistry& reg);
- /** Shell placeholders only: %STYLES%, %PAGE_TITLE%. */
- void registerDefaultPlaceholders(PlaceholderRegistry& reg);
-
void createServer(uint16_t port);
void registerRoutes();
void setupDNSD();
@@ -103,14 +85,10 @@ class WiFiManagerServer {
std::unique_ptr server;
std::unique_ptr dnsServer;
- std::unique_ptr _tplRegistry;
-
#ifdef WM_DFTE_LOGGING
std::unique_ptr _dfteLogger;
bool _wmOwnsDfteLogSink = false;
#endif
-
- static WiFiManagerServer* s_instance;
};
#endif // defined(ESP8266) || defined(ESP32)
diff --git a/lib/WiFiManager/include/templates/PortalAppJS.h b/lib/WiFiManager/include/templates/PortalAppJS.h
index 748893d..9193087 100644
--- a/lib/WiFiManager/include/templates/PortalAppJS.h
+++ b/lib/WiFiManager/include/templates/PortalAppJS.h
@@ -18,9 +18,11 @@ const char PORTAL_APP_JS[] PROGMEM = R"rawliteral(
var boot={};
try{var el=document.getElementById('wm-bootstrap');if(el&&el.textContent)boot=JSON.parse(el.textContent);}catch(e){boot={};}
+// --- Core / DOM ---
function $(id){return document.getElementById(id);}
function esc(t){if(!t)return'';return String(t).replace(/[&<>"']/g,function(c){return({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]);});}
+// --- Toast / dialog ---
var _wmToastTimer=null;
function showToast(msg,isErr){
var el=$('wm-toast');
@@ -50,13 +52,37 @@ function showConfirm(msg,onOk){
ok.onclick=function(){hide();if(onOk)onOk();};
}
+function bindPortalChromeEvents(){
+ var back=$('wm-nav-back');
+ if(back){
+ back.addEventListener('click', function(ev){ ev.preventDefault(); history.back(); });
+ }
+ var r=$('wm-restart-btn'), e=$('wm-exit-btn'), c=$('wm-close-captive-btn'), er=$('wm-erase-btn');
+ if(r && window.portalRestart) r.addEventListener('click', window.portalRestart);
+ if(e && window.portalExit) e.addEventListener('click', window.portalExit);
+ if(c && window.portalCloseCaptive) c.addEventListener('click', window.portalCloseCaptive);
+ if(er && window.portalErase) er.addEventListener('click', window.portalErase);
+}
+
+function bindFormSubmitHandlers(){
+ var wf=$('wm-wifi-form'), pf=$('wm-param-form'), of=$('wm-ota-form');
+ if(wf && window.portalWifiSave) wf.addEventListener('submit', window.portalWifiSave);
+ if(pf && window.portalParamSave) pf.addEventListener('submit', window.portalParamSave);
+ if(of && window.portalOtaSubmit) of.addEventListener('submit', window.portalOtaSubmit);
+}
+
+// --- View shell ---
function setView(html){
var a=$('app');
if(!a)return;
stopWifiScanPolling();
+ stopWifiConnectPolling();
a.innerHTML=""+html+"
";
+ bindPortalChromeEvents();
+ bindFormSubmitHandlers();
}
+// --- Field render (WiFi / params meta) ---
function renderMetaField(f){
if(!f)return'';
if(f.html)return f.html;
@@ -89,7 +115,7 @@ function navBar(){
if(!f.paramsInWifi){h+=" · Setup";}
if(f.showInfo!==false){h+=" · Info";}
if(f.showUpdate){h+=" · Update";}
- if(boot.showBack){h+=" · Back";}
+ if(boot.showBack){h+=" · Back";}
h+="
";
return h;
}
@@ -97,9 +123,9 @@ function navBar(){
function deviceActionsHtml(){
var f=boot.features||{};
var h='', ok=false;
- if(f.showRestart){h+="";ok=true;}
- if(f.showExitPortal){h+="";ok=true;}
- if(f.showCloseCaptive){h+="";ok=true;}
+ if(f.showRestart){h+="";ok=true;}
+ if(f.showExitPortal){h+="";ok=true;}
+ if(f.showCloseCaptive){h+="";ok=true;}
if(!ok)return'';
return "Device actions
"+h+"";
}
@@ -115,12 +141,14 @@ function viewHome(){
setView(html);
}
+// --- HTTP ---
function api(path, opt){
opt=opt||{};
return fetch(path,{method:opt.method||'GET',headers:opt.headers,body:opt.body,credentials:'same-origin'})
.then(function(r){return r.text().then(function(t){return {ok:r.ok,status:r.status,body:t};});});
}
+// --- WiFi scan view ---
var _wmWifiScanPollTimer=null;
function stopWifiScanPolling(){
@@ -206,7 +234,7 @@ function viewWifi(){
try{var m=JSON.parse(res.body);}catch(e){m={};}
var html=navBar()+"WiFi
";
html+="";
- html+="";
html+="";
@@ -361,7 +403,7 @@ function viewUpdate(){
var f=boot.features||{};
var html=navBar()+"Firmware update
";
if(!f.showUpdate){html+="Firmware update is disabled.
";setView(html);return;}
- html+="";
html+="Upload a .bin firmware. The device restarts after a successful update.
";
@@ -405,6 +447,7 @@ window.portalOtaSubmit=function(ev){
return false;
};
+// --- Routing ---
function route(){
var h=location.hash||'#/';
if(h.indexOf('#/')!==0)h='#/';
diff --git a/lib/WiFiManager/include/templates/RootShell.h b/lib/WiFiManager/include/templates/RootShell.h
index 1f2ab36..757689d 100644
--- a/lib/WiFiManager/include/templates/RootShell.h
+++ b/lib/WiFiManager/include/templates/RootShell.h
@@ -6,6 +6,10 @@
*
* Single-page portal shell: only HTML document served for GET /.
* Dynamic UI is driven by embedded JS + JSON APIs under /api/...
+ *
+ * Placeholder keys (%PAGE_TITLE%, %STYLES%, %BOOTSTRAP_JSON%, %PORTAL_APP_JS%) are filled per request in
+ * WiFiManagerHandlers::handleRoot (shell contract comment in WiFiManagerHandlers.cpp); do not treat
+ * placeholders as a customization API.
*/
#ifndef _WM_ROOT_SHELL_TEMPLATE_H_
diff --git a/lib/WiFiManager/src/WiFiManager.cpp b/lib/WiFiManager/src/WiFiManager.cpp
index 0c0698b..0d8e31d 100644
--- a/lib/WiFiManager/src/WiFiManager.cpp
+++ b/lib/WiFiManager/src/WiFiManager.cpp
@@ -727,6 +727,9 @@ void WiFiManager::processPortalConnect() {
return;
case wm_cp_connect_state_t::starting: {
setSTAConfig();
+ if (_cleanConnect) {
+ WiFi_Disconnect(); // match connectWifi(): force a clean STA begin for portal saves too
+ }
if (!_connectonsave) {
if (!wifiConnectNew(_cpConnectSsid, _cpConnectPass, false)) {
failPortalConnect(WL_CONNECT_FAILED, F("WiFi begin failed"));
diff --git a/lib/WiFiManager/src/WiFiManagerHandlers.cpp b/lib/WiFiManager/src/WiFiManagerHandlers.cpp
index ebe64b2..a51a295 100644
--- a/lib/WiFiManager/src/WiFiManagerHandlers.cpp
+++ b/lib/WiFiManager/src/WiFiManagerHandlers.cpp
@@ -8,7 +8,6 @@
*/
#include "WiFiManagerHandlers.h"
-#include "WiFiManagerServer.h"
#include "templates/CSS.h"
#include "templates/RootShell.h"
#include "templates/PortalAppJS.h"
@@ -40,8 +39,6 @@ static void jsonAppendEscaped(String& out, const String& s) {
namespace {
-const char kEmptyTemplateChunk[] PROGMEM = "";
-
inline void reservePage(String& page, size_t extraBytes = WM_PAGE_RESERVE_BYTES) {
if (extraBytes == 0) return;
const size_t targetLen = page.length() + extraBytes;
@@ -76,16 +73,13 @@ AsyncWebServerResponse* beginTemplateResponse(AsyncWebServerRequest* request,
);
}
-void registerSharedShellPlaceholders(WiFiManagerServer* server, PlaceholderRegistry& registry) {
- if (server) {
- server->registerDefaultStyles(registry);
- return;
- }
+// Shell contract (must match templates/RootShell.h — customize UI via WiFiManager APIs + bootstrap JSON, not registries):
+// %PAGE_TITLE% -> document title (from WiFiManager title state)
+// %STYLES% -> embedded portal CSS
+// %BOOTSTRAP_JSON% -> initial SPA runtime payload
+// %PORTAL_APP_JS% -> embedded SPA source
- registry.registerProgmemData("%STYLES%", CSS_STYLE);
-}
-
-struct ShellRenderBundle {
+struct PortalShellRenderBundle {
String bootstrapJson;
String pageTitleStatic;
PlaceholderRegistry registry;
@@ -93,10 +87,23 @@ struct ShellRenderBundle {
DynamicTemplateDescriptor bootstrapDescriptor;
DynamicTemplateDescriptor pageTitleDescriptor;
- ShellRenderBundle()
+ PortalShellRenderBundle()
: registry(WM_TEMPLATE_REGISTRY_CAPACITY), bootstrapDescriptor{}, pageTitleDescriptor{} {}
};
+void populatePortalShellBundle(PortalShellRenderBundle& bundle,
+ const String& pageTitle,
+ const String& bootstrapJson) {
+ bundle.pageTitleStatic = pageTitle;
+ bundle.bootstrapJson = bootstrapJson;
+ bundle.registry.registerProgmemData("%STYLES%", CSS_STYLE);
+ bundle.registry.registerProgmemData("%PORTAL_APP_JS%", PORTAL_APP_JS);
+ configureDynamicStringDescriptor(bundle.pageTitleDescriptor, bundle.pageTitleStatic);
+ bundle.registry.registerDynamicTemplate("%PAGE_TITLE%", &bundle.pageTitleDescriptor);
+ configureDynamicStringDescriptor(bundle.bootstrapDescriptor, bundle.bootstrapJson);
+ bundle.registry.registerDynamicTemplate("%BOOTSTRAP_JSON%", &bundle.bootstrapDescriptor);
+}
+
} // namespace
WiFiManagerHandlers::WiFiManagerHandlers(WiFiManager* wm) : _wm(wm) {}
@@ -547,22 +554,15 @@ void WiFiManagerHandlers::handleRoot(AsyncWebServerRequest *request) {
if (captivePortal(request)) return;
handleRequest(request);
- auto bundle = std::make_shared();
- bundle->bootstrapJson = buildPortalBootstrapJson();
-
- if (_wm->_serverManager) {
- _wm->_serverManager->registerDefaultStyles(bundle->registry);
- _wm->_serverManager->registerDefaultPageTitle(bundle->registry);
- } else {
- registerSharedShellPlaceholders(nullptr, bundle->registry);
- bundle->pageTitleStatic = _wm->_title;
- configureDynamicStringDescriptor(bundle->pageTitleDescriptor, bundle->pageTitleStatic);
- bundle->registry.registerDynamicTemplate("%PAGE_TITLE%", &bundle->pageTitleDescriptor);
- }
-
- configureDynamicStringDescriptor(bundle->bootstrapDescriptor, bundle->bootstrapJson);
- bundle->registry.registerDynamicTemplate("%BOOTSTRAP_JSON%", &bundle->bootstrapDescriptor);
- bundle->registry.registerProgmemData("%PORTAL_APP_JS%", PORTAL_APP_JS);
+ // Root shell render model:
+ // - WiFiManagerHandlers owns request-time shell assembly; WiFiManagerServer owns HTTP lifecycle only.
+ // - Build one request-scoped PortalShellRenderBundle.
+ // - Populate one request-scoped PlaceholderRegistry with shell defaults + request payloads.
+ // - Render WM_ROOT_SHELL_TEMPLATE.
+ auto bundle = std::make_shared();
+ populatePortalShellBundle(*bundle,
+ _wm ? _wm->_title : String(),
+ buildPortalBootstrapJson());
request->send(beginTemplateResponse(request, bundle, WM_ROOT_SHELL_TEMPLATE));
}
@@ -1011,7 +1011,7 @@ void WiFiManagerHandlers::handleApiWifiScan(AsyncWebServerRequest *request) {
_wm->requestAsyncScan(true);
AsyncWebServerResponse *response =
- request->beginResponse(202, "application/json", "{\"accepted\":true,\"state\":\"queued\"}");
+ request->beginResponse(202, "application/json", jsonApiWifiScanAccepted());
response->addHeader(F("Cache-Control"), F("no-cache"));
request->send(response);
}
@@ -1181,6 +1181,10 @@ void WiFiManagerHandlers::handleApiStatus(AsyncWebServerRequest *request) {
sendApiJson(request, 200, buildApiStatusJson());
}
+String WiFiManagerHandlers::jsonApiWifiScanAccepted() {
+ return F("{\"accepted\":true,\"state\":\"queued\"}");
+}
+
String WiFiManagerHandlers::jsonApiDeviceRestartScheduled() {
return F("{\"ok\":true,\"message\":\"Restart scheduled\"}");
}
diff --git a/lib/WiFiManager/src/WiFiManagerServer.cpp b/lib/WiFiManager/src/WiFiManagerServer.cpp
index 7e1960a..ef3973e 100644
--- a/lib/WiFiManager/src/WiFiManagerServer.cpp
+++ b/lib/WiFiManager/src/WiFiManagerServer.cpp
@@ -4,7 +4,8 @@
* @author alexhopeoconnor
* @license MIT
*
- * Server lifecycle: single shell + JSON APIs + OTA + captive portal.
+ * HTTP server lifecycle and route registration only. HTML shell rendering is request-scoped in
+ * WiFiManagerHandlers (WM_ROOT_SHELL_TEMPLATE + per-request placeholder registry).
* Route inventory matches WiFiManagerServer.h (GET /, /api/..., POST /u, onNotFound).
*/
@@ -15,61 +16,14 @@
#include "WiFiManagerDfteLogger.h"
#include
#endif
-#include "templates/CSS.h"
#if defined(ESP8266) || defined(ESP32)
-WiFiManagerServer* WiFiManagerServer::s_instance = nullptr;
-
-WiFiManagerServer* WiFiManagerServer::instance() {
- return s_instance;
-}
-
WiFiManagerServer::WiFiManagerServer(WiFiManager* wm)
- : _wm(wm), _handlers(std::make_unique(wm)) {
- s_instance = this;
-}
+ : _wm(wm), _handlers(std::make_unique(wm)) {}
WiFiManagerServer::~WiFiManagerServer() = default;
-const char* WiFiManagerServer::tplGetPageTitle() {
- auto srv = WiFiManagerServer::instance();
- if (!srv || !srv->_wm) return "";
- return srv->_wm->_title.c_str();
-}
-
-void WiFiManagerServer::registerDefaultStyles(PlaceholderRegistry& reg) {
- reg.registerProgmemData("%STYLES%", CSS_STYLE);
-}
-
-void WiFiManagerServer::registerDefaultPageTitle(PlaceholderRegistry& reg) {
- reg.registerRamData("%PAGE_TITLE%", &WiFiManagerServer::tplGetPageTitle);
-}
-
-void WiFiManagerServer::registerDefaultPlaceholders(PlaceholderRegistry& reg) {
- registerDefaultStyles(reg);
- registerDefaultPageTitle(reg);
-}
-
-void WiFiManagerServer::setupTemplateEngine() {
- if (!_tplRegistry) {
- _tplRegistry = std::unique_ptr(new PlaceholderRegistry(WM_TEMPLATE_REGISTRY_CAPACITY));
- } else {
- _tplRegistry->clear();
- }
- registerDefaultPlaceholders(*_tplRegistry);
-
-#ifdef WM_DFTE_LOGGING
- if (!deviceFrameworkTemplateEngineIsLoggingEnabled()) {
- if (!_dfteLogger) {
- _dfteLogger = std::make_unique(_wm);
- }
- deviceFrameworkTemplateEngineEnableLogging(_dfteLogger.get(), static_cast(this));
- _wmOwnsDfteLogSink = true;
- }
-#endif
-}
-
void WiFiManagerServer::createServer(uint16_t port) {
if (server) {
#ifndef WM_NO_LOG
@@ -89,7 +43,18 @@ void WiFiManagerServer::createServer(uint16_t port) {
}
server.reset(new AsyncWebServer(port));
- setupTemplateEngine();
+
+#ifdef WM_DFTE_LOGGING
+ // DFTE logging is still owned by server lifecycle; it is intentionally independent of
+ // request-scoped shell rendering / placeholder registration.
+ if (!deviceFrameworkTemplateEngineIsLoggingEnabled()) {
+ if (!_dfteLogger) {
+ _dfteLogger = std::make_unique(_wm);
+ }
+ deviceFrameworkTemplateEngineEnableLogging(_dfteLogger.get(), static_cast(this));
+ _wmOwnsDfteLogSink = true;
+ }
+#endif
}
void WiFiManagerServer::registerRoutes() {
@@ -100,10 +65,6 @@ void WiFiManagerServer::registerRoutes() {
return;
}
- if (!_tplRegistry) {
- setupTemplateEngine();
- }
-
if (_wm->_webservercallback != NULL) {
#ifndef WM_NO_LOG
_wm->log(WiFiManagerLogLevel::Debug, kWiFiMgrLogSubsystem, F("[CB] _webservercallback calling"));
@@ -212,8 +173,6 @@ void WiFiManagerServer::shutdownServer() {
dnsServer->stop();
dnsServer.reset();
}
-
- if (s_instance == this) s_instance = nullptr;
}
#endif
diff --git a/test/test_wifimanager/test_main.cpp b/test/test_wifimanager/test_main.cpp
index 841c862..9813457 100644
--- a/test/test_wifimanager/test_main.cpp
+++ b/test/test_wifimanager/test_main.cpp
@@ -15,8 +15,6 @@ TestCase tests[] = {
TEST_ENTRY(test_api_info_json_shape),
TEST_ENTRY(test_api_params_json_shape),
TEST_ENTRY(test_api_status_json_shape),
- TEST_ENTRY(test_api_action_response_json_literals),
- TEST_ENTRY(test_api_ota_done_success_json_literal),
// Configuration tests
TEST_ENTRY(test_configuration_setters),
diff --git a/test/test_wifimanager/test_main.h b/test/test_wifimanager/test_main.h
index 8d7f64c..b283072 100644
--- a/test/test_wifimanager/test_main.h
+++ b/test/test_wifimanager/test_main.h
@@ -131,8 +131,6 @@ void test_api_wifi_meta_json_shape();
void test_api_info_json_shape();
void test_api_params_json_shape();
void test_api_status_json_shape();
-void test_api_action_response_json_literals();
-void test_api_ota_done_success_json_literal();
// State transition tests
void test_portal_to_connected_transition();
diff --git a/test/test_wifimanager/tests/test_api_json_and_captive.cpp b/test/test_wifimanager/tests/test_api_json_and_captive.cpp
index 0ee2e9f..092667b 100644
--- a/test/test_wifimanager/tests/test_api_json_and_captive.cpp
+++ b/test/test_wifimanager/tests/test_api_json_and_captive.cpp
@@ -81,41 +81,3 @@ void test_api_status_json_shape() {
Serial.println("[TEST] API status JSON shape test completed successfully");
}
-
-void test_api_action_response_json_literals() {
- Serial.println("[TEST] Testing POST /api action JSON payloads...");
-
- TEST_ASSERT_EQUAL_STRING(
- "{\"ok\":true,\"message\":\"Restart scheduled\"}",
- WiFiManagerHandlers::jsonApiDeviceRestartScheduled().c_str());
- TEST_ASSERT_EQUAL_STRING(
- "{\"ok\":true,\"message\":\"Setup saved\"}",
- WiFiManagerHandlers::jsonApiParamsSaveOk().c_str());
- TEST_ASSERT_EQUAL_STRING(
- "{\"ok\":true,\"message\":\"Captive portal detection disabled\"}",
- WiFiManagerHandlers::jsonApiPortalCloseOk().c_str());
- TEST_ASSERT_EQUAL_STRING(
- "{\"ok\":true,\"message\":\"Exiting portal\"}",
- WiFiManagerHandlers::jsonApiPortalExitOk().c_str());
- TEST_ASSERT_EQUAL_STRING(
- "{\"ok\":false,\"message\":\"Exit not allowed\"}",
- WiFiManagerHandlers::jsonApiPortalExitForbidden().c_str());
- TEST_ASSERT_EQUAL_STRING(
- "{\"ok\":true,\"message\":\"WiFi configuration erased. Device will restart shortly.\"}",
- WiFiManagerHandlers::jsonApiEraseResponse(true).c_str());
- TEST_ASSERT_EQUAL_STRING(
- "{\"ok\":false,\"message\":\"Erase failed\"}",
- WiFiManagerHandlers::jsonApiEraseResponse(false).c_str());
-
- Serial.println("[TEST] Action response JSON literals test completed successfully");
-}
-
-void test_api_ota_done_success_json_literal() {
- Serial.println("[TEST] Testing POST /u completion success JSON...");
-
- TEST_ASSERT_EQUAL_STRING(
- "{\"ok\":true,\"message\":\"Firmware updated. Restarting...\"}",
- WiFiManagerHandlers::jsonApiOtaUpdateSuccess().c_str());
-
- Serial.println("[TEST] OTA success JSON literal test completed successfully");
-}