Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## [0.10.43](https://github.com/php-testo/testo/compare/0.10.42...0.10.43) (2026-08-18)


### Documentation

* **skills:** drop cross-framework comparisons from non-migration skills ([e976692](https://github.com/php-testo/testo/commit/e9766922e9de526b8bb153b92dc83f9b041d32c5))

## [0.10.42](https://github.com/php-testo/testo/compare/0.10.41...0.10.42) (2026-08-18)


Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
[![Documentation](https://img.shields.io/badge/Documentation-blue?style=for-the-badge&logo=gitbook&logoColor=white)](https://php-testo.github.io)
[![Support on Boosty](https://img.shields.io/static/v1?style=for-the-badge&label=&message=Sponsorship&logo=Boosty&logoColor=white&color=%23F15F2C)](https://boosty.to/roxblnfk)

[![Vibe Index](https://img.shields.io/static/v1?label=Vibe+Index&message=3.3&color=22b0b0&style=flat&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2ZmZiI%2BPHBhdGggZD0iTTkgNCBROSAxMyAxOCAxMyBROSAxMyA5IDIyIFE5IDEzIDAgMTMgUTkgMTMgOSA0IFoiLz48cGF0aCBkPSJNMTkgMSBRMTkgNiAyNCA2IFExOSA2IDE5IDExIFExOSA2IDE0IDYgUTE5IDYgMTkgMSBaIi8%2BPHBhdGggZD0iTTIwIDE0IFEyMCAxOCAyNCAxOCBRMjAgMTggMjAgMjIgUTIwIDE4IDE2IDE4IFEyMCAxOCAyMCAxNCBaIi8%2BPC9zdmc%2B)](https://github.com/roxblnfk/action-vibe-index)
[![Vibe Index](https://img.shields.io/static/v1?label=Vibe+Index&message=3.4&color=23afb3&style=flat&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2ZmZiI%2BPHBhdGggZD0iTTkgNCBROSAxMyAxOCAxMyBROSAxMyA5IDIyIFE5IDEzIDAgMTMgUTkgMTMgOSA0IFoiLz48cGF0aCBkPSJNMTkgMSBRMTkgNiAyNCA2IFExOSA2IDE5IDExIFExOSA2IDE0IDYgUTE5IDYgMTkgMSBaIi8%2BPHBhdGggZD0iTTIwIDE0IFEyMCAxOCAyNCAxOCBRMjAgMTggMjAgMjIgUTIwIDE4IDE2IDE4IFEyMCAxOCAyMCAxNCBaIi8%2BPC9zdmc%2B)](https://github.com/roxblnfk/action-vibe-index)
[![Psalm Level](https://shepherd.dev/github/php-testo/testo/level.svg)](https://shepherd.dev/github/php-testo/testo)
[![Type Coverage](https://shepherd.dev/github/php-testo/testo/coverage.svg)](https://shepherd.dev/github/php-testo/testo)
[![codecov](https://codecov.io/gh/php-testo/testo/branch/1.x/graph/badge.svg)](https://codecov.io/gh/php-testo/testo)
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"psr/log": "^2.0 || ^3.0",
"symfony/console": "^6.4 || ^7 || ^8.0",
"symfony/finder": "^6.4 || ^7 || ^8.0",
"testo/assert": "^0.1.13",
"testo/assert": "^0.1.14",
"testo/fiber": "^0.1.2",
"testo/bench": "^0.1.8",
"testo/bridge-symfony-console": "^0.1.9",
Expand Down
7 changes: 7 additions & 0 deletions plugin/assert/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## [0.1.14](https://github.com/php-testo/testo/compare/assert-0.1.13...assert-0.1.14) (2026-08-18)


### Documentation

* **assert:** drop the PHPUnit reference from sameElementsAs and show an example ([5a000e6](https://github.com/php-testo/testo/commit/5a000e6c8e8aa7fe1e64fda49b15199acf53bde0))

## [0.1.13](https://github.com/php-testo/testo/compare/assert-0.1.12...assert-0.1.13) (2026-08-18)


Expand Down
2 changes: 1 addition & 1 deletion plugin/assert/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
],
"require": {
"php": ">=8.2",
"testo/testo": "0.10.42 - 1"
"testo/testo": "0.10.43 - 1"
},
"autoload": {
"psr-4": {
Expand Down
9 changes: 7 additions & 2 deletions plugin/assert/src/Api/Builtin/ArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,13 @@ public function isList(string $message = ''): static;
/**
* Asserts that the array holds the same elements as the expected iterable, regardless of order.
*
* Both sides are canonicalized (recursively sorted, keys discarded) and then compared loosely,
* matching PHPUnit's {@see \PHPUnit\Framework\Assert::assertEqualsCanonicalizing()} semantics.
* Both sides are canonicalized (recursively sorted, keys discarded) and then compared loosely:
*
* ```php
* Assert::array([3, 1, 2])->sameElementsAs([1, 2, 3]); // passes — order ignored
* Assert::array(['a' => 1, 'b' => 2])->sameElementsAs([2, 1]); // passes — keys ignored
* Assert::array([1, 2])->sameElementsAs([1, 2, 3]); // fails — different elements
* ```
*
* @param iterable $expected The expected elements, in any order.
* @param string $message Optional message for the assertion.
Expand Down
3 changes: 1 addition & 2 deletions plugin/assert/src/Internal/Assertion/AssertArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,7 @@ public function sameElementsAs(iterable $expected, string $message = ''): static

/**
* Recursively sorts an array by value and discards keys, so two arrays holding the same
* elements in any order (and under any keys) canonicalize to an identical shape. Mirrors the
* canonicalization PHPUnit applies for `assertEqualsCanonicalizing`.
* elements in any order (and under any keys) canonicalize to an identical shape.
*/
private static function canonicalize(array $value): array
{
Expand Down
4 changes: 2 additions & 2 deletions resources/version.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
".": "0.10.42",
".": "0.10.43",
"plugin/repeat": "0.1.9",
"plugin/convention": "0.1.4",
"plugin/lifecycle": "0.1.5",
"plugin/retry": "0.1.5",
"plugin/filter": "0.1.6",
"plugin/test": "0.1.6",
"plugin/assert": "0.1.13",
"plugin/assert": "0.1.14",
"plugin/data": "0.1.8",
"plugin/inline": "0.1.8",
"plugin/bench": "0.1.8",
Expand Down
4 changes: 2 additions & 2 deletions skills/testo-flaky-tests/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function __construct(
) {}
```

- `times` is the **total** number of runs. `#[Repeat(times: 3)]` runs the test three times (mirrors Kotlin's `repeat(n)` and JUnit's `@RepeatedTest(n)`). It is **not** "additional repetitions on top of one run".
- `times` is the **total** number of runs. `#[Repeat(times: 3)]` runs the test three times. It is **not** "additional repetitions on top of one run".
- `maxFailures` defaults to `0` — any single failure fails the whole loop.
- Combining with `#[Retry]`: Repeat runs *inside* Retry — each retry attempt re-runs the full repeat cycle. Possible, but the semantics are subtle; surface it to the user before suggesting both.

Expand All @@ -91,7 +91,7 @@ Don't ship `#[Repeat(times: 50)]` long-term on a fast suite — CI cost adds up.
## Pitfalls

- **Don't disable `markFlaky`** on `#[Retry]` / `#[Repeat]` (it defaults to `true`). Setting `markFlaky: false` is **silent rot** — a flaky test that retries to green hides the underlying defect. Only flip it off when the user explicitly asks.
- **`Repeat(times: N)` is total runs, not extra runs.** `Repeat(times: 1)` runs the test once. People coming from older PHPUnit `@Repeat` semantics expect "additional" — they're wrong here.
- **`Repeat(times: N)` is total runs, not extra runs.** `Repeat(times: 1)` runs the test once, `Repeat(times: 3)` runs it three times total — `N` is the run count, not a number of *additional* runs on top of the first.
- Combining `#[Retry]` with `#[Repeat]` is allowed: Repeat runs **inside** Retry (each retry attempt re-runs the full repeat cycle). Only suggest both when the user genuinely wants that nesting.
- A test with `Expect::exception(...)` and `#[Retry]` is almost always wrong — expected exceptions are deterministic by design.
- Don't use retries to paper over network calls in unit tests — replace the dependency with a fake instead.
Expand Down
8 changes: 4 additions & 4 deletions skills/testo-write-tests/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ description: Write or modify tests in a project that uses the Testo PHP testing

# Writing tests with Testo

Testo is **not PHPUnit**. The attribute set, assertion facade, exception expectations, and lifecycle
hooks are Testo's own — do not transliterate PHPUnit idioms.
The attribute set, assertion facade, exception expectations, and lifecycle hooks are Testo's own.
Write them the Testo way described below — don't transliterate idioms from other test frameworks.

## Before you write code

Expand Down Expand Up @@ -81,7 +81,7 @@ Assert::string($s)->contains('foo')->notContains('bar');
Assert::int($n)->greaterThan(0)->lessThanOrEqual(100);
Assert::numeric($n)->between(1, 100); // int, float, or numeric string
Assert::array($a)->hasKeys('id', 'name')->isList()->hasCount(3)->contains('x')->notContains('y');
Assert::array($a)->sameElementsAs([3, 2, 1]); // order-insensitive, like assertEqualsCanonicalizing
Assert::array($a)->sameElementsAs([3, 2, 1]); // order-insensitive, keys ignored
Assert::object($o)->instanceOf(Foo::class)->hasProperty('id');
Assert::json($s)->isObject()->hasKeys(['data', 'meta'])->assertPath('$.data.id', 42);
```
Expand Down Expand Up @@ -241,7 +241,7 @@ Always pass `--json` (as above) for a compact, machine-readable report that's ch
summary plus the failed tests. Use `--log-json=build/report.json` to write it to a file while keeping
the terminal output.

Use the Testo CLI, **never** `phpunit`.
Always run tests through the Testo CLI (`vendor/bin/testo`).

## Pitfalls

Expand Down
Loading