Skip to content

Add unit tests for site-wide enabled providers settings - #981

Open
noruzzamans wants to merge 2 commits into
WordPress:masterfrom
noruzzamans:test/add-site-wide-settings-unit-tests
Open

noruzzamans wants to merge 2 commits into
WordPress:masterfrom
noruzzamans:test/add-site-wide-settings-unit-tests

Conversation

@noruzzamans

@noruzzamans noruzzamans commented Sep 15, 2026

Copy link
Copy Markdown

What?

Adds comprehensive PHPUnit unit test coverage for the site-wide Two-Factor settings screen (Two_Factor_Settings) and the provider enforcement filter hooks in two-factor.php, while restricting the admin screen bypass check to the actual settings screen to prevent query argument spoofing on user profile screens.

Why?

The site-wide enabled-providers setting feature lacked dedicated unit test coverage. The settings renderer, save pipeline, and enforcement filters could regress unnoticed:

  • Missing test coverage for manage_options capability enforcement on settings view and form submission.
  • Form rendering, nonce verification, and provider sanitization on save operations.
  • Distinction between an unset state (null, which allows all registered providers by default) and an explicitly saved empty array (array(), which disables all providers).
  • Admin settings screen bypass logic, ensuring disabled providers still display on the admin screen for reconfiguration while strictly preventing the bypass from leaking to user profile screens or front-end contexts.

How?

  1. Settings Screen Bypass Guard (two-factor.php):
    • Restricts the settings bypass in two_factor_filter_enabled_providers() to require manage_options, ensure $pagenow === 'options-general.php', and validate that the current screen belongs to the settings page.
  2. Introduces Tests_Two_Factor_Settings in tests/class-two-factor-settings.php (25 dedicated tests, 40 assertions) covering:
    1. test_settings_class_exists: Verifies Two_Factor_Settings class availability and bootstrap.
    2. test_admin_hooks_register_enforcement_filters: Verifies registration of enforcement filter hooks on admin_init.
    3. test_render_settings_page_requires_manage_options: Enforces manage_options capability requirement on the settings page.
    4. test_render_settings_page_wrapper_requires_manage_options: Verifies capability protection on the settings wrapper callback.
    5. test_render_settings_page_outputs_provider_form: Verifies form rendering, nonce field output, and submit button generation.
    6. test_render_settings_page_checks_all_providers_by_default: Verifies all registered providers are checked by default when option is not yet saved.
    7. test_render_settings_page_checks_only_saved_providers: Verifies only configured providers are checked when settings are saved.
    8. test_render_settings_page_saves_sanitized_unique_providers: Verifies array sanitization, deduplication, and persistence of valid provider keys.
    9. test_render_settings_page_saves_empty_provider_list: Verifies saving with no providers selected correctly stores an empty array.
    10. test_render_settings_page_invalid_nonce_does_not_save: Verifies invalid or missing nonce terminates execution via wp_die() without persisting data.
    11. test_get_enabled_providers_option_returns_null_when_never_saved: Verifies two_factor_get_enabled_providers_option() returns null for unset option.
    12. test_get_enabled_providers_option_returns_saved_array: Verifies retrieval of saved provider key arrays.
    13. test_get_enabled_providers_option_returns_empty_array_when_saved_empty: Distinguishes explicitly empty array from unset state.
    14. test_get_enabled_providers_option_returns_empty_array_for_non_array: Guards against corrupt/malformed non-array option values.
    15. test_filter_enabled_providers_passthrough_when_never_saved: Verifies passthrough behavior for two_factor_filter_enabled_providers() when unset.
    16. test_filter_enabled_providers_removes_disabled_providers: Verifies disallowed providers are stripped from active provider map.
    17. test_filter_enabled_providers_empty_list_disables_all: Verifies empty allow-list removes all registered providers.
    18. test_filter_enabled_providers_bypassed_on_settings_screen: Verifies settings screen bypass allows administrators to re-enable disabled providers.
    19. test_filter_enabled_providers_not_bypassed_outside_admin: Prevents spoofing bypass logic outside administrative context.
    20. test_filter_enabled_providers_not_bypassed_on_profile_screen: Ensures spoofed page query arguments on user profile screens do not bypass provider filtering.
    21. test_filter_enabled_providers_for_user_passthrough_when_never_saved: Verifies user provider passthrough when site-wide setting is unset.
    22. test_filter_enabled_providers_for_user_intersects_site_list: Verifies user-enabled providers are strictly intersected with site allow-list.
    23. test_filter_enabled_providers_for_user_empty_site_list: Verifies empty site allow-list strips all user providers.
    24. test_get_providers_honors_saved_site_allow_list: Verifies Two_Factor_Core::get_providers() honors site-wide allow-list.
    25. test_get_enabled_providers_for_user_honors_site_allow_list: Verifies Two_Factor_Core::get_enabled_providers_for_user() honors site-wide allow-list.

