Skip to content

Commit 26cf993

Browse files
committed
feat(test): add unit tests for RoleCatalog and StandardRuleSets classes
1 parent 909935d commit 26cf993

3 files changed

Lines changed: 257 additions & 0 deletions

File tree

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TwigA11y\Tests\Rules\Aria;
6+
7+
use PHPUnit\Framework\Attributes\CoversClass;
8+
use PHPUnit\Framework\TestCase;
9+
use TwigA11y\Rules\Aria\RoleCatalog;
10+
11+
/**
12+
* @internal
13+
*/
14+
#[CoversClass(RoleCatalog::class)]
15+
final class RoleCatalogTest extends TestCase
16+
{
17+
public function testGetAllowedRolesReturnsNonEmptyArray(): void
18+
{
19+
$roles = RoleCatalog::getAllowedRoles();
20+
21+
self::assertIsArray($roles);
22+
self::assertNotEmpty($roles);
23+
}
24+
25+
public function testGetAllowedRolesContainsKnownWaiAriaRoles(): void
26+
{
27+
$roles = RoleCatalog::getAllowedRoles();
28+
29+
$expected = [
30+
'alert', 'alertdialog', 'application', 'article', 'banner',
31+
'button', 'checkbox', 'combobox', 'dialog', 'document',
32+
'feed', 'figure', 'form', 'grid', 'group', 'heading', 'img',
33+
'link', 'list', 'listbox', 'listitem', 'log', 'main', 'menu',
34+
'menubar', 'menuitem', 'navigation', 'none', 'option',
35+
'presentation', 'progressbar', 'radio', 'radiogroup', 'region',
36+
'row', 'rowgroup', 'scrollbar', 'search', 'searchbox',
37+
'separator', 'slider', 'spinbutton', 'status', 'switch',
38+
'tab', 'table', 'tablist', 'tabpanel', 'textbox', 'timer',
39+
'toolbar', 'tooltip', 'tree', 'treegrid', 'treeitem',
40+
];
41+
42+
foreach ($expected as $role) {
43+
self::assertContains($role, $roles, \sprintf('Expected role "%s" to be in the allowed roles list.', $role));
44+
}
45+
}
46+
47+
public function testGetAllowedRolesContainsOnlyStrings(): void
48+
{
49+
foreach (RoleCatalog::getAllowedRoles() as $role) {
50+
self::assertIsString($role);
51+
self::assertNotEmpty($role);
52+
}
53+
}
54+
55+
public function testGetCatalogReturnsNonEmptyArray(): void
56+
{
57+
$catalog = RoleCatalog::getCatalog();
58+
59+
self::assertIsArray($catalog);
60+
self::assertNotEmpty($catalog);
61+
}
62+
63+
public function testGetCatalogEntriesHaveExpectedShape(): void
64+
{
65+
foreach (RoleCatalog::getCatalog() as $role => $entry) {
66+
self::assertIsString($role, 'Catalog key must be a string role name.');
67+
self::assertArrayHasKey('required_attrs', $entry, \sprintf('Role "%s" must have required_attrs.', $role));
68+
self::assertArrayHasKey('required_children', $entry, \sprintf('Role "%s" must have required_children.', $role));
69+
self::assertIsArray($entry['required_attrs']);
70+
self::assertIsArray($entry['required_children']);
71+
}
72+
}
73+
74+
public function testGetCatalogContainsCompositeWidgets(): void
75+
{
76+
$catalog = RoleCatalog::getCatalog();
77+
78+
self::assertArrayHasKey('table', $catalog);
79+
self::assertContains('row', $catalog['table']['required_children']);
80+
81+
self::assertArrayHasKey('tablist', $catalog);
82+
self::assertContains('tab', $catalog['tablist']['required_children']);
83+
84+
self::assertArrayHasKey('list', $catalog);
85+
self::assertContains('listitem', $catalog['list']['required_children']);
86+
87+
self::assertArrayHasKey('radiogroup', $catalog);
88+
self::assertContains('radio', $catalog['radiogroup']['required_children']);
89+
90+
self::assertArrayHasKey('tree', $catalog);
91+
self::assertContains('treeitem', $catalog['tree']['required_children']);
92+
93+
self::assertArrayHasKey('grid', $catalog);
94+
self::assertContains('row', $catalog['grid']['required_children']);
95+
96+
self::assertArrayHasKey('listbox', $catalog);
97+
self::assertContains('option', $catalog['listbox']['required_children']);
98+
99+
self::assertArrayHasKey('menu', $catalog);
100+
self::assertContains('menuitem', $catalog['menu']['required_children']);
101+
102+
self::assertArrayHasKey('menubar', $catalog);
103+
self::assertContains('menuitem', $catalog['menubar']['required_children']);
104+
}
105+
106+
public function testGetCatalogRolesWithRequiredAttrs(): void
107+
{
108+
$catalog = RoleCatalog::getCatalog();
109+
110+
self::assertArrayHasKey('tab', $catalog);
111+
self::assertContains('aria-selected', $catalog['tab']['required_attrs']);
112+
113+
self::assertArrayHasKey('checkbox', $catalog);
114+
self::assertContains('aria-checked', $catalog['checkbox']['required_attrs']);
115+
116+
self::assertArrayHasKey('radio', $catalog);
117+
self::assertContains('aria-checked', $catalog['radio']['required_attrs']);
118+
}
119+
120+
public function testGetCatalogRolesWithNoRequiredAttrs(): void
121+
{
122+
$catalog = RoleCatalog::getCatalog();
123+
124+
foreach (['button', 'table', 'list', 'menu', 'menubar', 'row'] as $role) {
125+
self::assertArrayHasKey($role, $catalog);
126+
self::assertSame([], $catalog[$role]['required_attrs'], \sprintf('Role "%s" should have no required_attrs.', $role));
127+
}
128+
}
129+
}

