Add comprehensive test suite and fix main site compat#336
Add comprehensive test suite and fix main site compat#336superdav42 wants to merge 1 commit intomainfrom
Conversation
… site Add unit tests covering signup fields, admin list pages, database enums, helper functions, gateways, SSO, UI components, validation rules, and an e2e spec for modal form error handling. Fix multiple accounts compat to skip email scoping on the main site where it's unnecessary. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughVersion downgrade from 2.4.11-beta.4 to 2.4.11-beta.3 across configuration files and the main plugin class constant. Translation file updated with new beta-related strings and metadata. Single logic change adds early return in fix_login method for main site. Extensive unit test suite added for multiple components including signup fields, functions, admin pages, and UI elements. Single Cypress e2e test added for modal error handling. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
🔨 Build Complete - Ready for Testing!📦 Download Build Artifact (Recommended)Download the zip build, upload to WordPress and test:
🌐 Test in WordPress Playground (Very Experimental)Click the link below to instantly test this PR in your browser - no installation needed! Login credentials: |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@tests/WP_Ultimo/Checkout/Signup_Fields/Signup_Field_Email_Test.php`:
- Line 1: The test filename
tests/WP_Ultimo/Checkout/Signup_Fields/Signup_Field_Email_Test.php violates
WordPress PHPCS naming (PascalCase); either rename the test file and its class
to lowercase with hyphens (e.g., class-signup-field-email-test.php and matching
class name if necessary) or update the PHPCS config to exclude the tests
directory by adding an exclude-pattern for /tests/ to .phpcs.xml.dist; pick one
approach and apply consistently to other PascalCase test files (referencing
Signup_Field_Email_Test.php and any similarly named test classes).
In `@tests/WP_Ultimo/Functions/Checkout_Functions_Test.php`:
- Around line 126-130: The test fails because wu_multiple_memberships_enabled()
currently returns the raw setting value (which may be a string/int), so update
that function to always return a strict boolean: fetch the setting via
wu_get_setting('enable_multiple_memberships', true) and convert it to a bool
(preferably via wp_validate_boolean(...) for correct handling of
'1'/'true'/'yes' strings) before returning or passing through filters; ensure
the function signature and any filters applied still receive/return a boolean so
assertIsBool() passes.
In `@tests/WP_Ultimo/Helpers/Validation_Rules/Country_Test.php`:
- Around line 44-49: Update the docblock above the test_valid_country_gb method
in Country_Test.php to reference the correct ISO country code "GB" (or say
"United Kingdom") instead of "UK"; locate the test method named
test_valid_country_gb and the assertion $this->rule->check('GB') and change the
comment text so it no longer misleadingly mentions "UK".
In `@ultimate-multisite.php`:
- Line 6: The docblock `@version` tag is out of sync with the plugin header
Version: value; update the `@version` annotation from "2.4.11-beta.1" to
"2.4.11-beta.3" so the docblock and the plugin header match (look for the plugin
header "Version:" and the docblock "@version" string in ultimate-multisite.php
and make them identical).
🧹 Nitpick comments (17)
tests/e2e/cypress/integration/030-modal-form-error-handling.spec.js (2)
2-14: Redundantbeforehook —beforeEachalready covers the first test.The
beforeblock performs the exact same login asbeforeEach. SincebeforeEachruns before every test (including the first one), thebeforehook only adds an extra login round-trip on the first test with no benefit.♻️ Suggested fix
describe("Modal Form Error Handling", () => { - before(() => { - cy.loginByForm( - Cypress.env("admin").username, - Cypress.env("admin").password - ); - }); - beforeEach(() => { cy.loginByForm( Cypress.env("admin").username, Cypress.env("admin").password ); });
92-115: Consider addingcy.wait("@formHandlerNetworkError")for consistency.The other intercept-based tests (500, invalid JSON) use
cy.wait("@alias")after submission, but this test skips it. While the assertion timeout handles it, the explicit wait makes the test intent clearer and produces a more descriptive failure message if the intercept never fires.tests/WP_Ultimo/Functions/Date_Functions_Test.php (1)
116-124: Consider adding a comment or adjusting the test name to clarifywu_get_days_agoalways returns non-positive values.The function negates
DateInterval::$days(which is always absolute), so both past and future dates return the same-1. The inline comment on Line 122 helps, but the test nametest_get_days_ago_future_datecould mislead readers into expecting a positive result. This is a documentation-level nit.tests/WP_Ultimo/Functions/Url_Helpers_Test.php (1)
110-115: Misleading comment about base64 padding.Line 113 says "without padding = char", but
base64_encode('plugins_loaded')does produce=padding (cGx1Z2luc19sb2FkZWQ=). The=is URL-encoded to%3Dbyadd_query_arg, so the regex still matches — the test is correct, but the comment is inaccurate.Suggested comment fix
- // The base64 value is embedded in the URL (without padding = char) - $this->assertMatchesRegularExpression('/wu-when=[a-zA-Z0-9]+/', $url); + // The base64 value is URL-encoded (padding '=' becomes '%3D') + $this->assertMatchesRegularExpression('/wu-when=[a-zA-Z0-9%]+/', $url);tests/WP_Ultimo/Functions/Sort_Helpers_Test.php (1)
86-98: Static analysis: array items should each be on a new line.The linter flagged that multi-item associative arrays should have each value on a new line (lines 88-89).
🔧 Proposed fix
public function test_sort_by_column_with_usort(): void { $items = [ - ['name' => 'C', 'order' => 30], - ['name' => 'A', 'order' => 10], - ['name' => 'B', 'order' => 20], + [ + 'name' => 'C', + 'order' => 30, + ], + [ + 'name' => 'A', + 'order' => 10, + ], + [ + 'name' => 'B', + 'order' => 20, + ], ];tests/WP_Ultimo/Checkout/Signup_Fields/Signup_Field_Submit_Button_Test.php (1)
132-147: Missingelement_classesandwrapper_element_classesin test attributes may cause PHP notices.The production
to_fields_arrayaccesses$attributes['element_classes']for styling. These keys are absent from the test attributes, which could produce undefined-index notices depending on how the base class merges defaults.Proposed fix
$attributes = [ 'id' => 'submit_btn', 'name' => 'Submit', 'step' => 'checkout', 'enable_go_back_button' => false, 'back_button_label' => 'Go Back', + 'element_classes' => '', + 'wrapper_element_classes' => '', ];Apply the same addition to the other
to_fields_arraytest methods in this file.tests/WP_Ultimo/Checkout/Signup_Fields/Signup_Field_Username_Test.php (1)
30-99: Test coverage is lighter than sibling field tests.Compared to other
Signup_Field_*tests in this PR, this file is missing tests fordefaults()(which hasauto_generate_usernameandenable_inline_login_usernamekeys),force_attributes()(which forcesid => 'username'andrequired => true), andto_fields_array(). Theto_fields_arraymethod has interesting branching (auto-generate, logged-in check) that would benefit from coverage, though theis_user_logged_in()dependency may require mocking.tests/WP_Ultimo/Checkout/Signup_Fields/Signup_Field_Email_Test.php (1)
74-77: Weak assertion:assertIsBoolinstead of asserting the actual value.Other field tests (e.g.,
Signup_Field_Username_Test) assert the concrete boolean value (assertTrue/assertFalse). Here,assertIsBoolonly checks the return type without validating correctness. The email field'sis_user_field()likely returnstrue—assert it explicitly.Proposed fix
public function test_is_user_field(): void { - $result = $this->field->is_user_field(); - $this->assertIsBool($result); + $this->assertTrue($this->field->is_user_field()); }tests/WP_Ultimo/Gateways/Free_Gateway_Test.php (1)
115-210: Consider extracting shared setup into a helper method.The user/customer/product/membership creation logic is repeated nearly identically across
test_process_checkout_new,test_process_cancellation, andtest_process_refund. A private helper (e.g.,create_free_membership_setup()) would reduce duplication and make future maintenance easier.♻️ Example helper extraction
+ /** + * Creates a free-plan test setup with user, customer, product, and membership. + * + * `@param` string $login User login. + * `@param` string $email User email. + * `@param` string $status Membership status. + * `@return` array{user_id: int, customer: object, product: object, membership: object} + */ + private function create_free_setup(string $login, string $email, string $status): array { + $user_id = self::factory()->user->create([ + 'user_login' => $login, + 'user_email' => $email, + ]); + + $customer = wu_create_customer([ + 'user_id' => $user_id, + 'email_verification' => 'none', + ]); + $this->assertNotWPError($customer); + + $product = wu_create_product([ + 'name' => 'Free Plan', + 'slug' => 'free-plan-' . wp_generate_uuid4(), + 'pricing_type' => 'free', + 'amount' => 0, + 'type' => 'plan', + ]); + $this->assertNotWPError($product); + + $membership = wu_create_membership([ + 'customer_id' => $customer->get_id(), + 'plan_id' => $product->get_id(), + 'status' => $status, + 'recurring' => false, + 'amount' => 0, + 'skip_validation' => true, + ]); + $this->assertNotWPError($membership); + + return compact('user_id', 'customer', 'product', 'membership'); + }tests/WP_Ultimo/Functions/Checkout_Functions_Test.php (1)
172-186: Duplicate test —test_create_checkout_fields_with_simple_fieldsis identical totest_create_checkout_fields_returns_array.Both tests pass an empty array to
wu_create_checkout_fieldsand assert the result is an array. Either remove the duplicate or make the second test exercise a meaningful field configuration.♻️ Suggested: replace the duplicate with a test that actually exercises field creation
public function test_create_checkout_fields_with_simple_fields(): void { - // Just test with empty array as complex fields need more setup - $fields = wu_create_checkout_fields([]); + // Test with an unknown type to verify graceful handling + $fields = wu_create_checkout_fields([ + ['type' => 'nonexistent_type'], + ]); $this->assertIsArray($fields); + $this->assertEmpty($fields); }tests/WP_Ultimo/SSO/SSO_Test.php (3)
361-407: Source-code regex assertions are brittle and will break on any refactor.These tests read the PHP source file and match regex patterns against it, which means any code reformatting, variable renaming, or restructuring will cause test failures even if behavior is unchanged. This is a maintenance risk.
Consider alternatives:
- Use
@runInSeparateProcess+@preserveGlobalState disabledto test methods that callexit().- Extract the logic before
exit()into a testable helper that the main method delegates to.- Use a test double / mock that intercepts
exit()or overrideswp_safe_redirect.If these tests stay as-is, they should at minimum be tagged with a group (e.g.,
@group source-inspection) so they can be identified and updated during refactors.
544-578: Same source-inspection concern applies to the JSONP header assertions.Counting regex matches (
$count === 2) to verify both code paths set theContent-Typeheader is especially fragile — adding a third JSONP path or an unrelated header call would break the assertion.
340-351:assertTrue(true)is a code smell for "no assertion" — consider a more explicit pattern.While the intent (verifying no exception/exit occurs) is valid,
$this->assertTrue(true)provides no real signal. PHPUnit's$this->expectNotToPerformAssertions()is more explicit when the test genuinely has no assertion, or you could assert a return value.tests/WP_Ultimo/Functions/Financial_Functions_Test.php (1)
65-114: Tests only cover the empty/zero-data baseline.All financial calculation tests (
wu_calculate_arr,wu_calculate_mrr,wu_calculate_revenue,wu_calculate_refunds,wu_calculate_taxes_by_rate,wu_calculate_financial_data_by_product) only assert behavior when there's no data. Consider adding tests that create memberships/payments and verify non-zero calculations to catch regressions in the actual computation logic.tests/WP_Ultimo/Helpers/Validation_Rules/State_Test.php (1)
33-60: Missing negative test: no assertion that an invalid state code fails validation.All state tests assert
assertTrue. There's no test verifying that an invalid state code (e.g.,'ZZ'with country'US') returnsfalse. Without this, you can't confirm the rule actually rejects anything.♻️ Add a failing-validation test
+ /** + * Test invalid US state returns false. + */ + public function test_invalid_us_state(): void { + $this->rule->setParameters(['country' => 'US']); + $this->assertFalse($this->rule->check('ZZ')); + }tests/WP_Ultimo/Functions/Currency_Functions_Test.php (1)
190-193: Weak assertion: custom value passed but not verified in result.
wu_currency_decimal_filter(3)is called but onlyassertIsIntis checked — same as the no-arg test above. Consider asserting the returned value equals (or is influenced by) the input3.💡 Proposed improvement
public function test_currency_decimal_filter_custom(): void { $decimals = wu_currency_decimal_filter(3); $this->assertIsInt($decimals); + $this->assertEquals(3, $decimals); }tests/WP_Ultimo/Admin_Pages/Product_List_Admin_Page_Test.php (1)
33-50: Consider extracting reflection helpers to reduce boilerplate across admin page tests.The same reflection pattern (
new \ReflectionClass→getProperty→setAccessible→getValue) is duplicated inProduct_List_Admin_Page_Test,Payment_List_Admin_Page_Test, andCustomer_List_Admin_Page_Test. A shared trait or base test class with agetProtectedProperty($object, $name)helper would reduce this repetition.💡 Example helper trait
trait ReflectionHelperTrait { protected function getProtectedProperty(object $object, string $property): mixed { $reflection = new \ReflectionClass($object); $prop = $reflection->getProperty($property); $prop->setAccessible(true); return $prop->getValue($object); } }Then usage becomes:
public function test_page_id(): void { - $reflection = new \ReflectionClass($this->page); - $property = $reflection->getProperty('id'); - $property->setAccessible(true); - - $this->assertEquals('wp-ultimo-products', $property->getValue($this->page)); + $this->assertEquals('wp-ultimo-products', $this->getProtectedProperty($this->page, 'id')); }
| @@ -0,0 +1,101 @@ | |||
| <?php | |||
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if other test files in this PR also violate the naming convention
# and whether existing test files follow a different pattern
echo "=== New test files in this PR (Signup_Fields) ==="
fd -t f -e php tests/WP_Ultimo/Checkout/Signup_Fields/ 2>/dev/null | sort
echo ""
echo "=== Broader test directory listing ==="
fd -t f -e php tests/ 2>/dev/null | head -30
echo ""
echo "=== Test files with lowercase-hyphen naming? ==="
fd -t f -e php tests/ 2>/dev/null | grep -E '\-test\.php|_test\.php' | head -20
echo ""
echo "=== Any phpcs or linting config files? ==="
fd -t f -E node_modules "phpcs|phpunit|psalm|phpstan|wp-coding-standards" . 2>/dev/null | head -20
echo ""
echo "=== Content of potential phpcs config files ==="
find . -maxdepth 2 -name ".phpcs.xml*" -o -name "phpcs.xml*" -o -name ".phpcsignore" 2>/dev/null | head -10 | xargs cat 2>/dev/nullRepository: Ultimate-Multisite/ultimate-multisite
Length of output: 6308
🏁 Script executed:
#!/bin/bash
echo "=== Looking for ignore/exclusion files ==="
fd -t f "\.phpcsignore|\.phpcs-exclude|\.eslintignore|\.gitignore" . 2>/dev/null | head -20
echo ""
echo "=== Content of .phpcsignore if exists ==="
cat .phpcsignore 2>/dev/null || echo "(no .phpcsignore found)"
echo ""
echo "=== Content of .gitignore (relevant lines) ==="
cat .gitignore 2>/dev/null | grep -E "test|spec" | head -20 || echo "(no matching patterns)"
echo ""
echo "=== Check if phpcs.xml exists ==="
find . -maxdepth 1 -name ".phpcs.xml*" -o -name "phpcs.xml*" 2>/dev/null | xargs ls -la 2>/dev/null
echo ""
echo "=== Search for any other test files in repo with different naming ==="
find . -path ./vendor -prune -o -type f -name "*test*.php" -print 2>/dev/null | head -20Repository: Ultimate-Multisite/ultimate-multisite
Length of output: 586
Filename does not follow WordPress coding standards — rename or exclude test files from linting.
The phpcs configuration applies WordPress coding standards globally without excluding the tests/ directory. WordPress standards require lowercase with hyphens (e.g., class-signup-field-email-test.php), which will cause CI failures for all test files in this PR that use PascalCase naming. Either rename all test files to follow the convention or add an exclude pattern for tests/ in .phpcs.xml.dist:
<exclude-pattern>/tests/</exclude-pattern>🧰 Tools
🪛 GitHub Actions: Code Quality
[error] 1-1: Filenames should be all lowercase with hyphens as word separators. Expected signup-field-email-test.php, but found Signup_Field_Email_Test.php.
🪛 GitHub Check: Code Quality Checks
[failure] 1-1:
Class file names should be based on the class name with "class-" prepended. Expected class-signup-field-email-test.php, but found Signup_Field_Email_Test.php.
[failure] 1-1:
Filenames should be all lowercase with hyphens as word separators. Expected signup-field-email-test.php, but found Signup_Field_Email_Test.php.
🤖 Prompt for AI Agents
In `@tests/WP_Ultimo/Checkout/Signup_Fields/Signup_Field_Email_Test.php` at line
1, The test filename
tests/WP_Ultimo/Checkout/Signup_Fields/Signup_Field_Email_Test.php violates
WordPress PHPCS naming (PascalCase); either rename the test file and its class
to lowercase with hyphens (e.g., class-signup-field-email-test.php and matching
class name if necessary) or update the PHPCS config to exclude the tests
directory by adding an exclude-pattern for /tests/ to .phpcs.xml.dist; pick one
approach and apply consistently to other PascalCase test files (referencing
Signup_Field_Email_Test.php and any similarly named test classes).
| public function test_multiple_memberships_enabled_returns_bool(): void { | ||
| $enabled = wu_multiple_memberships_enabled(); | ||
|
|
||
| $this->assertIsBool($enabled); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, let's find the implementation of wu_multiple_memberships_enabled
fd -t f "\.php$" | xargs grep -l "function wu_multiple_memberships_enabled"Repository: Ultimate-Multisite/ultimate-multisite
Length of output: 107
🏁 Script executed:
#!/bin/bash
# Let's also search for wu_get_setting to understand its behavior
fd -t f "\.php$" | xargs grep -l "function wu_get_setting"Repository: Ultimate-Multisite/ultimate-multisite
Length of output: 133
🏁 Script executed:
#!/bin/bash
# Read the checkout functions file to find wu_multiple_memberships_enabled
cat -n inc/functions/checkout.php | grep -A 5 "function wu_multiple_memberships_enabled"Repository: Ultimate-Multisite/ultimate-multisite
Length of output: 236
🏁 Script executed:
#!/bin/bash
# Read the settings functions file to find wu_get_setting
cat -n inc/functions/settings.php | grep -A 10 "function wu_get_setting"Repository: Ultimate-Multisite/ultimate-multisite
Length of output: 410
🏁 Script executed:
#!/bin/bash
# Find the Settings class and its get_setting method
fd -t f "\.php$" | xargs grep -l "class.*Settings" | head -5Repository: Ultimate-Multisite/ultimate-multisite
Length of output: 276
🏁 Script executed:
#!/bin/bash
# Search for the get_setting method definition
fd -t f "\.php$" | xargs grep -B 2 "function get_setting" | head -30Repository: Ultimate-Multisite/ultimate-multisite
Length of output: 1749
🏁 Script executed:
#!/bin/bash
# Read the get_setting method in the Settings class
sed -n '/public function get_setting/,/^[[:space:]]*}/p' inc/class-settings.php | head -30Repository: Ultimate-Multisite/ultimate-multisite
Length of output: 420
🏁 Script executed:
#!/bin/bash
# Get more lines from the get_setting method to see the complete return statement
sed -n '/public function get_setting/,/^[[:space:]]*}/p' inc/class-settings.php | head -50Repository: Ultimate-Multisite/ultimate-multisite
Length of output: 420
🏁 Script executed:
#!/bin/bash
# Get line number where get_setting is defined and read more lines
grep -n "public function get_setting" inc/class-settings.php | head -1Repository: Ultimate-Multisite/ultimate-multisite
Length of output: 149
🏁 Script executed:
#!/bin/bash
# Read a larger section to see the complete implementation
cat -n inc/class-settings.php | grep -A 25 "public function get_setting"Repository: Ultimate-Multisite/ultimate-multisite
Length of output: 1102
wu_multiple_memberships_enabled() may not return a strict boolean.
The function returns wu_get_setting('enable_multiple_memberships', true), which retrieves a raw setting value from the database without any type casting. Settings are typically stored as strings or integers in WordPress (e.g., 'yes', '1'), and the value passes through a filter that can transform it further. The assertIsBool() assertion may fail if the setting is stored as a truthy non-boolean value.
🤖 Prompt for AI Agents
In `@tests/WP_Ultimo/Functions/Checkout_Functions_Test.php` around lines 126 -
130, The test fails because wu_multiple_memberships_enabled() currently returns
the raw setting value (which may be a string/int), so update that function to
always return a strict boolean: fetch the setting via
wu_get_setting('enable_multiple_memberships', true) and convert it to a bool
(preferably via wp_validate_boolean(...) for correct handling of
'1'/'true'/'yes' strings) before returning or passing through filters; ensure
the function signature and any filters applied still receive/return a boolean so
assertIsBool() passes.
| /** | ||
| * Test valid country code UK. | ||
| */ | ||
| public function test_valid_country_gb(): void { | ||
| $this->assertTrue($this->rule->check('GB')); | ||
| } |
There was a problem hiding this comment.
Docblock says "UK" but the test validates "GB".
The ISO 3166-1 alpha-2 code for the United Kingdom is GB, which the test method name and assertion correctly use. The docblock should say "GB" (or "United Kingdom") rather than "UK" to avoid confusion — especially since UK is not a valid ISO code and could mislead someone into adding a check('UK') assertion expecting true.
📝 Proposed fix
/**
- * Test valid country code UK.
+ * Test valid country code GB (United Kingdom).
*/📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /** | |
| * Test valid country code UK. | |
| */ | |
| public function test_valid_country_gb(): void { | |
| $this->assertTrue($this->rule->check('GB')); | |
| } | |
| /** | |
| * Test valid country code GB (United Kingdom). | |
| */ | |
| public function test_valid_country_gb(): void { | |
| $this->assertTrue($this->rule->check('GB')); | |
| } |
🤖 Prompt for AI Agents
In `@tests/WP_Ultimo/Helpers/Validation_Rules/Country_Test.php` around lines 44 -
49, Update the docblock above the test_valid_country_gb method in
Country_Test.php to reference the correct ISO country code "GB" (or say "United
Kingdom") instead of "UK"; locate the test method named test_valid_country_gb
and the assertion $this->rule->check('GB') and change the comment text so it no
longer misleadingly mentions "UK".
| * Plugin URI: https://ultimatemultisite.com | ||
| * Description: Ultimate Multisite is a WordPress Multisite plugin that turns your network into a complete Website-as-a-Service (WaaS) platform with subscriptions, site provisioning, domain mapping, and customer management. Formerly WP Ultimo. | ||
| * Version: 2.4.11-beta.4 | ||
| * Version: 2.4.11-beta.3 |
There was a problem hiding this comment.
Stale @version tag in the docblock.
Line 32 still reads @version 2.4.11-beta.1 while the plugin header on Line 6 is 2.4.11-beta.3. Consider keeping these in sync to avoid confusion.
Proposed fix
- * `@version` 2.4.11-beta.1
+ * `@version` 2.4.11-beta.3Also applies to: 32-32
🤖 Prompt for AI Agents
In `@ultimate-multisite.php` at line 6, The docblock `@version` tag is out of sync
with the plugin header Version: value; update the `@version` annotation from
"2.4.11-beta.1" to "2.4.11-beta.3" so the docblock and the plugin header match
(look for the plugin header "Version:" and the docblock "@version" string in
ultimate-multisite.php and make them identical).
Summary
Test plan
vendor/bin/phpunitto verify all new tests pass🤖 Generated with Claude Code
Summary by CodeRabbit
Chores
Bug Fixes
Tests