承接 mrpunyapal/rector-pest 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

mrpunyapal/rector-pest

Composer 安装命令:

composer require --dev mrpunyapal/rector-pest

包简介

Rector upgrade rules for Pest - refactoring and best practices for Pest testing framework

README 文档

README

Latest Version on Packagist Total Downloads on Packagist CI

Rector rules for PestPHP to improve code quality and help with version upgrades.

Rector Pest now also exposes a semantic remediation layer for safe Pest-specific diagnostics. Canonical issue identifiers, semantic metadata, and diagnostic-to-fix mapping live inside this package so Rector rules can stay independent from any single analyzer while still remaining ready for future PestStan interoperability.

Available Rules

See all available Pest rules here. See the semantic architecture and interoperability contract here.

Installation

composer require --dev mrpunyapal/rector-pest

Available Rule Sets

Code Quality

Improve your Pest tests with better readability and expressiveness.

The code-quality set also fixes a small set of PestStan-aligned anti-patterns, including static Pest callbacks that actually require instance binding, invalid beforeAll()/afterAll() usage inside describe() blocks, invalid literal repeat() counts, and redundant literal type expectations when another matcher keeps the chain meaningful. Empty test closures and impossible literal/type combinations remain modeled in the semantic registry, but they are not auto-fixed when the runtime semantics would change or the intent would become ambiguous.

These semantic fixes do not require PestStan at runtime for package consumers. This repository still keeps PestStan as a development-only dependency for its own PHPStan configuration, while Rector Pest itself owns the canonical issue registry and consumes analyzer diagnostics through stable identifiers instead of direct analyzer coupling.

// rector.php
use RectorPest\Set\PestSetList;
use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/tests',
    ])
    ->withSets([
        PestSetList::PEST_CODE_QUALITY,
    ]);
Set Description
PestSetList::PEST_CODE_QUALITY Converts expect() assertions to use Pest's built-in matchers for better readability
PestSetList::PEST_CHAIN Merges multiple expect() calls into chained expectations and optimizes their order.
PestSetList::PEST_LARAVEL Laravel-specific rules (requires illuminate/support): converts Str:: equality checks to Pest string case matchers
PestSetList::PEST_MIGRATION PHPUnit → Pest migration rules (opt-in): converts assertions, data providers, and test structure
PestSetList::PEST_BROWSER Pest Browser code-quality rules (requires pestphp/pest-plugin-browser): converts expect($page->getter()) patterns to dedicated browser assertion methods

Version Upgrade Sets

Use PestLevelSetList to automatically upgrade to a specific Pest version. Sets for higher versions include sets for lower versions.

// rector.php
use RectorPest\Set\PestLevelSetList;
use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/tests',
    ])
    ->withSets([
        PestLevelSetList::UP_TO_PEST_40,
    ]);
Set Description
PestLevelSetList::UP_TO_PEST_30 Upgrade from Pest v2 to v3
PestLevelSetList::UP_TO_PEST_40 Upgrade from Pest v2/v3 to v4 (includes v3 changes)

Manual Version Configuration

Use PestSetList if you only want changes for a specific version:

// rector.php
use RectorPest\Set\PestSetList;
use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/tests',
    ])
    ->withSets([
        PestSetList::PEST_30, // Only v2→v3 changes
    ]);
Set Description
PestSetList::PEST_30 Pest v2 → v3 migration rules
PestSetList::PEST_40 Pest v3 → v4 migration rules

Chaining Expectations

The PEST_CHAIN set automatically merges multiple expect() calls into a single chained expression.

// rector.php
use RectorPest\Set\PestSetList;
use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/tests',
    ])
    ->withSets([
        PestSetList::PEST_CODE_QUALITY,
        PestSetList::PEST_CHAIN,
    ]);

Before:

expect($value1)->toBe(10);
expect($value1)->toBeInt();
expect($value2)->toBe(20);
expect($value2)->toBeString();
expect($value3)->toBe(30);

After:

expect($value1)->toBe(10)
    ->toBeInt()
    ->and($value2)->toBe(20)
    ->toBeString()
    ->and($value3)->toBe(30);

Formatting rules (requires rector/rector 2.4.1+):

  • The first matcher after expect() stays on the same line as expect()
  • The first matcher after ->and() stays on the same line as ->and()
  • Every additional matcher in a segment goes on its own indented line
  • ->not->toBeX() is treated as a single unit and stays inline

Note: On rector/rector versions older than 2.4.1, chaining still works but all method calls are printed inline on a single line.

PHPUnit to Pest Migration

The PEST_MIGRATION set helps convert PHPUnit test patterns to Pest equivalents. This is an opt-in set — review changes carefully after applying.

// rector.php
use RectorPest\Set\PestSetList;
use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/tests',
    ])
    ->withSets([
        PestSetList::PEST_MIGRATION,
    ]);

Included rules:

Rule Description
ConvertAssertToExpectRector Converts $this->assert*() calls to expect()-> chains
ConvertExpectExceptionToThrowRector Converts $this->expectException*() plus the throwing call to expect(fn() => ...)->toThrow()

Pest Browser Testing

The PEST_BROWSER set improves code quality of tests written with pestphp/pest-plugin-browser. It converts verbose expect($page->getter()) patterns into the plugin's dedicated browser assertion methods, producing clearer failure messages and more readable tests.

