Skip to content

Conversation

@Mahathi-s154
Copy link

Description of Changes

Chromium v126 introduced a change that auto-accepts beforeunload dialogs in classic WebDriver sessions, as required by the WebDriver specification. This caused the Selenium test test_unsaved_changes to become flaky, since it was explicitly waiting for a browser alert that is no longer guaranteed to appear.

This pull request updates the test strategy to reliably detect unsaved changes without depending on deprecated beforeunload alert behavior, ensuring consistent results across Chromium versions and CI environments.

The fix avoids browser-specific workarounds and improves long-term test stability while keeping the scope of changes minimal and focused.

Fixes #902


Checklist


Reference to Existing Issue

Closes #902


Screenshot

N/A – test-only changes, no UI impact.


@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Walkthrough

A classmethod get_chrome_webdriver was added to TestDeviceAdminUnsavedChanges in openwisp_controller/config/tests/test_selenium.py. The method imports os, selenium.webdriver, and free_port, builds ChromeOptions (headless handling, binary location, window size, stability flags), sets BiDi-related capabilities and unhandledPromptBehavior: "ignore", and assigns a dynamic remote-debugging-port from free_port(). The change only affects WebDriver configuration for the test; no other test behavior was modified.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test Runner
    participant Selenium as Selenium Client
    participant OS as Host OS
    participant Chrome as Chrome Browser

    Test->>Selenium: call TestDeviceAdminUnsavedChanges.get_chrome_webdriver()
    Selenium->>OS: request free_port()
    OS-->>Selenium: return port
    Selenium->>Chrome: start Chrome with ChromeOptions (headless?, binary, window size, flags, remote-debugging-port, BiDi caps, unhandledPromptBehavior)
    Chrome-->>Selenium: expose DevTools/BiDi endpoints
    Selenium-->>Test: return configured WebDriver instance
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is specific and clearly describes the main change: fixing a flaky Selenium test issue specific to Chromium v126+.
Description check ✅ Passed The description covers the issue, root cause, solution, and includes a filled checklist. However, it lacks detailed explanation of the implementation (how BiDi mode solves the problem) and test methodology.
Linked Issues check ✅ Passed The PR implements a fix for issue #902 by updating the test strategy to detect unsaved changes reliably without depending on beforeunload alerts, which aligns with all stated objectives.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the flaky test: a single test helper method override is added with necessary imports. No unrelated modifications are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
openwisp_controller/config/tests/test_selenium.py (1)

516-516: Truthy-string gotcha with SELENIUM_HEADLESS env var.

os.environ.get("SELENIUM_HEADLESS", False) will be truthy for any non-empty string, including "0", "false", or "no". This is likely consistent with the parent class behavior, but worth noting — if someone sets SELENIUM_HEADLESS=0 expecting to disable headless mode, it won't work as intended.

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8888a18 and c99e597.

📒 Files selected for processing (1)
  • openwisp_controller/config/tests/test_selenium.py
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-01-15T15:05:49.557Z
Learnt from: DragnEmperor
Repo: openwisp/openwisp-controller PR: 1175
File: openwisp_controller/config/management/commands/clear_last_ip.py:38-42
Timestamp: 2026-01-15T15:05:49.557Z
Learning: In Django projects, when using select_related() to traverse relations (for example, select_related("organization__config_settings")), the traversed relation must not be deferred. If you also use .only() in the same query, include the relation name or FK field (e.g., "organization" or "organization_id") in the .only() list to avoid the error "Field X cannot be both deferred and traversed using select_related at the same time." Apply this guideline to Django code in openwisp_controller/config/management/commands/clear_last_ip.py and similar modules by ensuring any select_related with an accompanying only() includes the related field names to prevent deferred/traversed conflicts.

Applied to files:

  • openwisp_controller/config/tests/test_selenium.py
📚 Learning: 2026-01-15T15:07:17.354Z
Learnt from: DragnEmperor
Repo: openwisp/openwisp-controller PR: 1175
File: openwisp_controller/geo/estimated_location/tests/tests.py:172-175
Timestamp: 2026-01-15T15:07:17.354Z
Learning: In this repository, flake8 enforces E501 (line too long) via setup.cfg (max-line-length = 88) while ruff ignores E501 via ruff.toml. Therefore, use '# noqa: E501' on lines that intentionally exceed 88 characters to satisfy flake8 without affecting ruff checks. This applies to Python files across the project (any .py) and is relevant for tests as well. Use sparingly and only where breaking lines is not feasible without hurting readability or functionality.

Applied to files:

  • openwisp_controller/config/tests/test_selenium.py
