semmet-angular 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/README.md +6 -0
  2. package/package.json +1 -1
  3. package/src/accordion/files/__name@dasherize__/__name@dasherize__.spec.ts.template +124 -0
  4. package/src/accordion/index.js +1 -1
  5. package/src/accordion/index.js.map +1 -1
  6. package/src/accordion/index.ts +1 -1
  7. package/src/alert/files/__name@dasherize__/__name@dasherize__.spec.ts.template +27 -0
  8. package/src/alert/index.js +1 -1
  9. package/src/alert/index.js.map +1 -1
  10. package/src/alert/index.ts +1 -1
  11. package/src/alert-dialog/files/__name@dasherize__/__name@dasherize__.spec.ts.template +66 -0
  12. package/src/alert-dialog/index.js +1 -1
  13. package/src/alert-dialog/index.js.map +1 -1
  14. package/src/alert-dialog/index.ts +1 -1
  15. package/src/button/files/__name@dasherize__/__name@dasherize__.spec.ts.template +69 -0
  16. package/src/button/index.js +1 -1
  17. package/src/button/index.js.map +1 -1
  18. package/src/button/index.ts +1 -1
  19. package/src/button-group/files/__name@dasherize__/__name@dasherize__.spec.ts.template +70 -0
  20. package/src/button-group/index.js +1 -1
  21. package/src/button-group/index.js.map +1 -1
  22. package/src/button-group/index.ts +1 -1
  23. package/src/carousel/files/__name@dasherize__/__name@dasherize__.spec.ts.template +69 -0
  24. package/src/carousel/index.js +1 -1
  25. package/src/carousel/index.js.map +1 -1
  26. package/src/carousel/index.ts +1 -1
  27. package/src/checkbox/files/__name@dasherize__/__name@dasherize__.spec.ts.template +41 -0
  28. package/src/checkbox/index.js +1 -1
  29. package/src/checkbox/index.js.map +1 -1
  30. package/src/checkbox/index.ts +1 -1
  31. package/src/close-button/files/__name@dasherize__/__name@dasherize__.spec.ts.template +64 -0
  32. package/src/close-button/index.js +1 -1
  33. package/src/close-button/index.js.map +1 -1
  34. package/src/close-button/index.ts +1 -1
  35. package/src/combobox/files/__name@dasherize__/__name@dasherize__.spec.ts.template +79 -0
  36. package/src/combobox/index.js +1 -1
  37. package/src/combobox/index.js.map +1 -1
  38. package/src/combobox/index.ts +1 -1
  39. package/src/dialog/files/__name@dasherize__/__name@dasherize__.spec.ts.template +68 -0
  40. package/src/dialog/index.js +1 -1
  41. package/src/dialog/index.js.map +1 -1
  42. package/src/dialog/index.ts +1 -1
  43. package/src/disclosure/files/__name@dasherize__/__name@dasherize__.spec.ts.template +67 -0
  44. package/src/disclosure/index.js +1 -1
  45. package/src/disclosure/index.js.map +1 -1
  46. package/src/disclosure/index.ts +1 -1
  47. package/src/input/files/__name@dasherize__/__name@dasherize__.spec.ts.template +56 -0
  48. package/src/input/index.js +1 -1
  49. package/src/input/index.js.map +1 -1
  50. package/src/input/index.ts +1 -1
  51. package/src/list-group/files/__name@dasherize__/__name@dasherize__.spec.ts.template +66 -0
  52. package/src/list-group/index.js +1 -1
  53. package/src/list-group/index.js.map +1 -1
  54. package/src/list-group/index.ts +1 -1
  55. package/src/listbox/files/__name@dasherize__/__name@dasherize__.spec.ts.template +50 -0
  56. package/src/listbox/index.js +1 -1
  57. package/src/listbox/index.js.map +1 -1
  58. package/src/listbox/index.ts +1 -1
  59. package/src/menu-button/files/__name@dasherize__/__name@dasherize__.spec.ts.template +64 -0
  60. package/src/menu-button/index.js +1 -1
  61. package/src/menu-button/index.js.map +1 -1
  62. package/src/menu-button/index.ts +1 -1
  63. package/src/navbar/files/__name@dasherize__/__name@dasherize__.spec.ts.template +74 -0
  64. package/src/navbar/index.js +1 -1
  65. package/src/navbar/index.js.map +1 -1
  66. package/src/navbar/index.ts +1 -1
  67. package/src/navigation-menu/files/__name@dasherize__/__name@dasherize__.spec.ts.template +51 -0
  68. package/src/navigation-menu/index.js +1 -1
  69. package/src/navigation-menu/index.js.map +1 -1
  70. package/src/navigation-menu/index.ts +1 -1
  71. package/src/offcanvas/files/__name@dasherize__/__name@dasherize__.spec.ts.template +70 -0
  72. package/src/offcanvas/index.js +1 -1
  73. package/src/offcanvas/index.js.map +1 -1
  74. package/src/offcanvas/index.ts +1 -1
  75. package/src/pagination/files/__name@dasherize__/__name@dasherize__.spec.ts.template +41 -0
  76. package/src/pagination/index.js +1 -1
  77. package/src/pagination/index.js.map +1 -1
  78. package/src/pagination/index.ts +1 -1
  79. package/src/popover/files/__name@dasherize__/__name@dasherize__.spec.ts.template +69 -0
  80. package/src/popover/index.js +1 -1
  81. package/src/popover/index.js.map +1 -1
  82. package/src/popover/index.ts +1 -1
  83. package/src/radio-group/files/__name@dasherize__/__name@dasherize__.spec.ts.template +47 -0
  84. package/src/radio-group/index.js +1 -1
  85. package/src/radio-group/index.js.map +1 -1
  86. package/src/radio-group/index.ts +1 -1
  87. package/src/select/files/__name@dasherize__/__name@dasherize__.spec.ts.template +54 -0
  88. package/src/select/index.js +1 -1
  89. package/src/select/index.js.map +1 -1
  90. package/src/select/index.ts +1 -1
  91. package/src/slider/files/__name@dasherize__/__name@dasherize__.spec.ts.template +61 -0
  92. package/src/slider/index.js +1 -1
  93. package/src/slider/index.js.map +1 -1
  94. package/src/slider/index.ts +1 -1
  95. package/src/spinbutton/files/__name@dasherize__/__name@dasherize__.spec.ts.template +74 -0
  96. package/src/spinbutton/index.js +1 -1
  97. package/src/spinbutton/index.js.map +1 -1
  98. package/src/spinbutton/index.ts +1 -1
  99. package/src/switch/files/__name@dasherize__/__name@dasherize__.spec.ts.template +35 -0
  100. package/src/switch/index.js +1 -1
  101. package/src/switch/index.js.map +1 -1
  102. package/src/switch/index.ts +1 -1
  103. package/src/tabs/files/__name@dasherize__/__name@dasherize__.spec.ts.template +113 -0
  104. package/src/tabs/index.js +1 -1
  105. package/src/tabs/index.js.map +1 -1
  106. package/src/tabs/index.ts +1 -1
  107. package/src/textarea/files/__name@dasherize__/__name@dasherize__.spec.ts.template +59 -0
  108. package/src/textarea/index.js +1 -1
  109. package/src/textarea/index.js.map +1 -1
  110. package/src/textarea/index.ts +1 -1
  111. package/src/toast/files/__name@dasherize__/__name@dasherize__.spec.ts.template +48 -0
  112. package/src/toast/index.js +1 -1
  113. package/src/toast/index.js.map +1 -1
  114. package/src/toast/index.ts +1 -1
  115. package/src/toolbar/files/__name@dasherize__/__name@dasherize__.spec.ts.template +45 -0
  116. package/src/toolbar/index.js +1 -1
  117. package/src/toolbar/index.js.map +1 -1
  118. package/src/toolbar/index.ts +1 -1
  119. package/src/tooltip/files/__name@dasherize__/__name@dasherize__.spec.ts.template +56 -0
  120. package/src/tooltip/index.js +1 -1
  121. package/src/tooltip/index.js.map +1 -1
  122. package/src/tooltip/index.ts +1 -1
  123. package/src/tree-view/files/__name@dasherize__/__name@dasherize__.spec.ts.template +84 -0
  124. package/src/tree-view/index.js +1 -1
  125. package/src/tree-view/index.js.map +1 -1
  126. package/src/tree-view/index.ts +1 -1
  127. package/src/utils/component-test-files/__name@dasherize__/__name@dasherize__.spec.ts.template +15 -1
  128. package/src/utils/generate-component.d.ts +6 -1
  129. package/src/utils/generate-component.js +21 -6
  130. package/src/utils/generate-component.js.map +1 -1
  131. package/src/utils/generate-component.ts +28 -7