Requirement: The target project must have pestphp/pest-plugin-browser installed.

// rector.php
use RectorPest\Set\PestSetList;
use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/tests/Browser',
    ])
    ->withSets([
        PestSetList::PEST_BROWSER,
    ]);

Included rules:

Rule Transforms
UseBrowserValueAssertionsRector expect($page->value($sel))->toBe($v)$page->assertValue($sel, $v) and negated form → assertValueIsNot
UseBrowserAriaAndDataAttributeAssertionsRector expect($page->attribute($sel, 'aria-*'))->toBe($v)$page->assertAriaAttribute($sel, $attr, $v) and data-* form → assertDataAttribute
UseBrowserAttributeAssertionsRector expect($page->attribute($sel, $attr))->toBe/toContain/not->toContain/toBeNullassertAttribute, assertAttributeContains, assertAttributeDoesntContain, assertAttributeMissing
UseBrowserSourceAssertionsRector expect($page->content())->toContain($html)assertSourceHas and negated form → assertSourceMissing
UseBrowserScriptAssertionsRector expect($page->script($expr))->toBe/toEqual($v)$page->assertScript($expr, $v)
UseBrowserUrlAssertionsRector expect($page->url())->toBe($url)$page->assertUrlIs($url)

URL assertions scope: only assertUrlIs is covered because it is the only URL-related assertion that has a direct expect($page->getter())->toBe() equivalent. Path, scheme, host, port, query-string, and fragment assertions (assertPathIs, assertSchemeIs, assertHostIs, etc.) have no expect() counterparts in the plugin and are out of scope.

Aria/data attribute assertions scope: assertAriaAttribute and assertDataAttribute are covered by UseBrowserAriaAndDataAttributeAssertionsRector. Note that the plugin methods accept the attribute name without the aria-/data- prefix — the rule strips the prefix automatically.

Before:

expect($page->value('input[name=email]'))->toBe('test@example.com');
expect($page->attribute('button', 'aria-label'))->toBe('Close');
expect($page->attribute('div', 'data-id'))->toBe('123');
expect($page->attribute('img', 'alt'))->toBe('Profile Picture');
expect($page->attribute('div', 'class'))->toContain('container');
expect($page->attribute('div', 'class'))->not->toContain('hidden');
expect($page->attribute('button', 'disabled'))->toBeNull();
expect($page->content())->toContain('<h1>Welcome</h1>');
expect($page->content())->not->toContain('<div class="error">');
expect($page->script('document.title'))->toBe('Home Page');
expect($page->script('window.scrollY'))->toEqual(0);
expect($page->url())->toBe('https://example.com/home');

After:

$page->assertValue('input[name=email]', 'test@example.com');
$page->assertAriaAttribute('button', 'label', 'Close');
$page->assertDataAttribute('div', 'id', '123');
$page->assertAttribute('img', 'alt', 'Profile Picture');
$page->assertAttributeContains('div', 'class', 'container');
$page->assertAttributeDoesntContain('div', 'class', 'hidden');
$page->assertAttributeMissing('button', 'disabled');
$page->assertSourceHas('<h1>Welcome</h1>');
$page->assertSourceMissing('<div class="error">');
$page->assertScript('document.title', 'Home Page');
$page->assertScript('window.scrollY', 0);
$page->assertUrlIs('https://example.com/home');

Using Individual Rules

You can also use individual rules instead of sets:

// rector.php
use RectorPest\Rules\ChainExpectCallsRector;
use Rector\Config\RectorConfig;

return RectorConfig::configure()
    ->withPaths([
        __DIR__ . '/tests',
    ])
    ->withRules([
        ChainExpectCallsRector::class,
    ]);

Running Rector

# Preview changes
vendor/bin/rector process --dry-run

# Apply changes
vendor/bin/rector process

Semantic Interoperability

Rector Pest separates three concerns:

  • deterministic semantic analyzers that only return local facts needed for a safe transformation
  • a canonical issue registry with stable identifiers and metadata for interoperability
  • an interop layer that maps external diagnostics onto canonical issues and safe Rector fixes

That split keeps the transformation layer conservative. For example, redundant literal type cleanup only removes checks when the literal value is deterministic and the surrounding chain does not branch or transform the expectation subject. Static callback cleanup also distinguishes nested Pest callbacks from nested non-Pest closure trees so outer describe() callbacks are not rewritten just because an inner hook needs instance binding.

The current semantic contract is documented in docs/semantic-architecture.md.

Requirements

  • PHP 8.2+
  • Rector 2.0+

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

The MIT License (MIT). Please see License File for more information.

mrpunyapal/rector-pest 适用场景与选型建议

mrpunyapal/rector-pest 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 78.93k 次下载、GitHub Stars 达 69, 最近一次更新时间为 2025 年 12 月 10 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「testing」 「phpunit」 「ast」 「dev」 「refactoring」 「static-analysis」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 mrpunyapal/rector-pest 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 mrpunyapal/rector-pest 我们能提供哪些服务?
定制开发 / 二次开发

基于 mrpunyapal/rector-pest 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 78.93k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 69
  • 点击次数: 31
  • 依赖项目数: 39
  • 推荐数: 0

GitHub 信息

  • Stars: 69
  • Watchers: 4
  • Forks: 6
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-12-10