🔇 Additional comments (2)
openwisp_controller/config/tests/test_selenium.py (2)

531-532: Verify enable_bidi compatibility with your Selenium version.

options.enable_bidi = True requires Selenium 4.22.0 or later. Ensure the Selenium version pinned in your project meets this minimum requirement, otherwise instantiation will silently set an unknown attribute without effect or raise an error.

Likely an incorrect or invalid review comment.


504-533: The parent class doesn't have a get_chrome_webdriver method—this code is new, not an override.

The BaseSeleniumTestMixin from openwisp-utils (current versions 1.2.x–1.3.x) uses Firefox, not Chrome, and does not expose a get_chrome_webdriver method. This is entirely new code added to support Chrome-specific testing of the beforeunload alert behavior. The docstring incorrectly claims this overrides a parent method that doesn't exist. Calling super().get_chrome_webdriver() (as suggested) would fail.

While the Chrome setup code is verbose, it reflects the necessary Selenium API calls rather than avoidable duplication from a parent. The enable_bidi = True attribute is valid in Selenium and correctly enables WebDriver BiDi support for the session.

Likely an incorrect or invalid review comment.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Mahathi-s154 Mahathi-s154 force-pushed the issues/902-fix-selenium-unsaved-changes branch from 56196d2 to 8888a18 Compare February 9, 2026 15:22
Chromium v126 auto-accepts beforeunload dialogs in classic WebDriver
sessions, causing Selenium tests waiting for alerts to fail.

This change updates the test strategy to reliably detect unsaved
changes without relying on deprecated beforeunload alert behavior.

