You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CLAUDE.md
+32-4Lines changed: 32 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -136,13 +136,13 @@ faqLevel: false # no collection — questions stay in place as inline spoilers
136
136
137
137
## API Signatures (`<signature>`)
138
138
139
-
For documenting methodsand functions in API reference pages. Renders a highlighted PHP signature box with description, parameters, and examples.
139
+
For documenting methods, functions, and PHP attributes in API reference pages. Renders a highlighted PHP signature box with description, parameters, and examples.
<short>Declares a retry policy for a test on failure.</short>
164
+
</signature>
165
+
```
166
+
167
+
Attribute signatures are detected by the `#[` prefix in `name`. The `#[...]` wrapper is preserved in the rendered signature box. Headings display as `#[ShortName]` (e.g., `#[Retry]`). The inner FQN (without `#[...]`) is used for registry lookup and `<attr>` cross-references.
168
+
160
169
**Attributes:**
161
-
- `name` (required) — full method signaturewith types and return type. Supports FQN (`\Testo\Assert::method`) — namespace is stripped for display, only short class name shown.
162
-
- `h` — heading level for auto-generated heading (`"3"` → `<h3>Assert::same</h3>`). Default: `"0"` (bold text, no heading). Heading text is extracted automatically: `Class::method` from the signature.
170
+
-`name` (required) — full signature. For functions: FQN with types and return type(`\Testo\Assert::method`). For attributes: `#[\Namespace\AttrName(params)]`. Namespace is stripped for display.
171
+
-`h` — heading level for auto-generated heading (`"3"` → `<h3>Assert::same</h3>` or `<h2>#[Retry]</h2>`). Default: `"0"` (bold text, no heading).
163
172
-`compact` — compact rendering mode: signature + short + description inline, no card/sections. Good for simple methods in lists.
164
173
165
174
**Inner tags (all optional):**
@@ -195,6 +204,25 @@ Renders as `Assert::blank()` with syntax highlighting. On hover, shows a tooltip
195
204
196
205
**Registry:** All `<signature>` blocks with FQN names (starting with `\`) are collected at build startup. The `<func>` tag content is matched by stripping arguments: `\Testo\Assert::blank()` matches `\Testo\Assert::blank(mixed $actual, string $message = ''): void`.
197
206
207
+
## Attribute References (`<attr>`)
208
+
209
+
For cross-referencing PHP attributes inline within text. Renders as `#[ShortName]` with Shiki highlighting and a hover tooltip showing the full signature and description.
210
+
211
+
**Plugin:**`.vitepress/func-block.ts` — markdown-it inline + block rules. **Registry:**`.vitepress/func-registry.ts` — separate attribute registry (parallel to function registry).
212
+
213
+
**Syntax:**
214
+
```html
215
+
<attr>\Testo\Retry</attr>
216
+
```
217
+
218
+
Takes the plain FQN (without `#[...]`) and renders as `#[Retry]` with syntax highlighting. On hover, shows a tooltip with the full attribute signature and `<short>` description from the corresponding `<signature>` block.
219
+
220
+
**Behavior:**
221
+
- Same linking/tooltip rules as `<func>`: link if `h > 0`, tooltip-only otherwise, plain `<code>` if not found
222
+
- The `#[...]` wrapping is added automatically — always pass plain FQN in the tag
223
+
- Locale-aware: EN pages reference EN signatures, RU pages reference RU signatures
224
+
- Uses a separate registry from `<func>` to avoid FQN collisions
225
+
198
226
## Class References (`<class>`)
199
227
200
228
For referencing PHP classes inline. Renders the short class name (without namespace) with a hover tooltip showing the full FQN.
The plugin provides the <attr>\Testo\Retry</attr> attribute and an interceptor that retry a failed test a specified number of times. If the test passes on retry, it's marked as flaky. The attribute can be placed on a method, function, or an entire class — in the latter case, the policy applies to all tests in the class.
<short>Declares a retry policy for a test on failure.</short>
13
+
<description>
14
+
Works with any test type: regular tests, inline tests, benchmarks. When placed on a class (Test Case), applies to all tests within it.
15
+
</description>
16
+
<paramname="$maxAttempts">Maximum number of attempts, including the first run. For example, `3` means up to two retries after the initial failure.</param>
17
+
<paramname="$markFlaky">Whether to mark the test as flaky if it only passed on retry. Defaults to `true`.</param>
On a class — all tests inside inherit the retry policy:
32
+
33
+
```php
34
+
#[Retry(maxAttempts: 5, markFlaky: false)]
35
+
final class ExternalApiTest
36
+
{
37
+
public function checkHealth(): void { /* ... */ }
38
+
39
+
public function checkStatus(): void { /* ... */ }
40
+
}
41
+
```
42
+
</example>
43
+
</signature>
44
+
45
+
## Suite-Level Policy
46
+
47
+
The attribute sets a retry policy for a specific test or class. To apply retries to an entire Test Suite, use the <class>\Testo\Retry\Interceptor\RetryPolicyRunInterceptor</class> directly — add it to the pipeline via a plugin:
48
+
49
+
```php
50
+
return new ApplicationConfig(
51
+
suites: [
52
+
new SuiteConfig(
53
+
name: 'Integration',
54
+
location: ['tests/Integration'],
55
+
plugins: [
56
+
// ...
57
+
new class implements PluginConfigurator {
58
+
#[\Override]
59
+
public function configure(Container $container): void
This way all tests in the Integration Test Suite will be retried up to 3 times on failure, without placing the attribute on each test individually.
73
+
74
+
::: question What happens if a retry policy is defined at multiple levels?
75
+
When multiple retry policies are defined, only the closest one to the test applies. For example, if the Test Suite has `maxAttempts: 3`, the class has `2`, and the method has `5`, the test will retry **up to 5 times**. Policies do not stack.
Плагин предоставляет атрибут <attr>\Testo\Retry</attr> и интерцептор, которые перезапускают упавший тест указанное количество раз. Если тест проходит при повторной попытке, он помечается как нестабильный (flaky). Атрибут можно повесить на метод, функцию или целый класс — в последнем случае политика применяется ко всем тестам в классе.
<short>Объявляет политику повторного запуска теста при падении.</short>
9
+
<description>
10
+
Можно использовать на любом типе тестов: обычных, встроенных, бенчмарках. При размещении на классе (Test Case) применяется ко всем тестам внутри.
11
+
</description>
12
+
<paramname="$maxAttempts">Максимальное количество попыток, включая первый запуск. Например, `3` означает не более двух повторных попыток после первого падения.</param>
13
+
<paramname="$markFlaky">Помечать ли тест как нестабильный (flaky), если он прошёл только при повторной попытке. По умолчанию `true`.</param>
На классе — все тесты внутри получат политику повторного запуска:
28
+
29
+
```php
30
+
#[Retry(maxAttempts: 5, markFlaky: false)]
31
+
final class ExternalApiTest
32
+
{
33
+
public function checkHealth(): void { /* ... */ }
34
+
35
+
public function checkStatus(): void { /* ... */ }
36
+
}
37
+
```
38
+
</example>
39
+
</signature>
40
+
41
+
## Политика повторов на уровне Test Suite
42
+
43
+
Атрибут задаёт политику для конкретного теста или класса. Если нужно применить повторный запуск ко всему Test Suite, используйте интерцептор <class>\Testo\Retry\Interceptor\RetryPolicyRunInterceptor</class> напрямую — добавьте его в пайплайн через плагин:
44
+
45
+
```php
46
+
return new ApplicationConfig(
47
+
suites: [
48
+
new SuiteConfig(
49
+
name: 'Integration',
50
+
location: ['tests/Integration'],
51
+
plugins: [
52
+
// ...
53
+
new class implements PluginConfigurator {
54
+
#[\Override]
55
+
public function configure(Container $container): void
В этом случае все тесты в Test Suite - Integration будут перезапускаться до 3 раз при падении, без необходимости расставлять атрибуты на каждом тесте.
69
+
70
+
::: question Что будет, если задать политику повторов на нескольких уровнях?
71
+
При множественном определении политики повторов применяется только ближайшая к тесту. Например, если на Test Suite задано `maxAttempts: 3`, на классе — `2`, а на методе — `5`, тест будет повторяться **до 5 раз**. Политики не накапливаются.
0 commit comments