@@ -0,0 +1,74 @@
1
+ import { Component } from '@angular/core';
2
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
3
+ import { By } from '@angular/platform-browser';
4
+
5
+ import { <%= classify(name) %> } from './<%= dasherize(name) %>';
6
+
7
+ @Component({
8
+ imports: [<%= classify(name) %>],
9
+ template: `<<%= selector %> />`,
10
+ })
11
+ class HostComponent {}
12
+
13
+ describe('<%= classify(name) %>', () => {
14
+ let fixture: ComponentFixture<HostComponent>;
15
+ let host: HTMLElement;
16
+
17
+ beforeEach(async () => {
18
+ await TestBed.configureTestingModule({
19
+ imports: [HostComponent],
20
+ }).compileComponents();
21
+
22
+ fixture = TestBed.createComponent(HostComponent);
23
+ fixture.detectChanges();
24
+ host = fixture.nativeElement as HTMLElement;
25
+ });
26
+
27
+ it('renders spinbutton semantics and value bounds', () => {
28
+ const input = host.querySelector<HTMLInputElement>('[role="spinbutton"]');
29
+
30
+ expect(input).toBeTruthy();
31
+ expect(input?.getAttribute('aria-labelledby')).toBeTruthy();
32
+ expect(input?.getAttribute('aria-valuemin')).toBe('0');
33
+ expect(input?.getAttribute('aria-valuemax')).toBe('99');
34
+ expect(input?.getAttribute('aria-valuenow')).toBe('1');
35
+ });
36
+
37
+ it('increments and decrements from buttons and keyboard', () => {
38
+ const inputDebug = fixture.debugElement.query(By.css('[role="spinbutton"]'));
39
+ const input = inputDebug.nativeElement as HTMLInputElement;
40
+ const buttons = Array.from(host.querySelectorAll<HTMLButtonElement>('button'));
41
+
42
+ buttons[1].click();
43
+ fixture.detectChanges();
44
+ expect(input.value).toBe('2');
45
+ expect(input.getAttribute('aria-valuenow')).toBe('2');
46
+
47
+ inputDebug.triggerEventHandler('keydown', new KeyboardEvent('keydown', { key: 'ArrowDown' }));
48
+ fixture.detectChanges();
49
+ expect(input.value).toBe('1');
50
+
51
+ buttons[0].click();
52
+ fixture.detectChanges();
53
+ expect(input.value).toBe('0');
54
+
55
+ inputDebug.triggerEventHandler('keydown', new KeyboardEvent('keydown', { key: 'ArrowDown' }));
56
+ fixture.detectChanges();
57
+ expect(input.value).toBe('0');
58
+ });
59
+
60
+ it('accepts typed numbers and clamps them to the supported range', () => {
61
+ const inputDebug = fixture.debugElement.query(By.css('[role="spinbutton"]'));
62
+ const input = inputDebug.nativeElement as HTMLInputElement;
63
+
64
+ input.value = '120';
65
+ inputDebug.triggerEventHandler('change', { target: input });
66
+ fixture.detectChanges();
67
+ expect(input.value).toBe('99');
68
+
69
+ input.value = '-10';
70
+ inputDebug.triggerEventHandler('change', { target: input });
71
+ fixture.detectChanges();
72
+ expect(input.value).toBe('0');
73
+ });
74
+ });
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.spinbutton = void 0;
4
4
  const generate_component_1 = require("../utils/generate-component");