Fixes openwisp#902
@Mahathi-s154 Mahathi-s154 force-pushed the issues/902-fix-selenium-unsaved-changes branch from 8888a18 to c99e597 Compare February 9, 2026 16:13
@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/openwisp/openwisp-controller/issues/comments/3871073300","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n## Walkthrough\n\nA classmethod `get_chrome_webdriver` was added to `TestDeviceAdminUnsavedChanges` in `openwisp_controller/config/tests/test_selenium.py`. The method imports `os`, `selenium.webdriver`, and `free_port`, builds ChromeOptions (headless handling, binary location, window size, stability flags), sets BiDi-related capabilities and `unhandledPromptBehavior: \"ignore\"`, and assigns a dynamic `remote-debugging-port` from `free_port()`. The change only affects WebDriver configuration for the test; no other test behavior was modified.\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant Test as Test Runner\n    participant Selenium as Selenium Client\n    participant OS as Host OS\n    participant Chrome as Chrome Browser\n\n    Test->>Selenium: call TestDeviceAdminUnsavedChanges.get_chrome_webdriver()\n    Selenium->>OS: request free_port()\n    OS-->>Selenium: return port\n    Selenium->>Chrome: start Chrome with ChromeOptions (headless?, binary, window size, flags, remote-debugging-port, BiDi caps, unhandledPromptBehavior)\n    Chrome-->>Selenium: expose DevTools/BiDi endpoints\n    Selenium-->>Test: return configured WebDriver instance\n```\n\n## Estimated code review effort\n\n🎯 2 (Simple) | ⏱️ ~8 minutes\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 4</summary>\n\n<details>\n<summary>✅ Passed checks (4 passed)</summary>\n\n|         Check name         | Status   | Explanation                                                                                                                                                                                                    |\n| :------------------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|         Title check        | ✅ Passed | The title is specific and clearly describes the main change: fixing a flaky Selenium test issue specific to Chromium v126+.                                                                                    |\n|      Description check     | ✅ Passed | The description covers the issue, root cause, solution, and includes a filled checklist. However, it lacks detailed explanation of the implementation (how BiDi mode solves the problem) and test methodology. |\n|     Linked Issues check    | ✅ Passed | The PR implements a fix for issue `#902` by updating the test strategy to detect unsaved changes reliably without depending on beforeunload alerts, which aligns with all stated objectives.                     |\n| Out of Scope Changes check | ✅ Passed | All changes are scoped to fixing the flaky test: a single test helper method override is added with necessary imports. No unrelated modifications are present.                                                 |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>openwisp_controller/config/tests/test_selenium.py (1)</summary><blockquote>\n\n`516-516`: **Truthy-string gotcha with `SELENIUM_HEADLESS` env var.**\n\n`os.environ.get(\"SELENIUM_HEADLESS\", False)` will be truthy for *any* non-empty string, including `\"0\"`, `\"false\"`, or `\"no\"`. This is likely consistent with the parent class behavior, but worth noting — if someone sets `SELENIUM_HEADLESS=0` expecting to disable headless mode, it won't work as intended.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<details>\n<summary>📜 Recent review details</summary>\n\n**Configuration used**: Organization UI\n\n**Review profile**: CHILL\n\n**Plan**: Pro\n\n<details>\n<summary>📥 Commits</summary>\n\nReviewing files that changed from the base of the PR and between 8888a18ef35e7fa4afb639c360755860bc5a0c04 and c99e597ff5648182111b355aff33c59d9190f838.\n\n</details>\n\n<details>\n<summary>📒 Files selected for processing (1)</summary>\n\n* `openwisp_controller/config/tests/test_selenium.py`\n\n</details>\n\n<details>\n<summary>🧰 Additional context used</summary>\n\n<details>\n<summary>🧠 Learnings (2)</summary>\n\n<details>\n<summary>📚 Learning: 2026-01-15T15:05:49.557Z</summary>\n\n```\nLearnt from: DragnEmperor\nRepo: openwisp/openwisp-controller PR: 1175\nFile: openwisp_controller/config/management/commands/clear_last_ip.py:38-42\nTimestamp: 2026-01-15T15:05:49.557Z\nLearning: In Django projects, when using select_related() to traverse relations (for example, select_related(\"organization__config_settings\")), the traversed relation must not be deferred. If you also use .only() in the same query, include the relation name or FK field (e.g., \"organization\" or \"organization_id\") in the .only() list to avoid the error \"Field X cannot be both deferred and traversed using select_related at the same time.\" Apply this guideline to Django code in openwisp_controller/config/management/commands/clear_last_ip.py and similar modules by ensuring any select_related with an accompanying only() includes the related field names to prevent deferred/traversed conflicts.\n```\n\n**Applied to files:**\n- `openwisp_controller/config/tests/test_selenium.py`\n\n</details>\n<details>\n<summary>📚 Learning: 2026-01-15T15:07:17.354Z</summary>\n\n```\nLearnt from: DragnEmperor\nRepo: openwisp/openwisp-controller PR: 1175\nFile: openwisp_controller/geo/estimated_location/tests/tests.py:172-175\nTimestamp: 2026-01-15T15:07:17.354Z\nLearning: In this repository, flake8 enforces E501 (line too long) via setup.cfg (max-line-length = 88) while ruff ignores E501 via ruff.toml. Therefore, use '# noqa: E501' on lines that intentionally exceed 88 characters to satisfy flake8 without affecting ruff checks. This applies to Python files across the project (any .py) and is relevant for tests as well. Use sparingly and only where breaking lines is not feasible without hurting readability or functionality.\n```\n\n**Applied to files:**\n- `openwisp_controller/config/tests/test_selenium.py`\n\n</details>\n\n</details>\n\n</details>\n\n<details>\n<summary>🔇 Additional comments (2)</summary><blockquote>\n\n<details>\n<summary>openwisp_controller/config/tests/test_selenium.py (2)</summary><blockquote>\n\n`531-532`: **Verify `enable_bidi` compatibility with your Selenium version.**\n\n`options.enable_bidi = True` requires Selenium 4.22.0 or later. Ensure the Selenium version pinned in your project meets this minimum requirement, otherwise instantiation will silently set an unknown attribute without effect or raise an error.\n\n\n> Likely an incorrect or invalid review comment.\n\n---\n\n`504-533`: **The parent class doesn't have a `get_chrome_webdriver` method—this code is new, not an override.**\n\nThe `BaseSeleniumTestMixin` from `openwisp-utils` (current versions 1.2.x–1.3.x) uses Firefox, not Chrome, and does not expose a `get_chrome_webdriver` method. This is entirely new code added to support Chrome-specific testing of the beforeunload alert behavior. The docstring incorrectly claims this overrides a parent method that doesn't exist. Calling `super().get_chrome_webdriver()` (as suggested) would fail.\n\nWhile the Chrome setup code is verbose, it reflects the necessary Selenium API calls rather than avoidable duplication from a parent. The `enable_bidi = True` attribute is valid in Selenium and correctly enables WebDriver BiDi support for the session.\n\n\n\n> Likely an incorrect or invalid review comment.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<sub>✏️ Tip: You can disable this entire section by setting `review_details` to `false` in your review settings.</sub>\n\n</details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=openwisp/openwisp-controller&utm_content=1220)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/openwisp/openwisp-controller/issues/comments/3871073300","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:22:29 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"8041:274E67:1256B2:4EC61A:698A09C3","x-ratelimit-limit":"5400","x-ratelimit-remaining":"5395","x-ratelimit-reset":"1770657721","x-ratelimit-resource":"core","x-ratelimit-used":"5","x-xss-protection":"0"},"data":""}}

