diff --git a/lib/WiFiManager/include/WiFiManager.h b/lib/WiFiManager/include/WiFiManager.h index e82d15a..7106a15 100644 --- a/lib/WiFiManager/include/WiFiManager.h +++ b/lib/WiFiManager/include/WiFiManager.h @@ -1082,6 +1082,12 @@ protected: _configPortalStart = millis(); } } + void wmTestSetWebPortalActive(bool active) { + webPortalActive = active; + if (active) { + _configPortalStart = millis(); + } + } void wmTestSetPortalConnectSuccess(const String& message, const String& stationIp, uint8_t status = WL_CONNECTED) { _cpConnectState = wm_cp_connect_state_t::success; _cpConnectMessage = message; diff --git a/lib/WiFiManager/src/WiFiManager.cpp b/lib/WiFiManager/src/WiFiManager.cpp index 2a14da7..a583fa0 100644 --- a/lib/WiFiManager/src/WiFiManager.cpp +++ b/lib/WiFiManager/src/WiFiManager.cpp @@ -385,7 +385,10 @@ bool WiFiManager::startStationCandidate(const WiFiManagerStationProfiles& candid _begin(); _stationCandidate = candidate; _stationCandidateActive = true; - _stationCandidateFromPortal = configPortalActive; + // A profile submitted from either portal surface is owned by the station + // controller. Do not let the legacy empty-SSID portal state machine mark + // it successful before the controller has a usable station address. + _stationCandidateFromPortal = configPortalActive || webPortalActive; _stationAttemptMask = 0; _stationPendingSlot = WM_NO_STATION_PROFILE; _stationNextAttemptAt = 0; @@ -506,7 +509,7 @@ void WiFiManager::queueStationProfile(uint8_t slot) { } void WiFiManager::completePortalStationAttempt(bool success, uint8_t status, const String& message) { - if (!_stationCandidateFromPortal && !configPortalActive) { + if (!_stationCandidateFromPortal && !configPortalActive && !webPortalActive) { return; } diff --git a/test/test_wifimanager/test_main.cpp b/test/test_wifimanager/test_main.cpp index 44be950..9d56534 100644 --- a/test/test_wifimanager/test_main.cpp +++ b/test/test_wifimanager/test_main.cpp @@ -14,6 +14,7 @@ TestCase tests[] = { TEST_ENTRY(test_api_wifi_meta_password_field_type), TEST_ENTRY(test_api_wifi_connect_status_success_redirect), TEST_ENTRY(test_profile_portal_success_keeps_handoff_alive), + TEST_ENTRY(test_profile_portal_candidate_does_not_take_legacy_empty_ssid_path), TEST_ENTRY(test_api_info_json_shape), TEST_ENTRY(test_api_params_json_shape), TEST_ENTRY(test_api_status_json_shape), @@ -183,4 +184,3 @@ void loop() { begun = false; // avoid repeating } } - diff --git a/test/test_wifimanager/test_main.h b/test/test_wifimanager/test_main.h index a5194f9..ec7b593 100644 --- a/test/test_wifimanager/test_main.h +++ b/test/test_wifimanager/test_main.h @@ -119,6 +119,7 @@ void test_api_wifi_meta_json_shape(); void test_api_wifi_meta_password_field_type(); void test_api_wifi_connect_status_success_redirect(); void test_profile_portal_success_keeps_handoff_alive(); +void test_profile_portal_candidate_does_not_take_legacy_empty_ssid_path(); void test_api_info_json_shape(); void test_api_params_json_shape(); void test_api_status_json_shape(); @@ -146,4 +147,3 @@ void test_portal_resource_recovery(); void test_scan_result_storage_released_when_portal_closes(); #endif // TEST_MAIN_H - 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 d5a861c..4a5d964 100644 --- a/test/test_wifimanager/tests/test_api_json_and_captive.cpp +++ b/test/test_wifimanager/tests/test_api_json_and_captive.cpp @@ -96,6 +96,29 @@ void test_profile_portal_success_keeps_handoff_alive() { Serial.println("[TEST] Profile portal success hand-off delay test completed successfully"); } +void test_profile_portal_candidate_does_not_take_legacy_empty_ssid_path() { + Serial.println("[TEST] Testing profile portal candidate state ownership..."); + + WiFiManager wm; +#ifdef UNIT_TEST + WiFiManagerStationProfiles candidate; + candidate.slots[0].enabled = true; + snprintf(candidate.slots[0].ssid, sizeof(candidate.slots[0].ssid), "%s", "candidate-network"); + wm.wmTestSetWebPortalActive(true); + TEST_ASSERT_TRUE(wm.startStationCandidate(candidate)); + wm.process(); + TEST_ASSERT_EQUAL_MESSAGE( + WiFiManager::WM_CP_CONNECT_WAITING, + wm.getConfigPortalConnectState(), + "A web-portal profile candidate must not be treated as the legacy empty-SSID save path" + ); +#else + TEST_IGNORE_MESSAGE("UNIT_TEST helpers unavailable"); +#endif + + Serial.println("[TEST] Profile portal candidate state ownership test completed successfully"); +} + void test_api_info_json_shape() { Serial.println("[TEST] Testing /api/info JSON shape...");