5
- exports.spinbutton = (0, generate_component_1.createAriaComponentSchematic)();
5
+ exports.spinbutton = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
6
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,UAAU,GAAG,IAAA,iDAA4B,GAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,UAAU,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import { createAriaComponentSchematic } from '../utils/generate-component';
2
2
 
3
- export const spinbutton = createAriaComponentSchematic();
3
+ export const spinbutton = createAriaComponentSchematic({ includeSharedUnitTest: false });
@@ -0,0 +1,35 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+ import { <%= classify(name) %> } from './<%= dasherize(name) %>';
3
+
4
+ describe('<%= classify(name) %>', () => {
5
+ let fixture: ComponentFixture<<%= classify(name) %>>;
6
+
7
+ beforeEach(async () => {
8
+ await TestBed.configureTestingModule({
9
+ imports: [<%= classify(name) %>],
10
+ }).compileComponents();
11
+
12
+ fixture = TestBed.createComponent(<%= classify(name) %>);
13
+ fixture.detectChanges();
14
+ });
15
+
16
+ function switchButton(): HTMLButtonElement {
17
+ return fixture.nativeElement.querySelector('[role="switch"]');
18
+ }
19
+
20
+ it('renders a native button with switch semantics', () => {
21
+ expect(switchButton().tagName).toBe('BUTTON');
22
+ expect(switchButton().getAttribute('aria-checked')).toBe('false');
23
+ expect(switchButton().textContent?.trim()).toBe('Enable notifications');
24
+ });
25
+
26
+ it('toggles aria-checked when clicked', () => {
27
+ switchButton().click();
28
+ fixture.detectChanges();
29
+ expect(switchButton().getAttribute('aria-checked')).toBe('true');
30
+
31
+ switchButton().click();
32
+ fixture.detectChanges();
33
+ expect(switchButton().getAttribute('aria-checked')).toBe('false');
34
+ });
35
+ });
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.switchSchematic = void 0;
4
4
  const generate_component_1 = require("../utils/generate-component");
