@ai-kits/wp-ag-kit 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/README.md +12 -14
  2. package/STRUCTURE.md +9 -7
  3. package/agents/woocommerce-expert.md +32 -0
  4. package/agents/wordpress-expert.md +4 -2
  5. package/package.json +5 -3
  6. package/skills/woocommerce/SKILL.md +54 -0
  7. package/skills/woocommerce/references/backend-dev-guide.md +44 -0
  8. package/skills/woocommerce/references/code-entities.md +186 -0
  9. package/skills/woocommerce/references/code-quality.md +273 -0
  10. package/skills/woocommerce/references/code-review-guide.md +71 -0
  11. package/skills/woocommerce/references/coding-conventions.md +182 -0
  12. package/skills/woocommerce/references/copy-guidelines-guide.md +17 -0
  13. package/skills/woocommerce/references/data-integrity.md +164 -0
  14. package/skills/woocommerce/references/dependency-injection.md +102 -0
  15. package/skills/woocommerce/references/dev-cycle-guide.md +32 -0
  16. package/skills/woocommerce/references/file-entities.md +73 -0
  17. package/skills/woocommerce/references/hooks.md +87 -0
  18. package/skills/woocommerce/references/js-i18n-patterns.md +298 -0
  19. package/skills/woocommerce/references/markdown-guide.md +358 -0
  20. package/skills/woocommerce/references/markdown-linting.md +202 -0
  21. package/skills/woocommerce/references/php-i18n-patterns.md +83 -0
  22. package/skills/woocommerce/references/php-linting-patterns.md +304 -0
  23. package/skills/woocommerce/references/running-tests.md +249 -0
  24. package/skills/woocommerce/references/security-patterns.md +109 -0
  25. package/skills/woocommerce/references/sentence-case.md +177 -0
  26. package/skills/woocommerce/references/type-annotations.md +161 -0
  27. package/skills/woocommerce/references/unit-tests.md +362 -0
  28. package/skills/woocommerce/references/woocommerce-global-objects.md +89 -0