Testing Instructions

  1. Start the local Docker test environment:
    npm run env start
  2. Run the Tests_Two_Factor_Settings test suite:
    npm run composer -- test -- --filter Tests_Two_Factor_Settings
  3. Confirm all 25 tests pass with 40 assertions:
    OK (25 tests, 40 assertions)
    
  4. Run the full test suite to verify zero regressions:
    npm test
  5. Run PHP CodeSniffer and static analysis:
    npm run lint:php
    npm run lint:phpstan
    Expected: 0 errors, 0 warnings.

Testing that has already taken place:

  • Local Environment: Docker wp-env (PHP 8.2, WordPress latest).
  • PHPUnit Suite: Ran Tests_Two_Factor_Settings — 25 tests, 40 assertions passed cleanly.
  • Regression Testing: Full test suite (223 tests, 700 assertions) passed with 0 failures.
  • Static Analysis & Linting: Ran PHPCS (WordPress standard) and PHPStan — 0 errors, 0 warnings.

Changelog Entry

Development Update - Add unit tests for the site-wide enabled providers settings screen and enforcement filters, and tighten settings screen bypass checks.

Open WordPress Playground Preview

The 0.16 settings screen and its enforcement filters had no coverage, so capability checks, save sanitization, and provider allow-list filtering could regress unnoticed.
@noruzzamans
noruzzamans force-pushed the test/add-site-wide-settings-unit-tests branch from 068c773 to fdadc94 Compare September 15, 2026 16:44
@noruzzamans
noruzzamans marked this pull request as ready for review September 15, 2026 16:47
@github-actions

github-actions Bot commented Sep 15, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: noruzzamans <noruzzaman@git.wordpress.org>
Co-authored-by: masteradhoc <masteradhoc@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The promised user-profile bypass protection is untested and currently fails for spoofed admin query arguments.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds PHPUnit coverage for site-wide provider settings and enforcement.

Changes:

  • Tests settings rendering, permissions, saving, and nonce validation.
  • Tests provider allow-list filtering and core integration.
File summaries
File Description
tests/class-two-factor-settings.php Adds 24 settings and provider-enforcement tests.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +386 to +390
public function test_filter_enabled_providers_not_bypassed_outside_admin() {
$_GET['page'] = 'two-factor-settings';
update_option( Two_Factor_Core::ENABLED_PROVIDERS_OPTION_KEY, array( 'Two_Factor_Email' ) );

$result = two_factor_filter_enabled_providers( $this->sample_provider_map() );

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in c2f9c24: restricted the settings screen bypass in two_factor_filter_enabled_providers() to verify $pagenow === 'options-general.php', current_user_can( 'manage_options' ), and current screen context, and added test_filter_enabled_providers_not_bypassed_on_profile_screen() covering admin requests on user profile screens.

@masteradhoc

Copy link
Copy Markdown
Collaborator

Thanks for the PR @noruzzamans! Would you mind checking the open copilot feedback?

Ensure disabled providers are not exposed on user profile screens when the page query parameter is spoofed, and add unit test coverage for profile screen context.
@noruzzamans

Copy link
Copy Markdown
Author

Thanks for flagging that, @masteradhoc!

I've addressed the feedback in c2f9c24:

  1. Restricted settings screen bypass (two-factor.php): Tightened two_factor_filter_enabled_providers() to require manage_options, verify $pagenow === 'options-general.php', and validate that the current screen ID/base belongs to the settings page. This prevents query argument spoofing (?page=two-factor-settings) on user profile screens (profile.php / user-edit.php) from exposing disabled providers.
  2. Added regression test (tests/class-two-factor-settings.php): Added test_filter_enabled_providers_not_bypassed_on_profile_screen() covering an authenticated administrator on profile.php with a spoofed page query argument, ensuring disabled providers remain strictly filtered out.

All 223 tests (700 assertions), PHPCS, and PHPStan pass cleanly locally.

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.

3 participants