5
- exports.switchSchematic = (0, generate_component_1.createAriaComponentSchematic)();
5
+ exports.switchSchematic = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
6
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,eAAe,GAAG,IAAA,iDAA4B,GAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,eAAe,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import { createAriaComponentSchematic } from '../utils/generate-component';
2
2
 
3
- export const switchSchematic = createAriaComponentSchematic();
3
+ export const switchSchematic = createAriaComponentSchematic({ includeSharedUnitTest: false });
@@ -0,0 +1,113 @@
1
+ import { Component } from '@angular/core';
2
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
3
+ import { <%= classify(name) %>, <%= classify(name) %>Item } from './<%= dasherize(name) %>';
4
+
5
+ @Component({
6
+ imports: [<%= classify(name) %>, <%= classify(name) %>Item],
7
+ template: `
8
+ <<%= selector %> [preserveContent]="preserveContent">
9
+ <ng-template <%= camelize(name) %>Item id="profile" label="Profile" [selected]="true">
10
+ <p>Profile content</p>
11
+ </ng-template>
12
+
13
+ <ng-template <%= camelize(name) %>Item id="settings" label="Settings">
14
+ <p>Settings content</p>
15
+ </ng-template>
16
+
17
+ <ng-template <%= camelize(name) %>Item id="billing" label="Billing" disabled>
18
+ <p>Billing content</p>
19
+ </ng-template>
20
+ </<%= selector %>>
21
+ `,
22
+ })
23
+ class HostComponent {
24
+ preserveContent = true;
25
+ }
26
+
27
+ describe('<%= classify(name) %>', () => {
28
+ let fixture: ComponentFixture<HostComponent>;
29
+
30
+ beforeEach(async () => {
31
+ await TestBed.configureTestingModule({
32
+ imports: [HostComponent],
33
+ }).compileComponents();
34
+
35
+ fixture = TestBed.createComponent(HostComponent);
36
+ fixture.detectChanges();
37
+ });
38
+
39
+ function tabs(): HTMLButtonElement[] {
40
+ return Array.from(fixture.nativeElement.querySelectorAll('[role="tab"]'));
41
+ }
42
+
43
+ function panels(): HTMLElement[] {
44
+ return Array.from(fixture.nativeElement.querySelectorAll('[role="tabpanel"]'));
45
+ }
46
+
47
+ it('renders a tablist with ARIA relationships', () => {
48
+ const tablist = fixture.nativeElement.querySelector('[role="tablist"]');
49
+ const [profileTab, settingsTab] = tabs();
50
+ const [profilePanel, settingsPanel] = panels();
51
+
52
+ expect(tablist).toBeTruthy();
53
+ expect(profileTab.textContent?.trim()).toBe('Profile');
54
+ expect(profileTab.getAttribute('aria-selected')).toBe('true');
55
+ expect(profileTab.getAttribute('aria-controls')).toBe(profilePanel.id);
56
+ expect(profileTab.tabIndex).toBe(0);
57
+ expect(profilePanel.getAttribute('aria-labelledby')).toBe(profileTab.id);
58
+ expect(profilePanel.hidden).toBe(false);
59
+
60
+ expect(settingsTab.getAttribute('aria-selected')).toBe('false');
61
+ expect(settingsTab.getAttribute('aria-controls')).toBe(settingsPanel.id);
62
+ expect(settingsTab.tabIndex).toBe(-1);
63
+ expect(settingsPanel.hidden).toBe(true);
64
+ });
65
+
66
+ it('selects an enabled tab with click', () => {
67
+ const [, settingsTab] = tabs();
68
+ const [profilePanel, settingsPanel] = panels();
69
+
70
+ settingsTab.click();
71
+ fixture.detectChanges();
72
+
73
+ expect(settingsTab.getAttribute('aria-selected')).toBe('true');
74
+ expect(settingsTab.tabIndex).toBe(0);
75
+ expect(settingsPanel.hidden).toBe(false);
76
+ expect(settingsPanel.textContent).toContain('Settings content');
77
+ expect(profilePanel.hidden).toBe(true);
78
+ });
79
+
80
+ it('does not select disabled tabs', () => {
81
+ const disabledTab = tabs()[2];
82
+ const disabledPanel = panels()[2];
83
+
84
+ expect(disabledTab.disabled).toBe(true);
85
+
86
+ disabledTab.click();
87
+ fixture.detectChanges();
88
+
89
+ expect(disabledTab.getAttribute('aria-selected')).toBe('false');
90
+ expect(disabledPanel.hidden).toBe(true);
91
+ });
92
+
93
+ it('moves focus and selection with arrow, Home, and End keys while skipping disabled tabs', () => {
94
+ const [profileTab, settingsTab, billingTab] = tabs();
95
+
96
+ profileTab.focus();
97
+ profileTab.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true }));
98
+ fixture.detectChanges();
99
+ expect(document.activeElement).toBe(settingsTab);
100
+ expect(settingsTab.getAttribute('aria-selected')).toBe('true');
101
+
102
+ settingsTab.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true }));
103
+ fixture.detectChanges();
104
+ expect(document.activeElement).toBe(profileTab);
105
+ expect(profileTab.getAttribute('aria-selected')).toBe('true');
106
+
107
+ profileTab.dispatchEvent(new KeyboardEvent('keydown', { key: 'End', bubbles: true }));
108
+ fixture.detectChanges();
109
+ expect(document.activeElement).toBe(settingsTab);
110
+
111
+ expect(billingTab.disabled).toBe(true);
112
+ });
113
+ });
package/src/tabs/index.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.tabs = void 0;
4
4
  const generate_component_1 = require("../utils/generate-component");
