-
-
Notifications
You must be signed in to change notification settings - Fork 22
Add test helper functions for controlling HTML ID generation #274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| # Testing ID Generation | ||
|
|
||
| `Html::generateId()` produces IDs that include an `hrtime(true)` timestamp, making them unique across | ||
| requests but non-deterministic in tests. The file `src/test-functions.php` provides helpers that make | ||
| generated IDs predictable during testing. | ||
|
|
||
| ## Setup | ||
|
|
||
| Include the file once before running tests: | ||
|
|
||
| ```php | ||
| require_once 'vendor/yiisoft/html/src/test-functions.php'; | ||
| ``` | ||
|
|
||
| ## Functions | ||
|
|
||
| ### `\Yiisoft\Html\IdGenerator\disableSeed()` | ||
|
|
||
| Disables the `hrtime()` seed: IDs become short and deterministic — `i1`, `i2`, `test1`, etc. | ||
| Call this in test setup to get predictable, hardcodable IDs. | ||
|
|
||
| ### `\Yiisoft\Html\IdGenerator\enableSeed()` | ||
|
|
||
| Re-enables the `hrtime()` seed, reverting to the default behaviour where IDs include a timestamp. | ||
| Call this in test teardown to restore normal operation. | ||
|
|
||
| ### `\Yiisoft\Html\IdGenerator\reset()` | ||
|
|
||
| Resets the counter to zero without changing the current seed mode. Useful when you need | ||
| a fresh counter mid-test while the seed is disabled. | ||
|
|
||
| ## Usage in PHPUnit | ||
|
|
||
| ### Bootstrap | ||
|
|
||
| To load the file automatically for the entire test suite, add it to your bootstrap file. | ||
|
|
||
| In `phpunit.xml`: | ||
|
|
||
| ```xml | ||
| <phpunit bootstrap="tests/bootstrap.php"> | ||
| ``` | ||
|
|
||
| In `tests/bootstrap.php`: | ||
|
|
||
| ```php | ||
| // ... | ||
| require_once 'vendor/autoload.php'; | ||
| require_once 'vendor/yiisoft/html/src/test-functions.php'; | ||
| // ... | ||
| ``` | ||
|
|
||
| ### Global disableSeed with per-test reset | ||
|
|
||
| If all tests in the suite need deterministic IDs, call `disableSeed()` once in the bootstrap | ||
| and then call `reset()` at the start of each test that relies on specific ID values: | ||
|
|
||
| In `tests/bootstrap.php`: | ||
|
|
||
| ```php | ||
| require_once 'vendor/yiisoft/html/src/test-functions.php'; | ||
|
|
||
| \Yiisoft\Html\IdGenerator\disableSeed(); | ||
| ``` | ||
|
|
||
| In the test class: | ||
|
|
||
| ```php | ||
| use Yiisoft\Html\IdGenerator; | ||
|
|
||
| final class MyTest extends TestCase | ||
| { | ||
| public function testRendersLabel(): void | ||
| { | ||
| IdGenerator\reset(); | ||
|
|
||
| $this->assertSame('<label for="i1">Name</label>', ...); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### `setUp()` and `tearDown()` | ||
|
|
||
| Useful when only one test class (or a few) needs deterministic IDs while the rest of the suite | ||
| uses the default `hrtime()` behaviour — for example, when adding ID assertions to an existing | ||
| project without touching the global bootstrap. | ||
|
|
||
| Call `disableSeed()` and `reset()` in `setUp()` so every test starts with deterministic IDs | ||
| from `i1`. Add `enableSeed()` in `tearDown()` to restore the default behaviour after the class | ||
| finishes: | ||
|
|
||
| ```php | ||
| use Yiisoft\Html\IdGenerator; | ||
|
|
||
| final class MyTest extends TestCase | ||
| { | ||
| protected function setUp(): void | ||
| { | ||
| IdGenerator\disableSeed(); | ||
| IdGenerator\reset(); | ||
| } | ||
|
|
||
| protected function tearDown(): void | ||
| { | ||
| IdGenerator\enableSeed(); | ||
| } | ||
|
|
||
| public function testRendersLabel(): void | ||
| { | ||
| // IDs are now i1, i2, … — safe to hardcode in assertions | ||
| $this->assertSame('<label for="i1">Name</label>', ...); | ||
| } | ||
| } | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Yiisoft\Html; | ||
|
|
||
| /** | ||
| * @internal | ||
| */ | ||
| final class IdGenerator | ||
| { | ||
| /** | ||
| * @var array<string, int> | ||
| */ | ||
| public static array $counter = []; | ||
|
|
||
| public static bool $useSeed = true; | ||
|
|
||
| /** | ||
| * @psalm-return non-empty-string | ||
| */ | ||
| public static function generate(string $prefix): string | ||
| { | ||
| if (self::$useSeed) { | ||
| $prefix .= hrtime(true); | ||
| } | ||
| if (isset(self::$counter[$prefix])) { | ||
| $count = ++self::$counter[$prefix]; | ||
| } else { | ||
| $count = 1; | ||
| if (self::$useSeed) { | ||
| self::$counter = [$prefix => $count]; | ||
|
Check warning on line 32 in src/IdGenerator.php
|
||
| } else { | ||
| self::$counter[$prefix] = $count; | ||
| } | ||
| } | ||
| return $prefix . $count; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Yiisoft\Html\IdGenerator; | ||
|
|
||
| use Yiisoft\Html\IdGenerator; | ||
| use Yiisoft\Html\Html; | ||
|
|
||
| /** | ||
| * Resets the internal ID counter used by {@see Html::generateId()}. | ||
| */ | ||
| function reset(): void | ||
| { | ||
| IdGenerator::$counter = []; | ||
| } | ||
|
|
||
| /** | ||
| * Re-enables the `hrtime()` seed. {@see Html::generateId()} will include a timestamp again (default behaviour). | ||
| */ | ||
| function enableSeed(): void | ||
| { | ||
| IdGenerator::$useSeed = true; | ||
| } | ||
|
|
||
| /** | ||
| * Disables the `hrtime()` seed. {@see Html::generateId()} will produce short deterministic IDs: `i1`, `i2`, etc. | ||
| */ | ||
| function disableSeed(): void | ||
| { | ||
| IdGenerator::$useSeed = false; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Yiisoft\Html\Tests; | ||
|
|
||
| use PHPUnit\Framework\TestCase; | ||
| use Yiisoft\Html\Html; | ||
| use Yiisoft\Html\IdGenerator; | ||
|
|
||
| final class HtmlGenerateIdTest extends TestCase | ||
| { | ||
| protected function tearDown(): void | ||
| { | ||
| IdGenerator\reset(); | ||
| IdGenerator\enableSeed(); | ||
|
|
||
| parent::tearDown(); | ||
| } | ||
|
|
||
| public function testGenerateIdWithSeedEnabled(): void | ||
| { | ||
| $this->assertMatchesRegularExpression('/^i\d+$/', Html::generateId()); | ||
| $this->assertMatchesRegularExpression('/^test\d+$/', Html::generateId('test')); | ||
| } | ||
|
|
||
| public function testGenerateIdWithSeedDisabled(): void | ||
| { | ||
| IdGenerator\disableSeed(); | ||
| IdGenerator\reset(); | ||
|
|
||
| $this->assertSame('i1', Html::generateId()); | ||
| $this->assertSame('i2', Html::generateId()); | ||
| $this->assertSame('i3', Html::generateId()); | ||
| } | ||
|
|
||
| public function testGenerateIdWithSeedDisabledCustomPrefix(): void | ||
| { | ||
| IdGenerator\disableSeed(); | ||
| IdGenerator\reset(); | ||
|
|
||
| $this->assertSame('test1', Html::generateId('test')); | ||
| $this->assertSame('test2', Html::generateId('test')); | ||
| } | ||
|
|
||
| public function testGenerateIdWithSeedDisabledMixedPrefixesDoNotResetEachOther(): void | ||
| { | ||
| IdGenerator\disableSeed(); | ||
| IdGenerator\reset(); | ||
|
|
||
| $this->assertSame('i1', Html::generateId()); | ||
| $this->assertSame('test1', Html::generateId('test')); | ||
| $this->assertSame('i2', Html::generateId()); | ||
| $this->assertSame('test2', Html::generateId('test')); | ||
| } | ||
|
|
||
| public function testResetClearsCounterWithoutChangingSeedMode(): void | ||
| { | ||
| IdGenerator\disableSeed(); | ||
| IdGenerator\reset(); | ||
|
|
||
| $this->assertSame('i1', Html::generateId()); | ||
| $this->assertSame('i2', Html::generateId()); | ||
|
|
||
| IdGenerator\reset(); | ||
|
|
||
| $this->assertSame('i1', Html::generateId()); | ||
| } | ||
|
|
||
| public function testEnableSeedRestoresTimestampBehavior(): void | ||
| { | ||
| IdGenerator\disableSeed(); | ||
| IdGenerator\reset(); | ||
| $this->assertSame('i1', Html::generateId()); | ||
|
|
||
| IdGenerator\enableSeed(); | ||
|
|
||
| $this->assertMatchesRegularExpression('/^i\d{10,}/', Html::generateId()); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| require_once __DIR__ . '/../vendor/autoload.php'; | ||
| require_once __DIR__ . '/../src/test-functions.php'; |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.