tests/Standard/A11yStandardTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
use TwigA11y\Standard\A11yRecommendedStandard;
7474
use TwigA11y\Standard\A11yStandard;
7575
use TwigA11y\Standard\A11yStrict;
76+
use TwigA11y\Standard\StandardRuleSets;
7677
use TwigCsFixer\Rules\Node\NodeRuleInterface;
7778
use TwigCsFixer\Rules\RuleInterface;
7879
use TwigCsFixer\Standard\StandardInterface;
@@ -147,6 +148,7 @@
147148
#[CoversClass(A11yRecommendedStandard::class)]
148149
#[CoversClass(A11yStandard::class)]
149150
#[CoversClass(A11yStrict::class)]
151+
#[CoversClass(StandardRuleSets::class)]
150152
final class A11yStandardTest extends TestCase
151153
{
152154
public function testBasicStandardProvidesExpectedRules(): void
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TwigA11y\Tests\Standard;
6+
7+
use PHPUnit\Framework\Attributes\CoversClass;
8+
use PHPUnit\Framework\TestCase;
9+
use TwigA11y\Rules\Forms\InputLabelRule;
10+
use TwigA11y\Rules\Media\ImgAltRule;
11+
use TwigA11y\Rules\Structure\BannedTagsRule;
12+
use TwigA11y\Rules\Structure\ButtonContentRule;
13+
use TwigA11y\Rules\Structure\LangAttributeRule;
14+
use TwigA11y\Standard\StandardRuleSets;
15+
use TwigCsFixer\Rules\RuleInterface;
16+
17+
/**
18+
* @internal
19+
*/
20+
#[CoversClass(StandardRuleSets::class)]
21+
final class StandardRuleSetsTest extends TestCase
22+
{
23+
public function testBasicReturnsRuleInterfaceInstances(): void
24+
{
25+
$rules = StandardRuleSets::basic();
26+
27+
self::assertNotEmpty($rules);
28+
self::assertContainsOnlyInstancesOf(RuleInterface::class, $rules);
29+
}
30+
31+
public function testBasicContainsExpectedClasses(): void
32+
{
33+
$classes = array_map(static fn (RuleInterface $r): string => $r::class, StandardRuleSets::basic());
34+
35+
self::assertSame([
36+
ImgAltRule::class,
37+
BannedTagsRule::class,
38+
ButtonContentRule::class,
39+
InputLabelRule::class,
40+
LangAttributeRule::class,
41+
], $classes);
42+
}
43+
44+
public function testRecommendedReturnsRuleInterfaceInstances(): void
45+
{
46+
$rules = StandardRuleSets::recommended();
47+
48+
self::assertNotEmpty($rules);
49+
self::assertContainsOnlyInstancesOf(RuleInterface::class, $rules);
50+
}
51+
52+
public function testRecommendedIsSupersetOfBasic(): void
53+
{
54+
$basicClasses = array_map(static fn (RuleInterface $r): string => $r::class, StandardRuleSets::basic());
55+
$recommendedClasses = array_map(static fn (RuleInterface $r): string => $r::class, StandardRuleSets::recommended());
56+
57+
foreach ($basicClasses as $class) {
58+
self::assertContains($class, $recommendedClasses, \sprintf('Recommended should include basic rule "%s".', $class));
59+
}
60+
}
61+
62+
public function testStandardReturnsRuleInterfaceInstances(): void
63+
{
64+
$rules = StandardRuleSets::standard();
65+
66+
self::assertNotEmpty($rules);
67+
self::assertContainsOnlyInstancesOf(RuleInterface::class, $rules);
68+
}
69+
70+
public function testStandardIsSupersetOfRecommended(): void
71+
{
72+
$recommendedClasses = array_map(static fn (RuleInterface $r): string => $r::class, StandardRuleSets::recommended());
73+
$standardClasses = array_map(static fn (RuleInterface $r): string => $r::class, StandardRuleSets::standard());
74+
75+
foreach ($recommendedClasses as $class) {
76+
self::assertContains($class, $standardClasses, \sprintf('Standard should include recommended rule "%s".', $class));
77+
}
78+
}
79+
80+
public function testStrictReturnsRuleInterfaceInstances(): void
81+
{
82+
$rules = StandardRuleSets::strict();
83+
84+
self::assertNotEmpty($rules);
85+
self::assertContainsOnlyInstancesOf(RuleInterface::class, $rules);
86+
}
87+
88+
public function testStrictIsSupersetOfStandard(): void
89+
{
90+
$standardClasses = array_map(static fn (RuleInterface $r): string => $r::class, StandardRuleSets::standard());
91+
$strictClasses = array_map(static fn (RuleInterface $r): string => $r::class, StandardRuleSets::strict());
92+
93+
foreach ($standardClasses as $class) {
94+
self::assertContains($class, $strictClasses, \sprintf('Strict should include standard rule "%s".', $class));
95+
}
96+
}
97+
98+
public function testEachRuleSetContainsUniqueClasses(): void
99+
{
100+
foreach ([
101+
'basic' => StandardRuleSets::basic(),
102+
'recommended' => StandardRuleSets::recommended(),
103+
'standard' => StandardRuleSets::standard(),
104+
'strict' => StandardRuleSets::strict(),
105+
] as $level => $rules) {
106+
$classes = array_map(static fn (RuleInterface $r): string => $r::class, $rules);
107+
self::assertSame(
108+
array_unique($classes),
109+
$classes,
110+
\sprintf('Rule set "%s" should not contain duplicate rule classes.', $level)
111+
);
112+
}
113+
}
114+
115+
public function testInstantiateProducesNewInstancesEachCall(): void
116+
{
117+
$rulesA = StandardRuleSets::basic();
118+
$rulesB = StandardRuleSets::basic();
119+
120+
self::assertCount(\count($rulesA), $rulesB);
121+
122+
foreach ($rulesA as $i => $ruleA) {
123+
self::assertNotSame($ruleA, $rulesB[$i], 'Each call to basic() should return fresh instances.');
124+
}
125+
}
126+
}

0 commit comments

Comments
 (0)