5
- exports.tabs = (0, generate_component_1.createAriaComponentSchematic)();
5
+ exports.tabs = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
6
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,IAAI,GAAG,IAAA,iDAA4B,GAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,IAAI,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
package/src/tabs/index.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { createAriaComponentSchematic } from '../utils/generate-component';
2
2
 
3
- export const tabs = createAriaComponentSchematic();
3
+ export const tabs = createAriaComponentSchematic({ includeSharedUnitTest: false });
@@ -0,0 +1,59 @@
1
+ import { Component } from '@angular/core';
2
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
3
+ import { <%= classify(name) %> } from './<%= dasherize(name) %>';
4
+
5
+ @Component({
6
+ imports: [<%= classify(name) %>],
7
+ template: `
8
+ <<%= selector %>
9
+ label="Message"
10
+ hint="Be concise."
11
+ error="Message is required."
12
+ [required]="true"
13
+ [maxLength]="20"
14
+ [(value)]="message"
15
+ />
16
+ `,
17
+ })
18
+ class HostComponent {
19
+ message = '';
20
+ }
21
+
22
+ describe('<%= classify(name) %>', () => {
23
+ let fixture: ComponentFixture<HostComponent>;
24
+
25
+ beforeEach(async () => {
26
+ await TestBed.configureTestingModule({ imports: [HostComponent] }).compileComponents();
27
+ fixture = TestBed.createComponent(HostComponent);
28
+ fixture.detectChanges();
29
+ });
30
+
31
+ function textarea(): HTMLTextAreaElement {
32
+ return fixture.nativeElement.querySelector('textarea');
33
+ }
34
+
35
+ it('wires label, required state, counter, hint, and error', () => {
36
+ const label = fixture.nativeElement.querySelector('label');
37
+ const hint = fixture.nativeElement.querySelector('.semmet-field__hint');
38
+ const counter = fixture.nativeElement.querySelector('.semmet-field__counter');
39
+ const error = fixture.nativeElement.querySelector('.semmet-field__error');
40
+
41
+ expect(label.getAttribute('for')).toBe(textarea().id);
42
+ expect(textarea().required).toBe(true);
43
+ expect(textarea().getAttribute('aria-required')).toBe('true');
44
+ expect(textarea().getAttribute('aria-invalid')).toBe('true');
45
+ expect(textarea().getAttribute('aria-describedby')).toContain(hint.id);
46
+ expect(textarea().getAttribute('aria-describedby')).toContain(counter.id);
47
+ expect(textarea().getAttribute('aria-describedby')).toContain(error.id);
48
+ expect(counter.textContent).toContain('20 characters left');
49
+ });
50
+
51
+ it('updates the bound value and remaining counter on input', () => {
52
+ textarea().value = 'Hello';
53
+ textarea().dispatchEvent(new Event('input', { bubbles: true }));
54
+ fixture.detectChanges();
55
+
56
+ expect(fixture.componentInstance.message).toBe('Hello');
57
+ expect(fixture.nativeElement.querySelector('.semmet-field__counter').textContent).toContain('15 characters left');
58
+ });
59
+ });
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.textarea = void 0;
4
4
  const generate_component_1 = require("../utils/generate-component");