3 similar comments
@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/openwisp/openwisp-controller/issues/comments/3871073300","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n## Walkthrough\n\nA classmethod `get_chrome_webdriver` was added to `TestDeviceAdminUnsavedChanges` in `openwisp_controller/config/tests/test_selenium.py`. The method imports `os`, `selenium.webdriver`, and `free_port`, builds ChromeOptions (headless handling, binary location, window size, stability flags), sets BiDi-related capabilities and `unhandledPromptBehavior: \"ignore\"`, and assigns a dynamic `remote-debugging-port` from `free_port()`. The change only affects WebDriver configuration for the test; no other test behavior was modified.\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant Test as Test Runner\n    participant Selenium as Selenium Client\n    participant OS as Host OS\n    participant Chrome as Chrome Browser\n\n    Test->>Selenium: call TestDeviceAdminUnsavedChanges.get_chrome_webdriver()\n    Selenium->>OS: request free_port()\n    OS-->>Selenium: return port\n    Selenium->>Chrome: start Chrome with ChromeOptions (headless?, binary, window size, flags, remote-debugging-port, BiDi caps, unhandledPromptBehavior)\n    Chrome-->>Selenium: expose DevTools/BiDi endpoints\n    Selenium-->>Test: return configured WebDriver instance\n```\n\n## Estimated code review effort\n\n🎯 2 (Simple) | ⏱️ ~8 minutes\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 4</summary>\n\n<details>\n<summary>✅ Passed checks (4 passed)</summary>\n\n|         Check name         | Status   | Explanation                                                                                                                                                                                                    |\n| :------------------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|         Title check        | ✅ Passed | The title is specific and clearly describes the main change: fixing a flaky Selenium test issue specific to Chromium v126+.                                                                                    |\n|      Description check     | ✅ Passed | The description covers the issue, root cause, solution, and includes a filled checklist. However, it lacks detailed explanation of the implementation (how BiDi mode solves the problem) and test methodology. |\n|     Linked Issues check    | ✅ Passed | The PR implements a fix for issue `#902` by updating the test strategy to detect unsaved changes reliably without depending on beforeunload alerts, which aligns with all stated objectives.                     |\n| Out of Scope Changes check | ✅ Passed | All changes are scoped to fixing the flaky test: a single test helper method override is added with necessary imports. No unrelated modifications are present.                                                 |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>openwisp_controller/config/tests/test_selenium.py (1)</summary><blockquote>\n\n`516-516`: **Truthy-string gotcha with `SELENIUM_HEADLESS` env var.**\n\n`os.environ.get(\"SELENIUM_HEADLESS\", False)` will be truthy for *any* non-empty string, including `\"0\"`, `\"false\"`, or `\"no\"`. This is likely consistent with the parent class behavior, but worth noting — if someone sets `SELENIUM_HEADLESS=0` expecting to disable headless mode, it won't work as intended.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<details>\n<summary>📜 Recent review details</summary>\n\n**Configuration used**: Organization UI\n\n**Review profile**: CHILL\n\n**Plan**: Pro\n\n<details>\n<summary>📥 Commits</summary>\n\nReviewing files that changed from the base of the PR and between 8888a18ef35e7fa4afb639c360755860bc5a0c04 and c99e597ff5648182111b355aff33c59d9190f838.\n\n</details>\n\n<details>\n<summary>📒 Files selected for processing (1)</summary>\n\n* `openwisp_controller/config/tests/test_selenium.py`\n\n</details>\n\n<details>\n<summary>🧰 Additional context used</summary>\n\n<details>\n<summary>🧠 Learnings (2)</summary>\n\n<details>\n<summary>📚 Learning: 2026-01-15T15:05:49.557Z</summary>\n\n```\nLearnt from: DragnEmperor\nRepo: openwisp/openwisp-controller PR: 1175\nFile: openwisp_controller/config/management/commands/clear_last_ip.py:38-42\nTimestamp: 2026-01-15T15:05:49.557Z\nLearning: In Django projects, when using select_related() to traverse relations (for example, select_related(\"organization__config_settings\")), the traversed relation must not be deferred. If you also use .only() in the same query, include the relation name or FK field (e.g., \"organization\" or \"organization_id\") in the .only() list to avoid the error \"Field X cannot be both deferred and traversed using select_related at the same time.\" Apply this guideline to Django code in openwisp_controller/config/management/commands/clear_last_ip.py and similar modules by ensuring any select_related with an accompanying only() includes the related field names to prevent deferred/traversed conflicts.\n```\n\n**Applied to files:**\n- `openwisp_controller/config/tests/test_selenium.py`\n\n</details>\n<details>\n<summary>📚 Learning: 2026-01-15T15:07:17.354Z</summary>\n\n```\nLearnt from: DragnEmperor\nRepo: openwisp/openwisp-controller PR: 1175\nFile: openwisp_controller/geo/estimated_location/tests/tests.py:172-175\nTimestamp: 2026-01-15T15:07:17.354Z\nLearning: In this repository, flake8 enforces E501 (line too long) via setup.cfg (max-line-length = 88) while ruff ignores E501 via ruff.toml. Therefore, use '# noqa: E501' on lines that intentionally exceed 88 characters to satisfy flake8 without affecting ruff checks. This applies to Python files across the project (any .py) and is relevant for tests as well. Use sparingly and only where breaking lines is not feasible without hurting readability or functionality.\n```\n\n**Applied to files:**\n- `openwisp_controller/config/tests/test_selenium.py`\n\n</details>\n\n</details>\n\n</details>\n\n<details>\n<summary>🔇 Additional comments (2)</summary><blockquote>\n\n<details>\n<summary>openwisp_controller/config/tests/test_selenium.py (2)</summary><blockquote>\n\n`531-532`: **Verify `enable_bidi` compatibility with your Selenium version.**\n\n`options.enable_bidi = True` requires Selenium 4.22.0 or later. Ensure the Selenium version pinned in your project meets this minimum requirement, otherwise instantiation will silently set an unknown attribute without effect or raise an error.\n\n\n> Likely an incorrect or invalid review comment.\n\n---\n\n`504-533`: **The parent class doesn't have a `get_chrome_webdriver` method—this code is new, not an override.**\n\nThe `BaseSeleniumTestMixin` from `openwisp-utils` (current versions 1.2.x–1.3.x) uses Firefox, not Chrome, and does not expose a `get_chrome_webdriver` method. This is entirely new code added to support Chrome-specific testing of the beforeunload alert behavior. The docstring incorrectly claims this overrides a parent method that doesn't exist. Calling `super().get_chrome_webdriver()` (as suggested) would fail.\n\nWhile the Chrome setup code is verbose, it reflects the necessary Selenium API calls rather than avoidable duplication from a parent. The `enable_bidi = True` attribute is valid in Selenium and correctly enables WebDriver BiDi support for the session.\n\n\n\n> Likely an incorrect or invalid review comment.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<sub>✏️ Tip: You can disable this entire section by setting `review_details` to `false` in your review settings.</sub>\n\n</details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=openwisp/openwisp-controller&utm_content=1220)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/openwisp/openwisp-controller/issues/comments/3871073300","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:22:29 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"8041:274E67:1256B2:4EC61A:698A09C3","x-ratelimit-limit":"5400","x-ratelimit-remaining":"5395","x-ratelimit-reset":"1770657721","x-ratelimit-resource":"core","x-ratelimit-used":"5","x-xss-protection":"0"},"data":""}}

