|
| 1 | +# Tests |
| 2 | + |
| 3 | +The test suite uses PHPUnit and runs inside the Docker-based `@wordpress/env` environment against a live WordPress install. The `npm run composer` script is a wrapper that executes `composer` inside the `tests-cli` container at the plugin path. |
| 4 | + |
| 5 | +## Running Tests |
| 6 | + |
| 7 | +```bash |
| 8 | +# Full test suite |
| 9 | +npm test |
| 10 | + |
| 11 | +# Watch mode (re-runs on file changes, no coverage) |
| 12 | +npm run test:watch |
| 13 | + |
| 14 | +# Full test suite with coverage (requires xdebug-enabled env) |
| 15 | +npm run env start -- --xdebug=coverage |
| 16 | +npm test |
| 17 | +``` |
| 18 | + |
| 19 | +Coverage reports are written to `tests/logs/clover.xml` and `tests/logs/html/`. Open `tests/logs/html/index.html` in a browser to view the HTML report. |
| 20 | + |
| 21 | +### Filtering |
| 22 | + |
| 23 | +Pass PHPUnit arguments through the `composer` wrapper: |
| 24 | + |
| 25 | +```bash |
| 26 | +# Run a single test class |
| 27 | +npm run composer -- test -- --filter Tests_Two_Factor_Core |
| 28 | + |
| 29 | +# Run a single test method |
| 30 | +npm run composer -- test -- --filter test_create_login_nonce |
| 31 | + |
| 32 | +# Run by @group annotation |
| 33 | +npm run composer -- test -- --group totp |
| 34 | +npm run composer -- test -- --group email |
| 35 | +npm run composer -- test -- --group backup-codes |
| 36 | +npm run composer -- test -- --group providers |
| 37 | +npm run composer -- test -- --group core |
| 38 | + |
| 39 | +# Run a single file |
| 40 | +npm run composer -- test -- tests/providers/class-two-factor-totp.php |
| 41 | +``` |
| 42 | + |
| 43 | +## Test Files |
| 44 | + |
| 45 | +### Plugin Bootstrap — `tests/two-factor.php` |
| 46 | + |
| 47 | +**Class:** `Tests_Two_Factor` |
| 48 | +Smoke tests that the plugin loaded correctly: the `TWO_FACTOR_DIR` constant is defined and the core classes exist. |
| 49 | + |
| 50 | +### Core — `tests/class-two-factor-core.php` |
| 51 | + |
| 52 | +**Class:** `Tests_Two_Factor_Core` · **Group:** `core` |
| 53 | +The largest test file. Covers the full authentication lifecycle managed by `Two_Factor_Core`: |
| 54 | + |
| 55 | +- Hook registration (`add_hooks`) |
| 56 | +- Provider registration and retrieval (`get_providers`, `get_enabled_providers_for_user`, `get_available_providers_for_user`, `get_primary_provider_for_user`) |
| 57 | +- Login interception (`filter_authenticate`, `show_two_factor_login`, `process_provider`) |
| 58 | +- Login nonce creation, verification, and deletion |
| 59 | +- Rate limiting (`get_user_time_delay`, `is_user_rate_limited`) |
| 60 | +- Session management: two-factor factored vs. non-factored sessions, session destruction on 2FA enable/disable, revalidation |
| 61 | +- Password reset flow (compromise detection, email notifications, reset notices) |
| 62 | +- REST API permission callbacks (`rest_api_can_edit_user`) |
| 63 | +- User settings actions (`trigger_user_settings_action`, `current_user_can_update_two_factor_options`) |
| 64 | +- Uninstall cleanup |
| 65 | +- Filter hooks (`two_factor_providers`, `two_factor_primary_provider_for_user`, `two_factor_user_api_login_enable`) |
| 66 | + |
| 67 | +### Provider Base Class — `tests/providers/class-two-factor-provider.php` |
| 68 | + |
| 69 | +**Class:** `Tests_Two_Factor_Provider` · **Group:** `providers` |
| 70 | +Tests the abstract `Two_Factor_Provider` base class: |
| 71 | + |
| 72 | +- Singleton pattern (`get_instance`) |
| 73 | +- Code generation (`get_code`) and request sanitization (`sanitize_code_from_request`) |
| 74 | +- `get_key` returning the class name |
| 75 | +- `is_supported_for_user` (globally registered vs. not) |
| 76 | +- Default implementations of `get_alternative_provider_label`, `pre_process_authentication`, `uninstall_user_meta_keys`, `uninstall_options` |
| 77 | + |
| 78 | +### TOTP Provider — `tests/providers/class-two-factor-totp.php` |
| 79 | + |
| 80 | +**Class:** `Tests_Two_Factor_Totp` · **Groups:** `providers`, `totp` |
| 81 | +Tests `Two_Factor_Totp`: |
| 82 | + |
| 83 | +- Base32 encode/decode (including invalid input exception) |
| 84 | +- QR code URL generation |
| 85 | +- TOTP key storage and retrieval per user |
| 86 | +- Auth code validation (current tick, spaces stripped, invalid chars rejected) |
| 87 | +- `validate_code_for_user` replay protection |
| 88 | +- Algorithm variants: SHA1, SHA256, SHA512 (code generation and authentication) |
| 89 | +- Secret padding (`pad_secret`) |
| 90 | + |
| 91 | +### TOTP REST API — `tests/providers/class-two-factor-totp-rest-api.php` |
| 92 | + |
| 93 | +**Class:** `Tests_Two_Factor_Totp_REST_API` · **Groups:** `providers`, `totp` |
| 94 | +Extends `WP_Test_REST_TestCase`. Tests the TOTP REST endpoints: |
| 95 | + |
| 96 | +- Setting a TOTP key with a valid/invalid/missing auth code |
| 97 | +- Updating an existing TOTP key |
| 98 | +- Deleting own secret |
| 99 | +- Admin deleting another user's secret |
| 100 | +- Non-admin cannot delete another user's secret |
| 101 | + |
| 102 | +### Email Provider — `tests/providers/class-two-factor-email.php` |
| 103 | + |
| 104 | +**Class:** `Tests_Two_Factor_Email` · **Groups:** `providers`, `email` |
| 105 | +Tests `Two_Factor_Email`: |
| 106 | + |
| 107 | +- Token generation and validation (same user, different user, deleted token) |
| 108 | +- Email delivery (`generate_and_email_token`) |
| 109 | +- Authentication page rendering (no user, no token, existing token) |
| 110 | +- `validate_authentication` (valid, missing input, spaces stripped) |
| 111 | +- Token TTL and expiry |
| 112 | +- Token generation time tracking |
| 113 | +- Custom token length filter |
| 114 | +- `pre_process_authentication` (resend vs. no resend) |
| 115 | +- User options UI output |
| 116 | +- Uninstall meta key cleanup |
| 117 | + |
| 118 | +### Backup Codes Provider — `tests/providers/class-two-factor-backup-codes.php` |
| 119 | + |
| 120 | +**Class:** `Tests_Two_Factor_Backup_Codes` · **Groups:** `providers`, `backup-codes` |
| 121 | +Tests `Two_Factor_Backup_Codes`: |
| 122 | + |
| 123 | +- Code generation and validation |
| 124 | +- Replay prevention (code invalidated after use) |
| 125 | +- Cross-user isolation (code invalid for different user) |
| 126 | +- `is_available_for_user` (no codes vs. codes generated) |
| 127 | +- User options UI output |
| 128 | +- Code deletion |
| 129 | +- `two_factor_backup_codes_count` filter for customizing code length |
| 130 | + |
| 131 | +### Backup Codes REST API — `tests/providers/class-two-factor-backup-codes-rest-api.php` |
| 132 | + |
| 133 | +**Class:** `Tests_Two_Factor_Backup_Codes_REST_API` · **Groups:** `providers`, `backup-codes` |
| 134 | +Extends `WP_Test_REST_TestCase`. Tests the backup codes REST endpoints: |
| 135 | + |
| 136 | +- Generate codes and validate the downloadable file contents |
| 137 | +- User cannot generate codes for a different user |
| 138 | +- Admin can generate codes for other users |
| 139 | + |
| 140 | +### Dummy Provider — `tests/providers/class-two-factor-dummy.php` |
| 141 | + |
| 142 | +**Class:** `Tests_Two_Factor_Dummy` · **Groups:** `providers`, `dummy` |
| 143 | +Tests the `Two_Factor_Dummy` provider (always passes authentication — used as a test fixture): |
| 144 | + |
| 145 | +- `get_instance`, `get_label`, `authentication_page`, `validate_authentication`, `is_available_for_user` |
| 146 | + |
| 147 | +### Dummy Secure Provider — `tests/providers/class-two-factor-dummy-secure.php` |
| 148 | + |
| 149 | +**Class:** `Tests_Two_Factor_Dummy_Secure` · **Groups:** `providers`, `dummy` |
| 150 | +Tests `Two_Factor_Dummy_Secure` (a fixture that always _fails_ authentication, used to test the provider class name filter): |
| 151 | + |
| 152 | +- `get_key` override returns `Two_Factor_Dummy` |
| 153 | +- Authentication page rendering |
| 154 | +- `validate_authentication` always returns false |
| 155 | +- `two_factor_provider_classname` filter |
| 156 | + |
| 157 | +## Test Helpers |
| 158 | + |
| 159 | +- **`tests/bootstrap.php`** — Locates the WordPress test library (via `WP_TESTS_DIR` env var, relative path, or `/tmp/wordpress-tests-lib`), loads the plugin via `muplugins_loaded`, then boots the WP test environment. |
| 160 | +- **`tests/class-secure-dummy.php`** — Defines `Two_Factor_Dummy_Secure`, a test-only provider class that spoofs the key of `Two_Factor_Dummy` but always fails `validate_authentication`. Used by `Tests_Two_Factor_Dummy_Secure` and some core tests. |
0 commit comments