5
- exports.textarea = (0, generate_component_1.createAriaComponentSchematic)();
5
+ exports.textarea = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
6
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,QAAQ,GAAG,IAAA,iDAA4B,GAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,QAAQ,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import { createAriaComponentSchematic } from '../utils/generate-component';
2
2
 
3
- export const textarea = createAriaComponentSchematic();
3
+ export const textarea = createAriaComponentSchematic({ includeSharedUnitTest: false });
@@ -0,0 +1,48 @@
1
+ import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
2
+ import { <%= classify(name) %> } from './<%= dasherize(name) %>';
3
+
4
+ describe('<%= classify(name) %>', () => {
5
+ let fixture: ComponentFixture<<%= classify(name) %>>;
6
+
7
+ beforeEach(async () => {
8
+ await TestBed.configureTestingModule({ imports: [<%= classify(name) %>] }).compileComponents();
9
+ fixture = TestBed.createComponent(<%= classify(name) %>);
10
+ fixture.detectChanges();
11
+ });
12
+
13
+ function saveButton(): HTMLButtonElement {
14
+ return fixture.nativeElement.querySelector('button');
15
+ }
16
+
17
+ it('starts hidden and shows a status message from the trigger', () => {
18
+ expect(fixture.nativeElement.querySelector('[role="status"]')).toBeNull();
19
+
20
+ saveButton().click();
21
+ fixture.detectChanges();
22
+
23
+ const status = fixture.nativeElement.querySelector('[role="status"]');
24
+ expect(status).toBeTruthy();
25
+ expect(status.textContent).toContain('Your changes have been saved.');
26
+ });
27
+
28
+ it('dismisses manually', () => {
29
+ saveButton().click();
30
+ fixture.detectChanges();
31
+
32
+ const dismissButton = Array.from(fixture.nativeElement.querySelectorAll('button'))[1] as HTMLButtonElement;
33
+ dismissButton.click();
34
+ fixture.detectChanges();
35
+
36
+ expect(fixture.nativeElement.querySelector('[role="status"]')).toBeNull();
37
+ });
38
+
39
+ it('auto-dismisses after the configured delay', fakeAsync(() => {
40
+ saveButton().click();
41
+ fixture.detectChanges();
42
+
43
+ tick(5000);
44
+ fixture.detectChanges();
45
+
46
+ expect(fixture.nativeElement.querySelector('[role="status"]')).toBeNull();
47
+ }));
48
+ });
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.toast = void 0;
4
4
  const generate_component_1 = require("../utils/generate-component");
5
- exports.toast = (0, generate_component_1.createAriaComponentSchematic)();
5
+ exports.toast = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
6
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,KAAK,GAAG,IAAA,iDAA4B,GAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,KAAK,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import { createAriaComponentSchematic } from '../utils/generate-component';
2
2
 