@@ -0,0 +1,177 @@
1
+ # Sentence Case for UI Text
2
+
3
+ ## Table of Contents
4
+
5
+ - [Rule: Always Use Sentence Case](#rule-always-use-sentence-case)
6
+ - [Examples](#examples)
7
+ - [Exceptions](#exceptions)
8
+ - [Common UI Elements](#common-ui-elements)
9
+ - [Why Sentence Case?](#why-sentence-case)
10
+ - [Quick Reference](#quick-reference)
11
+ - [When in Doubt](#when-in-doubt)
12
+
13
+ ## Rule: Always Use Sentence Case
14
+
15
+ **Always use sentence case for UI copy, not title case.**
16
+
17
+ Sentence case means only the first word and proper nouns are capitalized.
18
+
19
+ ## Examples
20
+
21
+ ### Correct - Sentence Case
22
+
23
+ - "Payment provider options"
24
+ - "Complete setup"
25
+ - "Add new gateway"
26
+ - "Configure payment settings"
27
+ - "Save changes"
28
+ - "View documentation"
29
+ - "Enable test mode"
30
+
31
+ ### Incorrect - Title Case
32
+
33
+ - "Payment Provider Options"
34
+ - "Complete Setup"
35
+ - "Add New Gateway"
36
+ - "Configure Payment Settings"
37
+ - "Save Changes"
38
+ - "View Documentation"
39
+ - "Enable Test Mode"
40
+
41
+ ## Exceptions
42
+
43
+ Sentence case has specific exceptions where capitalization is required:
44
+
45
+ ### 1. Proper Nouns
46
+
47
+ Always capitalize proper nouns (names of specific products, services, or brands):
48
+
49
+ **Correct:**
50
+
51
+ - "Connect with WooPayments"
52
+ - "Import from WordPress"
53
+ - "Sync with Stripe"
54
+ - "Enable Google Analytics"
55
+
56
+ ### 2. Acronyms
57
+
58
+ Always capitalize acronyms:
59
+
60
+ **Correct:**
61
+
62
+ - "Configure API settings"
63
+ - "Enter URL"
64
+ - "Set up SSL certificate"
65
+ - "Generate CSV export"
66
+
67
+ ### 3. Brand Names
68
+
69
+ Always use the official capitalization for brand names:
70
+
71
+ **Correct:**
72
+
73
+ - "PayPal"
74
+ - "WooCommerce"
75
+ - "WordPress"
76
+ - "Stripe"
77
+
78
+ ## Common UI Elements
79
+
80
+ ### Buttons
81
+
82
+ ```text
83
+ ✅ Correct:
84
+ - "Save changes"
85
+ - "Add product"
86
+ - "Continue to checkout"
87
+ - "Send test email"
88
+
89
+ ❌ Incorrect:
90
+ - "Save Changes"
91
+ - "Add Product"
92
+ - "Continue To Checkout"
93
+ - "Send Test Email"
94
+ ```
95
+
96
+ ### Labels
97
+
98
+ ```text
99
+ ✅ Correct:
100
+ - "Payment method"
101
+ - "Shipping address"
102
+ - "Order notes"
103
+ - "Tax rate"
104
+
105
+ ❌ Incorrect:
106
+ - "Payment Method"
107
+ - "Shipping Address"
108
+ - "Order Notes"
109
+ - "Tax Rate"
110
+ ```
111
+
112
+ ### Menu Items
113
+
114
+ ```text
115
+ ✅ Correct:
116
+ - "Settings"
117
+ - "Payment gateways"
118
+ - "Tax settings"
119
+ - "Shipping zones"
120
+
121
+ ❌ Incorrect:
122
+ - "Settings" (this one is actually correct - it's a single word)
123
+ - "Payment Gateways"
124
+ - "Tax Settings"
125
+ - "Shipping Zones"
126
+ ```
127
+
128
+ ### Headings
129
+
130
+ ```text
131
+ ✅ Correct:
132
+ - "Payment settings"
133
+ - "Configure your store"
134
+ - "Advanced options"
135
+
136
+ ❌ Incorrect:
137
+ - "Payment Settings"
138
+ - "Configure Your Store"
139
+ - "Advanced Options"
140
+ ```
141
+
142
+ ### Messages and Notifications
143
+
144
+ ```text
145
+ ✅ Correct:
146
+ - "Settings saved successfully"
147
+ - "Unable to connect to payment provider"
148
+ - "Please enter a valid email address"
149
+
150
+ ❌ Incorrect:
151
+ - "Settings Saved Successfully"
152
+ - "Unable To Connect To Payment Provider"
153
+ - "Please Enter A Valid Email Address"
154
+ ```
155
+
156
+ ## Why Sentence Case?
157
+
158
+ More readable, conversational, and modern. Better for accessibility and internationalization.
159
+
160
+ ## Quick Reference
161
+
162
+ | Element Type | Example |
163
+ |--------------|---------|
164
+ | Button | "Save changes" |
165
+ | Link | "View all orders" |
166
+ | Label | "Email address" |
167
+ | Heading | "Payment options" |
168
+ | Message | "Order created successfully" |
169
+ | Menu item | "Product settings" |
170
+ | Checkbox | "Enable notifications" |
171
+ | Tab | "General settings" |
172
+
173
+ ## When in Doubt
174
+
175
+ Capitalize only: first word, proper nouns, and acronyms.
176
+
177
+ Example: "Enable WooPayments API integration"
@@ -0,0 +1,161 @@
1
+ # Type Annotations for Static Analysis
2
+
3
+ ## Table of Contents
4
+
5
+ - [Overview](#overview)
6
+ - [When to Use PHPStan Annotations](#when-to-use-phpstan-annotations)
7
+ - [Generic Types with @template](#generic-types-with-template)
8
+ - [PHPStan-Specific Annotations](#phpstan-specific-annotations)
9
+ - [Common Patterns](#common-patterns)
10
+ - [Suppressing False Positives](#suppressing-false-positives)
11
+
12
+ ## Overview
13
+
14
+ WooCommerce uses PHPStan for static analysis. Beyond standard PHPDoc annotations (`@param`, `@return`, `@var`), use PHPStan-specific annotations to provide richer type information that enables better type inference.
15
+
16
+ ## When to Use PHPStan Annotations
17
+
18
+ Use PHPStan annotations when:
19
+
20
+ - A method returns a type based on its input (generic/template types)
21
+ - Standard PHPDoc cannot express the type relationship
22
+ - You need to provide type information that PHP's type system cannot express
23
+
24
+ ## Generic Types with @template
25
+
26
+ Use `@template` to declare generic type parameters. This enables PHPStan to infer return types based on input types.
27
+
28
+ ### Basic Pattern
29
+
30
+ ```php
31
+ /**
32
+ * Get an instance of a class from the container.
33
+ *
34
+ * @template T of object
35
+ * @param string $class_name Class name.
36
+ * @phpstan-param class-string<T> $class_name
37
+ *
38
+ * @return T The instance of the requested class.
39
+ */
40
+ public function get( string $class_name ) {
41
+ // ...
42
+ }
43
+ ```
44
+
45
+ **How it works:**
46
+
47
+ 1. `@template T of object` - Declares a type variable `T` constrained to objects
48
+ 2. `@phpstan-param class-string<T> $class_name` - The input is a class name string for type `T`
49
+ 3. `@return T` - The return type is the same `T` that was passed in
50
+
51
+ **Result:** PHPStan knows that `$container->get( MyService::class )` returns `MyService`.
52
+
53
+ ### Constraint Options
54
+
55
+ ```php
56
+ // Any object type
57
+ @template T of object
58
+
59
+ // Specific base class or interface
60
+ @template T of WC_Product
61
+
62
+ // No constraint (can be any type including scalars)
63
+ @template T
64
+ ```
65
+
66
+ ## PHPStan-Specific Annotations
67
+
68
+ ### @phpstan-param vs @param
69
+
70
+ Use both when you need PHPStan-specific type info while keeping standard documentation:
71
+
72
+ ```php
73
+ /**
74
+ * @param string $class_name Class name to instantiate.
75
+ * @phpstan-param class-string<T> $class_name
76
+ */
77
+ ```
78
+
79
+ - `@param string` - Standard PHPDoc (for IDEs and documentation generators)
80
+ - `@phpstan-param class-string<T>` - PHPStan-specific (richer type info)
81
+
82
+ ### @phpstan-return
83
+
84
+ Use when the return type is more specific than the declared type:
85
+
86
+ ```php
87
+ /**
88
+ * @return object
89
+ * @phpstan-return T
90
+ */
91
+ ```
92
+
93
+ ### @phpstan-var
94
+
95
+ Use for inline type assertions:
96
+
97
+ ```php
98
+ /** @phpstan-var array<string, WC_Product> $products */
99
+ $products = get_transient( 'cached_products' );
100
+ ```
101
+
102
+ ## Common Patterns
103
+
104
+ ### Factory Methods
105
+
106
+ ```php
107
+ /**
108
+ * Create a new instance of a data store.
109
+ *
110
+ * @template T of WC_Data_Store
111
+ * @param string $object_type Object type (e.g., 'product', 'order').
112
+ * @phpstan-param class-string<T> $object_type
113
+ *
114
+ * @return T The data store instance.
115
+ */
116
+ public static function load( string $object_type ) {
117
+ // ...
118
+ }
119
+ ```
120
+
121
+ ### Container/Service Locator
122
+
123
+ ```php
124
+ /**
125
+ * @template T of object
126
+ * @param string $id Service identifier.
127
+ * @phpstan-param class-string<T> $id
128
+ *
129
+ * @return T Service instance.
130
+ */
131
+ public function get( string $id );
132
+ ```
133
+
134
+ ### Collections with Known Types
135
+
136
+ ```php
137
+ /**
138
+ * @param array<int, WC_Order_Item> $items Order items.
139
+ * @return array<string, float> Item totals keyed by item type.
140
+ */
141
+ public function calculate_totals( array $items ): array {
142
+ // ...
143
+ }
144
+ ```
145
+
146
+ ## Suppressing False Positives
147
+
148
+ When PHPStan reports an error that is a false positive (the code is correct but PHPStan cannot verify it), use inline ignores with explanations:
149
+
150
+ ```php
151
+ // @phpstan-ignore return.type (method uses reflection to return correct type at runtime)
152
+ return $this->create_instance( $class_name );
153
+ ```
154
+
155
+ Common ignore identifiers:
156
+
157
+ - `return.type` - Return type mismatch
158
+ - `argument.type` - Argument type mismatch
159
+ - `method.nonObject` - Method call on potentially non-object
160
+
161
+ **Important:** Only use ignores when the code is genuinely correct. Prefer fixing the type annotations or code when possible.
@@ -0,0 +1,362 @@
1
+ # Unit Testing Conventions
2
+
3
+ ## Table of Contents
4
+
5
+ - [Complete Test File Template](#complete-test-file-template)
6
+ - [Test File Naming and Location](#test-file-naming-and-location)
7
+ - [System Under Test Variable](#system-under-test-variable)
8
+ - [Test Method Documentation](#test-method-documentation)
9
+ - [Comments in Tests](#comments-in-tests)
10
+ - [Test Configuration](#test-configuration)
11
+ - [Example: Payment Extension Suggestions Tests](#example-payment-extension-suggestions-tests)
12
+ - [Mocking the WooCommerce Logger](#mocking-the-woocommerce-logger)
13
+ - [General Testing Best Practices](#general-testing-best-practices)
14
+
15
+ ## Complete Test File Template
16
+
17
+ Use this template when creating new test files. It shows all conventions applied together:
18
+
19
+ ```php
20
+ <?php
21
+ declare( strict_types = 1 );
22
+
23
+ namespace Automattic\WooCommerce\Tests\Internal\Admin;
24
+
25
+ use Automattic\WooCommerce\Internal\Admin\OrderProcessor;
26
+ use WC_Unit_Test_Case;
27
+
28
+ /**
29
+ * Tests for the OrderProcessor class.
30
+ */
31
+ class OrderProcessorTest extends WC_Unit_Test_Case {
32
+
33
+ /**
34
+ * The System Under Test.
35
+ *
36
+ * @var OrderProcessor
37
+ */
38
+ private $sut;
39
+
40
+ /**
41
+ * Set up test fixtures.
42
+ */
43
+ public function setUp(): void {
44
+ parent::setUp();
45
+ $this->sut = new OrderProcessor();
46
+ }
47
+
48
+ /**
49
+ * Tear down test fixtures.
50
+ */
51
+ public function tearDown(): void {
52
+ parent::tearDown();
53
+ }
54
+
55
+ /**
56
+ * @testdox Should return true when order is valid.
57
+ */
58
+ public function test_returns_true_for_valid_order(): void {
59
+ $order = wc_create_order();
60
+
61
+ $result = $this->sut->is_valid( $order );
62
+
63
+ $this->assertTrue( $result, 'Valid orders should return true' );
64
+ }
65
+
66
+ /**
67
+ * @testdox Should throw exception when order ID is negative.
68
+ */
69
+ public function test_throws_exception_for_negative_order_id(): void {
70
+ $this->expectException( \InvalidArgumentException::class );
71
+
72
+ $this->sut->process( -1 );
73
+ }
74
+ }
75
+ ```
76
+
77
+ ### Key Elements
78
+
79
+ | Element | Requirement |
80
+ | ------- | ----------- |
81
+ | `declare( strict_types = 1 )` | Required at file start |
82
+ | Namespace | Match source location: `Automattic\WooCommerce\Tests\{path}` |
83
+ | Base class | Extend `WC_Unit_Test_Case` |
84
+ | SUT variable | Use `$sut` with docblock "The System Under Test." |
85
+ | Test docblock | Use `@testdox` with sentence ending in `.` |
86
+ | Return type | Use `void` for test methods |
87
+ | Assertion messages | Include helpful context for failures |
88
+
89
+ ## Test File Naming and Location
90
+
91
+ | Source | Test | Pattern |
92
+ | -------------------- | ---------------------------------------------------- | ------------------------ |
93
+ | `includes/` classes | `tests/php/includes/{path}/class-wc-{name}-test.php` | Add `-test` suffix |
94
+ | `src/` classes | `tests/php/src/{path}/{name}Test.php` | Append `Test` (no hyphen)|
95
+
96
+ Test class: Same name as source class + `_Test` or `Test` suffix, extends `WC_Unit_Test_Case`
97
+
98
+ ## System Under Test Variable
99
+
100
+ Use `$sut` with docblock "The System Under Test."
101
+
102
+ ```php
103
+ /**
104
+ * The System Under Test.
105
+ *
106
+ * @var OrderProcessor
107
+ */
108
+ private $sut;
109
+ ```
110
+
111
+ ## Test Method Documentation
112
+
113
+ When adding or modifying a unit test method, the part of the docblock that describes the test must be prepended with `@testdox`. End the comment with `.` for compliance with linting rules.
114
+
115
+ **Example:**
116
+
117
+ ```php
118
+ /**
119
+ * @testdox Should return true when order is valid.
120
+ */
121
+ public function test_returns_true_for_valid_order() {
122
+ // ...
123
+ }
124
+
125
+ /**
126
+ * @testdox Should throw exception when order ID is negative.
127
+ */
128
+ public function test_throws_exception_for_negative_order_id() {
129
+ // ...
130
+ }
131
+ ```
132
+
133
+ ## Comments in Tests
134
+
135
+ **Avoid over-commenting tests.** Test names and assertion messages should explain intent.
136
+
137
+ **Good - Self-explanatory:**
138
+
139
+ ```php
140
+ /**
141
+ * @testdox Should return true when order status is draft.
142
+ */
143
+ public function test_returns_true_for_draft_orders() {
144
+ $order = $this->create_draft_order();
145
+
146
+ $result = $this->sut->can_delete( $order );
147
+
148
+ $this->assertTrue( $result, 'Draft orders should be deletable' );
149
+ }
150
+ ```
151
+
152
+ **Avoid - Over-commented:**
153
+
154
+ ```php
155
+ /**
156
+ * @testdox Should return true when order status is draft.
157
+ */
158
+ public function test_returns_true_for_draft_orders() {
159
+ // Create a draft order
160
+ $order = $this->create_draft_order();
161
+
162
+ // Call the method we're testing
163
+ $result = $this->sut->can_delete( $order );
164
+
165
+ // Verify the result is true
166
+ $this->assertTrue( $result, 'Draft orders should be deletable' );
167
+ }
168
+ ```
169
+
170
+ **Avoid - Arrange/Act/Assert comments:**
171
+
172
+ ```php
173
+ // Don't add these structural comments
174
+ // Arrange
175
+ $order = $this->create_draft_order();
176
+
177
+ // Act
178
+ $result = $this->sut->can_delete( $order );
179
+
180
+ // Assert
181
+ $this->assertTrue( $result );
182
+ ```
183
+
184
+ Use blank lines for visual separation instead. The test structure should be self-evident.
185
+
186
+ **When comments ARE useful in tests:**
187
+
188
+ - Explaining complex test setup: `// Simulate race condition by...`
189
+ - Documenting known issues: `// Workaround for WordPress core bug #12345`
190
+ - Clarifying business rules: `// Payment processor requires 24h hold`
191
+
192
+ ## Test Configuration
193
+
194
+ Test configuration file: `phpunit.xml`
195
+
196
+ ## Example: Payment Extension Suggestions Tests
197
+
198
+ The `PaymentsExtensionSuggestionsTest` class demonstrates good testing practices for country-specific functionality.
199
+
200
+ ### Key Patterns Used
201
+
202
+ 1. **Data-driven tests** using PHPUnit data providers
203
+ 2. **Extension count verification** for different merchant types
204
+ 3. **Clear test organization** by merchant type (online/offline)
205
+
206
+ ### Example Test Structure
207
+
208
+ ```php
209
+ class PaymentsExtensionSuggestionsTest extends WC_Unit_Test_Case {
210
+ /**
211
+ * The System Under Test.
212
+ *
213
+ * @var PaymentsExtensionSuggestions
214
+ */
215
+ private $sut;
216
+
217
+ public function setUp(): void {
218
+ parent::setUp();
219
+ $this->sut = new PaymentsExtensionSuggestions();
220
+ }
221
+
222
+ /**
223
+ * @testdox Should return correct extension count for online merchants by country
224
+ * @dataProvider online_merchant_country_data
225
+ */
226
+ public function test_get_country_extensions_count_for_online_merchants(
227
+ string $country_code,
228
+ int $expected_count
229
+ ) {
230
+ $merchant = array(
231
+ 'country' => $country_code,
232
+ 'selling_venues' => 'online',
233
+ );
234
+
235
+ $result = $this->sut->get_country_extensions_count( $merchant );
236
+
237
+ $this->assertSame(
238
+ $expected_count,
239
+ $result,
240
+ "Expected {$expected_count} extensions for online merchant in {$country_code}"
241
+ );
242
+ }
243
+
244
+ /**
245
+ * Data provider for online merchant tests.
246
+ *
247
+ * @return array
248
+ */
249
+ public function online_merchant_country_data() {
250
+ return array(
251
+ 'United States' => array( 'US', 5 ),
252
+ 'United Kingdom' => array( 'GB', 4 ),
253
+ 'Canada' => array( 'CA', 3 ),
254
+ 'Australia' => array( 'AU', 3 ),
255
+ // ... more countries
256
+ );
257
+ }
258
+
259
+ /**
260
+ * @testdox Should return correct extension count for offline merchants by country
261
+ * @dataProvider offline_merchant_country_data
262
+ */
263
+ public function test_get_country_extensions_count_for_offline_merchants(
264
+ string $country_code,
265
+ int $expected_count
266
+ ) {
267
+ $merchant = array(
268
+ 'country' => $country_code,
269
+ 'selling_venues' => 'offline',
270
+ );
271
+
272
+ $result = $this->sut->get_country_extensions_count( $merchant );
273
+
274
+ $this->assertSame(
275
+ $expected_count,
276
+ $result,
277
+ "Expected {$expected_count} extensions for offline merchant in {$country_code}"
278
+ );
279
+ }
280
+
281
+ /**
282
+ * Data provider for offline merchant tests.
283
+ *
284
+ * @return array
285
+ */
286
+ public function offline_merchant_country_data() {
287
+ return array(
288
+ 'United States' => array( 'US', 2 ),
289
+ 'United Kingdom' => array( 'GB', 1 ),
290
+ 'Canada' => array( 'CA', 1 ),
291
+ // ... more countries
292
+ );
293
+ }
294
+ }
295
+ ```
296
+
297
+ ### Important Notes for Payment Extension Tests
298
+
299
+ When working with payment extension suggestions:
300
+
301
+ 1. **Extension counts must match the implementation** in `src/Internal/Admin/Suggestions/PaymentsExtensionSuggestions.php`
302
+ 2. **When adding new countries** to the implementation, update both data providers in the test file
303
+ 3. **Tests are separated by merchant type** (online vs offline) as they have different extension counts
304
+ 4. **Data providers use descriptive keys** (country names) for better test output
305
+
306
+ ## Mocking the WooCommerce Logger
307
+
308
+ When testing code that uses `wc_get_logger()` (directly or via `SafeGlobalFunctionProxy::wc_get_logger()`), use the `woocommerce_logging_class` filter to inject a fake logger.
309
+
310
+ ### Why the Filter Approach?
311
+
312
+ - `register_legacy_proxy_function_mocks` doesn't intercept `SafeGlobalFunctionProxy` calls
313
+ - Passing an object (not a class name string) bypasses `wc_get_logger()`'s internal cache
314
+
315
+ ### Creating a Fake Logger
316
+
317
+ The fake logger must implement `WC_Logger_Interface`. Create an anonymous class with public arrays to track calls (`$debug_calls`, `$warning_calls`, etc.) and implement all interface methods (`add`, `log`, `debug`, `info`, `warning`, `error`, `emergency`, `alert`, `critical`, `notice`).
318
+
319
+ ### Using the Fake Logger
320
+
321
+ ```php
322
+ public function test_logs_warning_for_invalid_input(): void {
323
+ $fake_logger = $this->create_fake_logger();
324
+
325
+ // Inject via filter - passing object bypasses cache.
326
+ add_filter(
327
+ 'woocommerce_logging_class',
328
+ function () use ( $fake_logger ) {
329
+ return $fake_logger;
330
+ }
331
+ );
332
+
333
+ $this->sut->process_input( 'invalid-value' );
334
+
335
+ $this->assertCount( 1, $fake_logger->warning_calls );
336
+
337
+ remove_all_filters( 'woocommerce_logging_class' ); // Always clean up.
338
+ }
339
+ ```
340
+
341
+ ### Key Points
342
+
343
+ | Aspect | Detail |
344
+ | ------------ | ----------------------------------------------- |
345
+ | Filter name | `woocommerce_logging_class` |
346
+ | Return value | Object instance (not class name string) |
347
+ | Interface | Must implement `WC_Logger_Interface` |
348
+ | Cleanup | Always call `remove_all_filters()` after test |
349
+
350
+ ### Reference
351
+
352
+ See `PaymentGatewayTest.php:create_fake_logger()` for a complete implementation.
353
+
354
+ ## General Testing Best Practices
355
+
356
+ 1. **Always run tests after making changes** to verify functionality
357
+ 2. **Use specific test filters** during development (see running-tests.md in the woocommerce-dev-cycle skill)
358
+ 3. **Write descriptive test names** that explain what is being tested
359
+ 4. **Use data providers** for testing multiple scenarios with the same logic
360
+ 5. **Include helpful assertion messages** for debugging when tests fail
361
+ 6. **Test both success and failure cases**
362
+ 7. **Mock external dependencies** (database, API calls, etc.)