@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/openwisp/openwisp-controller/issues/comments/3871073300","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n## Walkthrough\n\nA classmethod `get_chrome_webdriver` was added to `TestDeviceAdminUnsavedChanges` in `openwisp_controller/config/tests/test_selenium.py`. The method imports `os`, `selenium.webdriver`, and `free_port`, builds ChromeOptions (headless handling, binary location, window size, stability flags), sets BiDi-related capabilities and `unhandledPromptBehavior: \"ignore\"`, and assigns a dynamic `remote-debugging-port` from `free_port()`. The change only affects WebDriver configuration for the test; no other test behavior was modified.\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant Test as Test Runner\n    participant Selenium as Selenium Client\n    participant OS as Host OS\n    participant Chrome as Chrome Browser\n\n    Test->>Selenium: call TestDeviceAdminUnsavedChanges.get_chrome_webdriver()\n    Selenium->>OS: request free_port()\n    OS-->>Selenium: return port\n    Selenium->>Chrome: start Chrome with ChromeOptions (headless?, binary, window size, flags, remote-debugging-port, BiDi caps, unhandledPromptBehavior)\n    Chrome-->>Selenium: expose DevTools/BiDi endpoints\n    Selenium-->>Test: return configured WebDriver instance\n```\n\n## Estimated code review effort\n\n🎯 2 (Simple) | ⏱️ ~8 minutes\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 4</summary>\n\n<details>\n<summary>✅ Passed checks (4 passed)</summary>\n\n|         Check name         | Status   | Explanation                                                                                                                                                                                                    |\n| :------------------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|         Title check        | ✅ Passed | The title is specific and clearly describes the main change: fixing a flaky Selenium test issue specific to Chromium v126+.                                                                                    |\n|      Description check     | ✅ Passed | The description covers the issue, root cause, solution, and includes a filled checklist. However, it lacks detailed explanation of the implementation (how BiDi mode solves the problem) and test methodology. |\n|     Linked Issues check    | ✅ Passed | The PR implements a fix for issue `#902` by updating the test strategy to detect unsaved changes reliably without depending on beforeunload alerts, which aligns with all stated objectives.                     |\n| Out of Scope Changes check | ✅ Passed | All changes are scoped to fixing the flaky test: a single test helper method override is added with necessary imports. No unrelated modifications are present.                                                 |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>openwisp_controller/config/tests/test_selenium.py (1)</summary><blockquote>\n\n`516-516`: **Truthy-string gotcha with `SELENIUM_HEADLESS` env var.**\n\n`os.environ.get(\"SELENIUM_HEADLESS\", False)` will be truthy for *any* non-empty string, including `\"0\"`, `\"false\"`, or `\"no\"`. This is likely consistent with the parent class behavior, but worth noting — if someone sets `SELENIUM_HEADLESS=0` expecting to disable headless mode, it won't work as intended.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<details>\n<summary>📜 Recent review details</summary>\n\n**Configuration used**: Organization UI\n\n**Review profile**: CHILL\n\n**Plan**: Pro\n\n<details>\n<summary>📥 Commits</summary>\n\nReviewing files that changed from the base of the PR and between 8888a18ef35e7fa4afb639c360755860bc5a0c04 and c99e597ff5648182111b355aff33c59d9190f838.\n\n</details>\n\n<details>\n<summary>📒 Files selected for processing (1)</summary>\n\n* `openwisp_controller/config/tests/test_selenium.py`\n\n</details>\n\n<details>\n<summary>🧰 Additional context used</summary>\n\n<details>\n<summary>🧠 Learnings (2)</summary>\n\n<details>\n<summary>📚 Learning: 2026-01-15T15:05:49.557Z</summary>\n\n```\nLearnt from: DragnEmperor\nRepo: openwisp/openwisp-controller PR: 1175\nFile: openwisp_controller/config/management/commands/clear_last_ip.py:38-42\nTimestamp: 2026-01-15T15:05:49.557Z\nLearning: In Django projects, when using select_related() to traverse relations (for example, select_related(\"organization__config_settings\")), the traversed relation must not be deferred. If you also use .only() in the same query, include the relation name or FK field (e.g., \"organization\" or \"organization_id\") in the .only() list to avoid the error \"Field X cannot be both deferred and traversed using select_related at the same time.\" Apply this guideline to Django code in openwisp_controller/config/management/commands/clear_last_ip.py and similar modules by ensuring any select_related with an accompanying only() includes the related field names to prevent deferred/traversed conflicts.\n```\n\n**Applied to files:**\n- `openwisp_controller/config/tests/test_selenium.py`\n\n</details>\n<details>\n<summary>📚 Learning: 2026-01-15T15:07:17.354Z</summary>\n\n```\nLearnt from: DragnEmperor\nRepo: openwisp/openwisp-controller PR: 1175\nFile: openwisp_controller/geo/estimated_location/tests/tests.py:172-175\nTimestamp: 2026-01-15T15:07:17.354Z\nLearning: In this repository, flake8 enforces E501 (line too long) via setup.cfg (max-line-length = 88) while ruff ignores E501 via ruff.toml. Therefore, use '# noqa: E501' on lines that intentionally exceed 88 characters to satisfy flake8 without affecting ruff checks. This applies to Python files across the project (any .py) and is relevant for tests as well. Use sparingly and only where breaking lines is not feasible without hurting readability or functionality.\n```\n\n**Applied to files:**\n- `openwisp_controller/config/tests/test_selenium.py`\n\n</details>\n\n</details>\n\n</details>\n\n<details>\n<summary>🔇 Additional comments (2)</summary><blockquote>\n\n<details>\n<summary>openwisp_controller/config/tests/test_selenium.py (2)</summary><blockquote>\n\n`531-532`: **Verify `enable_bidi` compatibility with your Selenium version.**\n\n`options.enable_bidi = True` requires Selenium 4.22.0 or later. Ensure the Selenium version pinned in your project meets this minimum requirement, otherwise instantiation will silently set an unknown attribute without effect or raise an error.\n\n\n> Likely an incorrect or invalid review comment.\n\n---\n\n`504-533`: **The parent class doesn't have a `get_chrome_webdriver` method—this code is new, not an override.**\n\nThe `BaseSeleniumTestMixin` from `openwisp-utils` (current versions 1.2.x–1.3.x) uses Firefox, not Chrome, and does not expose a `get_chrome_webdriver` method. This is entirely new code added to support Chrome-specific testing of the beforeunload alert behavior. The docstring incorrectly claims this overrides a parent method that doesn't exist. Calling `super().get_chrome_webdriver()` (as suggested) would fail.\n\nWhile the Chrome setup code is verbose, it reflects the necessary Selenium API calls rather than avoidable duplication from a parent. The `enable_bidi = True` attribute is valid in Selenium and correctly enables WebDriver BiDi support for the session.\n\n\n\n> Likely an incorrect or invalid review comment.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<sub>✏️ Tip: You can disable this entire section by setting `review_details` to `false` in your review settings.</sub>\n\n</details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=openwisp/openwisp-controller&utm_content=1220)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/openwisp/openwisp-controller/issues/comments/3871073300","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:22:29 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"8041:274E67:1256B2:4EC61A:698A09C3","x-ratelimit-limit":"5400","x-ratelimit-remaining":"5395","x-ratelimit-reset":"1770657721","x-ratelimit-resource":"core","x-ratelimit-used":"5","x-xss-protection":"0"},"data":""}}