3
- export const toast = createAriaComponentSchematic();
3
+ export const toast = createAriaComponentSchematic({ includeSharedUnitTest: false });
@@ -0,0 +1,45 @@
1
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+ import { <%= classify(name) %> } from './<%= dasherize(name) %>';
3
+
4
+ describe('<%= classify(name) %>', () => {
5
+ let fixture: ComponentFixture<<%= classify(name) %>>;
6
+
7
+ beforeEach(async () => {
8
+ await TestBed.configureTestingModule({ imports: [<%= classify(name) %>] }).compileComponents();
9
+ fixture = TestBed.createComponent(<%= classify(name) %>);
10
+ fixture.detectChanges();
11
+ });
12
+
13
+ function buttons(): HTMLButtonElement[] {
14
+ return Array.from(fixture.nativeElement.querySelectorAll('button'));
15
+ }
16
+
17
+ it('renders a labelled toolbar with roving tabindex', () => {
18
+ const toolbar = fixture.nativeElement.querySelector('[role="toolbar"]');
19
+ const [bold, italic] = buttons();
20
+
21
+ expect(toolbar.getAttribute('aria-label')).toBe('Text formatting');
22
+ expect(bold.textContent?.trim()).toBe('Bold');
23
+ expect(bold.tabIndex).toBe(0);
24
+ expect(italic.tabIndex).toBe(-1);
25
+ expect(bold.getAttribute('aria-pressed')).toBe('false');
26
+ });
27
+
28
+ it('toggles button pressed state on click', () => {
29
+ const [bold] = buttons();
30
+ bold.click();
31
+ fixture.detectChanges();
32
+
33
+ expect(bold.getAttribute('aria-pressed')).toBe('true');
34
+ });
35
+
36
+ it('moves focus with keyboard', () => {
37
+ const [bold, italic] = buttons();
38
+ bold.focus();
39
+ bold.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true }));
40
+ fixture.detectChanges();
41
+
42
+ expect(document.activeElement).toBe(italic);
43
+ expect(italic.tabIndex).toBe(0);
44
+ });
45
+ });
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.toolbar = void 0;
4
4
  const generate_component_1 = require("../utils/generate-component");
5
- exports.toolbar = (0, generate_component_1.createAriaComponentSchematic)();
5
+ exports.toolbar = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
6
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,OAAO,GAAG,IAAA,iDAA4B,GAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,OAAO,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import { createAriaComponentSchematic } from '../utils/generate-component';
2
2
 
3
- export const toolbar = createAriaComponentSchematic();
3
+ export const toolbar = createAriaComponentSchematic({ includeSharedUnitTest: false });
@@ -0,0 +1,56 @@
1
+ import { Component } from '@angular/core';
2
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
3
+ import { By } from '@angular/platform-browser';
4
+
5
+ import { <%= classify(name) %> } from './<%= dasherize(name) %>';
6
+
7
+ @Component({
8
+ imports: [<%= classify(name) %>],
9
+ template: `<<%= selector %> />`,
10
+ })
11
+ class HostComponent {}
12
+
13
+ describe('<%= classify(name) %>', () => {
14
+ let fixture: ComponentFixture<HostComponent>;
15
+ let host: HTMLElement;
16
+
17
+ beforeEach(async () => {
18
+ await TestBed.configureTestingModule({
19
+ imports: [HostComponent],
20
+ }).compileComponents();
21
+
22
+ fixture = TestBed.createComponent(HostComponent);
23
+ fixture.detectChanges();
24
+ host = fixture.nativeElement as HTMLElement;
25
+ });
26
+
27
+ it('wires the trigger to a hidden tooltip description', () => {
28
+ const button = host.querySelector<HTMLButtonElement>('button');
29
+ const tooltip = host.querySelector<HTMLElement>('[role="tooltip"]');
30
+
31
+ expect(button?.getAttribute('aria-describedby')).toBe(tooltip?.id);
32
+ expect(tooltip?.hidden).toBe(true);
33
+ expect(tooltip?.textContent?.trim()).toBe('Tooltip text');
34
+ });
35
+
36
+ it('shows on hover/focus and hides on leave/blur/Escape', () => {
37
+ const buttonDebug = fixture.debugElement.query(By.css('button'));
38
+ const tooltip = host.querySelector<HTMLElement>('[role="tooltip"]');
39
+
40
+ buttonDebug.triggerEventHandler('mouseenter');
41
+ fixture.detectChanges();
42
+ expect(tooltip?.hidden).toBe(false);
43
+
44
+ buttonDebug.triggerEventHandler('mouseleave');
45
+ fixture.detectChanges();
46
+ expect(tooltip?.hidden).toBe(true);
47
+
48
+ buttonDebug.triggerEventHandler('focus');
49
+ fixture.detectChanges();
50
+ expect(tooltip?.hidden).toBe(false);
51
+
52
+ buttonDebug.triggerEventHandler('keydown', new KeyboardEvent('keydown', { key: 'Escape' }));
53
+ fixture.detectChanges();
54
+ expect(tooltip?.hidden).toBe(true);
55
+ });
56
+ });
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.tooltip = void 0;
4
4
  const generate_component_1 = require("../utils/generate-component");
