feat(v3.3.0): enterprise presets, badges, notifications, rule controller, watch mode, offline healer, and WCAG 2.2 ruleset

This commit is contained in:
Enes Yakıştır
2026-09-12 10:12:05 +03:00
parent 2de1f34878
commit ef8ccb9f75
43 changed files with 2598 additions and 81 deletions
+56
View File
@@ -0,0 +1,56 @@
<?php
namespace YakNet\AccessibilityConsole\Tests\Rules;
use PHPUnit\Framework\TestCase;
use YakNet\AccessibilityConsole\Core\Scanner;
use YakNet\AccessibilityConsole\Rules\LabelInName;
class LabelInNameTest extends TestCase
{
public function testFlagsButtonWhoseAriaLabelDoesNotContainVisibleText(): void
{
$scanner = new Scanner();
$scanner->addRule(new LabelInName());
$html = '<button aria-label="Send Form">Submit</button>';
$violations = $scanner->scan($html);
$this->assertCount(1, $violations);
$this->assertSame('WCAG_2_5_3_LABEL_IN_NAME', $violations[0]->ruleId);
$this->assertStringContainsString('Submit', $violations[0]->message);
}
public function testPassesButtonWhoseAriaLabelContainsVisibleText(): void
{
$scanner = new Scanner();
$scanner->addRule(new LabelInName());
$html = '<button aria-label="Submit this inquiry">Submit</button>';
$violations = $scanner->scan($html);
$this->assertCount(0, $violations);
}
public function testPassesButtonWithoutExplicitAriaLabel(): void
{
$scanner = new Scanner();
$scanner->addRule(new LabelInName());
$html = '<button>Click Here</button>';
$violations = $scanner->scan($html);
$this->assertCount(0, $violations);
}
public function testFlagsLinkWhoseAriaLabelDiffersFromVisibleText(): void
{
$scanner = new Scanner();
$scanner->addRule(new LabelInName());
$html = '<a href="/contact" aria-label="Reach out to support">Contact Us</a>';
$violations = $scanner->scan($html);
$this->assertCount(1, $violations);
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace YakNet\AccessibilityConsole\Tests\Rules;
use PHPUnit\Framework\TestCase;
use YakNet\AccessibilityConsole\Core\Scanner;
use YakNet\AccessibilityConsole\Rules\RedundantEntry;
class RedundantEntryTest extends TestCase
{
public function testFlagsFormWithShippingAndBillingWithoutSameAsCheckbox(): void
{
$scanner = new Scanner();
$scanner->addRule(new RedundantEntry());
$html = '<form>
<input type="text" name="shipping_address" id="shipping_address">
<input type="text" name="shipping_city" id="shipping_city">
<input type="text" name="billing_address" id="billing_address">
<input type="text" name="billing_city" id="billing_city">
</form>';
$violations = $scanner->scan($html);
$this->assertCount(1, $violations);
$this->assertSame('WCAG_3_3_7_REDUNDANT_ENTRY', $violations[0]->ruleId);
}
public function testPassesFormWithSameAsShippingCheckbox(): void
{
$scanner = new Scanner();
$scanner->addRule(new RedundantEntry());
$html = '<form>
<input type="text" name="shipping_address" id="shipping_address">
<input type="text" name="shipping_city" id="shipping_city">
<label><input type="checkbox" name="same_as_shipping"> Billing same as shipping</label>
<input type="text" name="billing_address" id="billing_address">
<input type="text" name="billing_city" id="billing_city">
</form>';
$violations = $scanner->scan($html);
$this->assertCount(0, $violations);
}
}
+56
View File
@@ -0,0 +1,56 @@
<?php
namespace YakNet\AccessibilityConsole\Tests\Rules;
use PHPUnit\Framework\TestCase;
use YakNet\AccessibilityConsole\Core\Severity;
use YakNet\AccessibilityConsole\Core\WCAGStandard;
use YakNet\AccessibilityConsole\Rules\RuleController;
class RuleControllerTest extends TestCase
{
public function testInitializesAndRetrievesRule(): void
{
$controller = new RuleController();
$this->assertGreaterThanOrEqual(130, $controller->count());
$rule = $controller->getRule('WCAG_2_5_3_LABEL_IN_NAME');
$this->assertNotNull($rule);
}
public function testFilterByStandard(): void
{
$controller = new RuleController();
$aaRules = $controller->filterByStandard(WCAGStandard::AA);
$this->assertNotEmpty($aaRules);
foreach ($aaRules as $rule) {
$this->assertSame(WCAGStandard::AA, $rule->getStandard());
}
}
public function testFilterBySeverity(): void
{
$controller = new RuleController();
$errorRules = $controller->filterBySeverity(Severity::ERROR);
$this->assertNotEmpty($errorRules);
foreach ($errorRules as $rule) {
$this->assertSame(Severity::ERROR, $rule->getSeverity());
}
}
public function testExecuteRuleDirectlyOnDomElement(): void
{
$controller = new RuleController();
$dom = new \DOMDocument();
$dom->loadHTML('<button aria-label="Cancel">Submit</button>');
$button = $dom->getElementsByTagName('button')->item(0);
$this->assertInstanceOf(\DOMElement::class, $button);
$violation = $controller->executeRule('WCAG_2_5_3_LABEL_IN_NAME', $button);
$this->assertNotNull($violation);
$this->assertSame('WCAG_2_5_3_LABEL_IN_NAME', $violation->ruleId);
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace YakNet\AccessibilityConsole\Tests\Rules;
use PHPUnit\Framework\TestCase;
use YakNet\AccessibilityConsole\Rules\RuleExecutionStats;
class RuleExecutionStatsTest extends TestCase
{
public function testRecordAndRetrieveStats(): void
{
$stats = new RuleExecutionStats();
$stats->record('WCAG_1_1_1_IMG_ALT', 2.5, true);
$stats->record('WCAG_1_1_1_IMG_ALT', 1.5, false);
$stats->record('WCAG_1_4_3_CONTRAST', 10.0, true);
$all = $stats->getAllStats();
$this->assertSame(2, $all['WCAG_1_1_1_IMG_ALT']['invocations']);
$this->assertSame(4.0, $all['WCAG_1_1_1_IMG_ALT']['total_time_ms']);
$this->assertSame(1, $all['WCAG_1_1_1_IMG_ALT']['violations']);
$slowest = $stats->getSlowestRules(1);
$this->assertArrayHasKey('WCAG_1_4_3_CONTRAST', $slowest);
$this->assertSame(10.0, $slowest['WCAG_1_4_3_CONTRAST']['total_time_ms']);
}
public function testResetStats(): void
{
$stats = new RuleExecutionStats();
$stats->record('WCAG_1_1_1_IMG_ALT', 5.0, true);
$this->assertNotEmpty($stats->getAllStats());
$stats->reset();
$this->assertEmpty($stats->getAllStats());
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace YakNet\AccessibilityConsole\Tests\Rules;
use PHPUnit\Framework\TestCase;
use YakNet\AccessibilityConsole\Core\Scanner;
use YakNet\AccessibilityConsole\Rules\TextSpacing;
class TextSpacingTest extends TestCase
{
public function testFlagsConstrainedLineHeight(): void
{
$scanner = new Scanner();
$scanner->addRule(new TextSpacing());
$html = '<p style="line-height: 1; font-size: 16px;">This text has insufficient line height.</p>';
$violations = $scanner->scan($html);
$this->assertCount(1, $violations);
$this->assertSame('WCAG_1_4_12_TEXT_SPACING', $violations[0]->ruleId);
}
public function testPassesAdequateLineHeight(): void
{
$scanner = new Scanner();
$scanner->addRule(new TextSpacing());
$html = '<p style="line-height: 1.6; font-size: 16px;">Proper line height content.</p>';
$violations = $scanner->scan($html);
$this->assertCount(0, $violations);
}
public function testFlagsFixedHeightWithOverflowHiddenOnText(): void
{
$scanner = new Scanner();
$scanner->addRule(new TextSpacing());
$html = '<div style="height: 30px; overflow: hidden;"><p>This is a long paragraph that might be clipped when spacing is enlarged by the user in accessible mode.</p></div>';
$violations = $scanner->scan($html);
$this->assertCount(1, $violations);
}
}