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+=""; html+=renderFieldList(m.wifiFields||[]); var wf=m.wifiFields||[]; var hasPass=false; @@ -231,26 +259,38 @@ function viewWifi(){ }); } +// --- WiFi connect polling --- +var _wmWifiConnectPollTimer=null; + +function stopWifiConnectPolling(){ + if(_wmWifiConnectPollTimer){ + clearInterval(_wmWifiConnectPollTimer); + _wmWifiConnectPollTimer=null; + } +} + function pollWifiConnectStatus(){ - var msg=$('wm-wifi-msg'); - var iv=setInterval(function(){ + stopWifiConnectPolling(); + _wmWifiConnectPollTimer=setInterval(function(){ api('/api/wifi/connect-status').then(function(res){ var j={}; + var msg=$('wm-wifi-msg'); try{j=JSON.parse(res.body);}catch(e){} if(msg&&j.message){ msg.innerHTML=esc(j.message); } if(j.state==='success'){ - clearInterval(iv); + stopWifiConnectPolling(); showToast(j.message||'WiFi connected',false); location.hash='#/'; }else if(j.state==='failed'){ - clearInterval(iv); + stopWifiConnectPolling(); showToast(j.message||'WiFi connect failed',true); } }); },700); } + window.portalWifiSave=function(ev){ ev.preventDefault(); var fd=new FormData(document.getElementById('wm-wifi-form')); @@ -269,6 +309,7 @@ window.portalWifiSave=function(ev){ return false; }; +// --- Info view --- function viewInfo(){ setView(navBar()+"

Loading info...

"); api('/api/info').then(function(res){ @@ -300,11 +341,11 @@ function viewInfo(){ html+=section('About',d.about||[]); var act=d.actions||{}; html+="

Actions


"; - if(act.showRestart)html+="

"; - if(act.showExitPortal)html+="

"; - if(act.showCloseCaptive)html+="

"; + if(act.showRestart)html+="

"; + if(act.showExitPortal)html+="

"; + if(act.showCloseCaptive)html+="

"; if(act.showUpdate)html+="

Firmware update

"; - if(act.showErase)html+="

"; + if(act.showErase)html+="

"; setView(html); }); } @@ -332,12 +373,13 @@ window.portalErase=function(){ }); }; +// --- Params / OTA --- function viewSetup(){ setView(navBar()+"

Loading...

"); api('/api/params').then(function(res){ try{var d=JSON.parse(res.body);}catch(e){d={};} var html=navBar()+"

Parameters

"; - html+=""; + html+=""; html+=renderFieldList(d.params||[]); 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+=""; html+=""; 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"); -}