@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/openwisp/openwisp-controller/issues/comments/3871073300","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n## Walkthrough\n\nA classmethod `get_chrome_webdriver` was added to `TestDeviceAdminUnsavedChanges` in `openwisp_controller/config/tests/test_selenium.py`. The method imports `os`, `selenium.webdriver`, and `free_port`, builds ChromeOptions (headless handling, binary location, window size, stability flags), sets BiDi-related capabilities and `unhandledPromptBehavior: \"ignore\"`, and assigns a dynamic `remote-debugging-port` from `free_port()`. The change only affects WebDriver configuration for the test; no other test behavior was modified.\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant Test as Test Runner\n    participant Selenium as Selenium Client\n    participant OS as Host OS\n    participant Chrome as Chrome Browser\n\n    Test->>Selenium: call TestDeviceAdminUnsavedChanges.get_chrome_webdriver()\n    Selenium->>OS: request free_port()\n    OS-->>Selenium: return port\n    Selenium->>Chrome: start Chrome with ChromeOptions (headless?, binary, window size, flags, remote-debugging-port, BiDi caps, unhandledPromptBehavior)\n    Chrome-->>Selenium: expose DevTools/BiDi endpoints\n    Selenium-->>Test: return configured WebDriver instance\n```\n\n## Estimated code review effort\n\n🎯 2 (Simple) | ⏱️ ~8 minutes\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 4</summary>\n\n<details>\n<summary>✅ Passed checks (4 passed)</summary>\n\n|         Check name         | Status   | Explanation                                                                                                                                                                                                    |\n| :------------------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|         Title check        | ✅ Passed | The title is specific and clearly describes the main change: fixing a flaky Selenium test issue specific to Chromium v126+.                                                                                    |\n|      Description check     | ✅ Passed | The description covers the issue, root cause, solution, and includes a filled checklist. However, it lacks detailed explanation of the implementation (how BiDi mode solves the problem) and test methodology. |\n|     Linked Issues check    | ✅ Passed | The PR implements a fix for issue `#902` by updating the test strategy to detect unsaved changes reliably without depending on beforeunload alerts, which aligns with all stated objectives.                     |\n| Out of Scope Changes check | ✅ Passed | All changes are scoped to fixing the flaky test: a single test helper method override is added with necessary imports. No unrelated modifications are present.                                                 |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>openwisp_controller/config/tests/test_selenium.py (1)</summary><blockquote>\n\n`516-516`: **Truthy-string gotcha with `SELENIUM_HEADLESS` env var.**\n\n`os.environ.get(\"SELENIUM_HEADLESS\", False)` will be truthy for *any* non-empty string, including `\"0\"`, `\"false\"`, or `\"no\"`. This is likely consistent with the parent class behavior, but worth noting — if someone sets `SELENIUM_HEADLESS=0` expecting to disable headless mode, it won't work as intended.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<details>\n<summary>📜 Recent review details</summary>\n\n**Configuration used**: Organization UI\n\n**Review profile**: CHILL\n\n**Plan**: Pro\n\n<details>\n<summary>📥 Commits</summary>\n\nReviewing files that changed from the base of the PR and between 8888a18ef35e7fa4afb639c360755860bc5a0c04 and c99e597ff5648182111b355aff33c59d9190f838.\n\n</details>\n\n<details>\n<summary>📒 Files selected for processing (1)</summary>\n\n* `openwisp_controller/config/tests/test_selenium.py`\n\n</details>\n\n<details>\n<summary>🧰 Additional context used</summary>\n\n<details>\n<summary>🧠 Learnings (2)</summary>\n\n<details>\n<summary>📚 Learning: 2026-01-15T15:05:49.557Z</summary>\n\n```\nLearnt from: DragnEmperor\nRepo: openwisp/openwisp-controller PR: 1175\nFile: openwisp_controller/config/management/commands/clear_last_ip.py:38-42\nTimestamp: 2026-01-15T15:05:49.557Z\nLearning: In Django projects, when using select_related() to traverse relations (for example, select_related(\"organization__config_settings\")), the traversed relation must not be deferred. If you also use .only() in the same query, include the relation name or FK field (e.g., \"organization\" or \"organization_id\") in the .only() list to avoid the error \"Field X cannot be both deferred and traversed using select_related at the same time.\" Apply this guideline to Django code in openwisp_controller/config/management/commands/clear_last_ip.py and similar modules by ensuring any select_related with an accompanying only() includes the related field names to prevent deferred/traversed conflicts.\n```\n\n**Applied to files:**\n- `openwisp_controller/config/tests/test_selenium.py`\n\n</details>\n<details>\n<summary>📚 Learning: 2026-01-15T15:07:17.354Z</summary>\n\n```\nLearnt from: DragnEmperor\nRepo: openwisp/openwisp-controller PR: 1175\nFile: openwisp_controller/geo/estimated_location/tests/tests.py:172-175\nTimestamp: 2026-01-15T15:07:17.354Z\nLearning: In this repository, flake8 enforces E501 (line too long) via setup.cfg (max-line-length = 88) while ruff ignores E501 via ruff.toml. Therefore, use '# noqa: E501' on lines that intentionally exceed 88 characters to satisfy flake8 without affecting ruff checks. This applies to Python files across the project (any .py) and is relevant for tests as well. Use sparingly and only where breaking lines is not feasible without hurting readability or functionality.\n```\n\n**Applied to files:**\n- `openwisp_controller/config/tests/test_selenium.py`\n\n</details>\n\n</details>\n\n</details>\n\n<details>\n<summary>🔇 Additional comments (2)</summary><blockquote>\n\n<details>\n<summary>openwisp_controller/config/tests/test_selenium.py (2)</summary><blockquote>\n\n`531-532`: **Verify `enable_bidi` compatibility with your Selenium version.**\n\n`options.enable_bidi = True` requires Selenium 4.22.0 or later. Ensure the Selenium version pinned in your project meets this minimum requirement, otherwise instantiation will silently set an unknown attribute without effect or raise an error.\n\n\n> Likely an incorrect or invalid review comment.\n\n---\n\n`504-533`: **The parent class doesn't have a `get_chrome_webdriver` method—this code is new, not an override.**\n\nThe `BaseSeleniumTestMixin` from `openwisp-utils` (current versions 1.2.x–1.3.x) uses Firefox, not Chrome, and does not expose a `get_chrome_webdriver` method. This is entirely new code added to support Chrome-specific testing of the beforeunload alert behavior. The docstring incorrectly claims this overrides a parent method that doesn't exist. Calling `super().get_chrome_webdriver()` (as suggested) would fail.\n\nWhile the Chrome setup code is verbose, it reflects the necessary Selenium API calls rather than avoidable duplication from a parent. The `enable_bidi = True` attribute is valid in Selenium and correctly enables WebDriver BiDi support for the session.\n\n\n\n> Likely an incorrect or invalid review comment.\n\n</blockquote></details>\n\n</blockquote></details>\n\n<sub>✏️ Tip: You can disable this entire section by setting `review_details` to `false` in your review settings.</sub>\n\n</details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=openwisp/openwisp-controller&utm_content=1220)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/openwisp/openwisp-controller/issues/comments/3871073300","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:22:29 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"8041:274E67:1256B2:4EC61A:698A09C3","x-ratelimit-limit":"5400","x-ratelimit-remaining":"5395","x-ratelimit-reset":"1770657721","x-ratelimit-resource":"core","x-ratelimit-used":"5","x-xss-protection":"0"},"data":""}}

@coveralls
Copy link

Coverage Status

coverage: 98.607%. remained the same
when pulling 28ec326 on Mahathi-s154:issues/902-fix-selenium-unsaved-changes
into 012a094 on openwisp:master.

@Mahathi-s154
Copy link
Author

Hi @nemesifier ,
All required CI checks for this PR are passing successfully.
Requesting your review and merge when convenient.
Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] Flaky Selenium Test: test_unsaved_changes

3 participants