5
- exports.tooltip = (0, generate_component_1.createAriaComponentSchematic)();
5
+ exports.tooltip = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
6
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,OAAO,GAAG,IAAA,iDAA4B,GAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,OAAO,GAAG,IAAA,iDAA4B,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import { createAriaComponentSchematic } from '../utils/generate-component';
2
2
 
3
- export const tooltip = createAriaComponentSchematic();
3
+ export const tooltip = createAriaComponentSchematic({ includeSharedUnitTest: false });
@@ -0,0 +1,84 @@
1
+ import { Component } from '@angular/core';
2
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
3
+ import { By } from '@angular/platform-browser';
4
+
5
+ import { <%= classify(name) %> } from './<%= dasherize(name) %>';
6
+
7
+ @Component({
8
+ imports: [<%= classify(name) %>],
9
+ template: `<<%= selector %> />`,
10
+ })
11
+ class HostComponent {}
12
+
13
+ describe('<%= classify(name) %>', () => {
14
+ let fixture: ComponentFixture<HostComponent>;
15
+ let host: HTMLElement;
16
+
17
+ beforeEach(async () => {
18
+ await TestBed.configureTestingModule({
19
+ imports: [HostComponent],
20
+ }).compileComponents();
21
+
22
+ fixture = TestBed.createComponent(HostComponent);
23
+ fixture.detectChanges();
24
+ host = fixture.nativeElement as HTMLElement;
25
+ });
26
+
27
+ it('renders tree semantics with expanded root and roving tabindex', () => {
28
+ const tree = host.querySelector<HTMLElement>('[role="tree"]');
29
+ const items = Array.from(host.querySelectorAll<HTMLElement>('[role="treeitem"]'));
30
+
31
+ expect(tree?.getAttribute('aria-label')).toBe('Files');
32
+ expect(items.map((item) => item.textContent?.trim())).toEqual([
33
+ 'Documents Resume.pdf Cover Letter.docx',
34
+ 'Resume.pdf',
35
+ 'Cover Letter.docx',
36
+ ]);
37
+ expect(items[0].getAttribute('aria-expanded')).toBe('true');
38
+ expect(items[0].getAttribute('tabindex')).toBe('0');
39
+ expect(items[1].getAttribute('tabindex')).toBe('-1');
40
+ });
41
+
42
+ it('moves focus with arrow keys and collapses/expands branches', () => {
43
+ const getItems = () => Array.from(host.querySelectorAll<HTMLElement>('[role="treeitem"]'));
44
+ let items = getItems();
45
+
46
+ fixture.debugElement.queryAll(By.css('[role="treeitem"]'))[0].triggerEventHandler(
47
+ 'keydown',
48
+ new KeyboardEvent('keydown', { key: 'ArrowDown' }),
49
+ );
50
+ fixture.detectChanges();
51
+
52
+ items = getItems();
53
+ expect(items[0].getAttribute('tabindex')).toBe('-1');
54
+ expect(items[1].getAttribute('tabindex')).toBe('0');
55
+
56
+ fixture.debugElement.queryAll(By.css('[role="treeitem"]'))[1].triggerEventHandler(
57
+ 'keydown',
58
+ new KeyboardEvent('keydown', { key: 'ArrowLeft' }),
59
+ );
60
+ fixture.detectChanges();
61
+
62
+ items = getItems();
63
+ expect(items[0].getAttribute('tabindex')).toBe('0');
64
+
65
+ fixture.debugElement.queryAll(By.css('[role="treeitem"]'))[0].triggerEventHandler(
66
+ 'keydown',
67
+ new KeyboardEvent('keydown', { key: 'ArrowLeft' }),
68
+ );
69
+ fixture.detectChanges();
70
+
71
+ items = getItems();
72
+ expect(items).toHaveLength(1);
73
+ expect(items[0].getAttribute('aria-expanded')).toBe('false');
74
+
75
+ fixture.debugElement.query(By.css('[role="treeitem"]')).triggerEventHandler(
76
+ 'keydown',
77
+ new KeyboardEvent('keydown', { key: 'ArrowRight' }),
78
+ );
79
+ fixture.detectChanges();
80
+
81
+ expect(getItems()).toHaveLength(3);
82
+ expect(getItems()[0].getAttribute('aria-expanded')).toBe('true');
83
+ });
84
+ });