33 * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
44 */
55
6- import { Component , DebugElement } from '@angular/core' ;
6+ import { NgTemplateOutlet } from '@angular/common' ;
7+ import { AfterViewInit , Component , DebugElement , TemplateRef , ViewChild } from '@angular/core' ;
78import { ComponentFixture , TestBed } from '@angular/core/testing' ;
89import { By } from '@angular/platform-browser' ;
910import { NoopAnimationsModule } from '@angular/platform-browser/animations' ;
1011
1112import { NzLabelAlignType } from 'ng-zorro-antd/form/form.directive' ;
1213import { NzFormModule } from 'ng-zorro-antd/form/form.module' ;
14+ import { en_US , NzI18nService } from 'ng-zorro-antd/i18n' ;
1315
1416import { NzFormLabelComponent , NzFormTooltipIcon } from './form-label.component' ;
17+ import { NzRequiredMark } from './types' ;
1518
1619const testBedOptions = { imports : [ NoopAnimationsModule ] } ;
1720
@@ -87,6 +90,136 @@ describe('nz-form-label', () => {
8790 expect ( label . nativeElement . classList ) . toContain ( 'ant-form-item-label-wrap' ) ;
8891 } ) ;
8992 } ) ;
93+
94+ describe ( 'with form required mark integration' , ( ) => {
95+ let fixture : ComponentFixture < NzTestFormLabelRequiredMarkComponent > ;
96+ let testComponent : NzTestFormLabelRequiredMarkComponent ;
97+ let labels : DebugElement [ ] ;
98+ let i18nService : NzI18nService ;
99+
100+ beforeEach ( ( ) => {
101+ TestBed . configureTestingModule ( testBedOptions ) ;
102+ fixture = TestBed . createComponent ( NzTestFormLabelRequiredMarkComponent ) ;
103+ testComponent = fixture . componentInstance ;
104+ i18nService = TestBed . inject ( NzI18nService ) ;
105+ i18nService . setLocale ( en_US ) ;
106+ fixture . detectChanges ( ) ;
107+ labels = fixture . debugElement . queryAll ( By . directive ( NzFormLabelComponent ) ) ;
108+ } ) ;
109+
110+ it ( 'should inherit required mark from form directive when using boolean true' , ( ) => {
111+ const requiredLabel = labels . find ( l => l . nativeElement . classList . contains ( 'required-label' ) ) ;
112+ const optionalLabel = labels . find ( l => l . nativeElement . classList . contains ( 'optional-label' ) ) ;
113+
114+ expect ( requiredLabel ?. nativeElement . querySelector ( 'label' ) . classList ) . toContain ( 'ant-form-item-required' ) ;
115+ expect ( requiredLabel ?. nativeElement . querySelector ( 'label' ) . classList ) . not . toContain (
116+ 'ant-form-item-required-mark-optional'
117+ ) ;
118+ expect ( optionalLabel ?. nativeElement . querySelector ( 'label' ) . classList ) . not . toContain ( 'ant-form-item-required' ) ;
119+ } ) ;
120+
121+ it ( 'should show optional styling when form nzRequiredMark is false' , ( ) => {
122+ testComponent . requiredMark = false ;
123+ fixture . detectChanges ( ) ;
124+
125+ const requiredLabel = labels . find ( l => l . nativeElement . classList . contains ( 'required-label' ) ) ;
126+ const optionalLabel = labels . find ( l => l . nativeElement . classList . contains ( 'optional-label' ) ) ;
127+
128+ expect ( requiredLabel ?. nativeElement . querySelector ( 'label' ) . classList ) . toContain ( 'ant-form-item-required' ) ;
129+ expect ( requiredLabel ?. nativeElement . querySelector ( 'label' ) . classList ) . toContain (
130+ 'ant-form-item-required-mark-hidden'
131+ ) ;
132+ expect ( optionalLabel ?. nativeElement . querySelector ( 'label' ) . classList ) . not . toContain ( 'ant-form-item-required' ) ;
133+ expect ( optionalLabel ?. nativeElement . querySelector ( 'label' ) . classList ) . toContain (
134+ 'ant-form-item-required-mark-hidden'
135+ ) ;
136+ } ) ;
137+
138+ it ( 'should show optional styling when form nzRequiredMark is "optional"' , ( ) => {
139+ testComponent . requiredMark = 'optional' ;
140+ fixture . detectChanges ( ) ;
141+
142+ const requiredLabel = labels . find ( l => l . nativeElement . classList . contains ( 'required-label' ) ) ;
143+ const optionalLabel = labels . find ( l => l . nativeElement . classList . contains ( 'optional-label' ) ) ;
144+
145+ expect ( requiredLabel ?. nativeElement . querySelector ( 'label' ) . classList ) . toContain ( 'ant-form-item-required' ) ;
146+ expect ( requiredLabel ?. nativeElement . querySelector ( 'label' ) . classList ) . toContain (
147+ 'ant-form-item-required-mark-optional'
148+ ) ;
149+ expect ( optionalLabel ?. nativeElement . querySelector ( 'label' ) . classList ) . not . toContain ( 'ant-form-item-required' ) ;
150+ } ) ;
151+
152+ it ( 'should show optional text when nzRequiredMark is "optional" and field is not required' , ( ) => {
153+ testComponent . requiredMark = 'optional' ;
154+ fixture . detectChanges ( ) ;
155+
156+ const requiredLabel = labels . find ( l => l . nativeElement . classList . contains ( 'required-label' ) ) ;
157+ const optionalLabel = labels . find ( l => l . nativeElement . classList . contains ( 'optional-label' ) ) ;
158+
159+ // Required label should NOT show (optional) text
160+ expect ( requiredLabel ?. nativeElement . querySelector ( '.ant-form-item-optional' ) ) . toBeNull ( ) ;
161+
162+ // Optional label should show (optional) text
163+ expect ( optionalLabel ?. nativeElement . querySelector ( '.ant-form-item-optional' ) ) . toBeTruthy ( ) ;
164+ expect ( optionalLabel ?. nativeElement . querySelector ( '.ant-form-item-optional' ) . textContent ?. trim ( ) ) . toBe (
165+ '(optional)'
166+ ) ;
167+ } ) ;
168+
169+ it ( 'should NOT show optional text when nzRequiredMark is false' , ( ) => {
170+ testComponent . requiredMark = false ;
171+ fixture . detectChanges ( ) ;
172+
173+ const requiredLabel = labels . find ( l => l . nativeElement . classList . contains ( 'required-label' ) ) ;
174+ const optionalLabel = labels . find ( l => l . nativeElement . classList . contains ( 'optional-label' ) ) ;
175+
176+ expect ( requiredLabel ?. nativeElement . querySelector ( '.ant-form-item-optional' ) ) . toBeNull ( ) ;
177+ expect ( optionalLabel ?. nativeElement . querySelector ( '.ant-form-item-optional' ) ) . toBeNull ( ) ;
178+ } ) ;
179+
180+ it ( 'should NOT show optional text when nzRequiredMark is true' , ( ) => {
181+ testComponent . requiredMark = true ;
182+ fixture . detectChanges ( ) ;
183+
184+ const requiredLabel = labels . find ( l => l . nativeElement . classList . contains ( 'required-label' ) ) ;
185+ const optionalLabel = labels . find ( l => l . nativeElement . classList . contains ( 'optional-label' ) ) ;
186+
187+ expect ( requiredLabel ?. nativeElement . querySelector ( '.ant-form-item-optional' ) ) . toBeNull ( ) ;
188+ expect ( optionalLabel ?. nativeElement . querySelector ( '.ant-form-item-optional' ) ) . toBeNull ( ) ;
189+ } ) ;
190+
191+ it ( 'should use custom template when provided' , ( ) => {
192+ testComponent . useCustomTemplate = true ;
193+ fixture . detectChanges ( ) ;
194+
195+ const requiredLabel = labels . find ( l => l . nativeElement . classList . contains ( 'required-label' ) ) ;
196+ const optionalLabel = labels . find ( l => l . nativeElement . classList . contains ( 'optional-label' ) ) ;
197+
198+ expect ( requiredLabel ?. nativeElement . querySelector ( '.custom-required' ) ) . toBeTruthy ( ) ;
199+ expect ( requiredLabel ?. nativeElement . querySelector ( '.custom-required' ) . textContent ?. trim ( ) ) . toBe ( 'REQUIRED' ) ;
200+ expect ( optionalLabel ?. nativeElement . querySelector ( '.custom-optional' ) ) . toBeTruthy ( ) ;
201+ expect ( optionalLabel ?. nativeElement . querySelector ( '.custom-optional' ) . textContent ?. trim ( ) ) . toBe ( 'OPTIONAL' ) ;
202+
203+ expect ( requiredLabel ?. nativeElement . querySelector ( '.label-content' ) ) . toBeTruthy ( ) ;
204+ expect ( optionalLabel ?. nativeElement . querySelector ( '.label-content' ) ) . toBeTruthy ( ) ;
205+ } ) ;
206+
207+ it ( 'should handle template context correctly with required and optional labels' , ( ) => {
208+ testComponent . useCustomTemplate = true ;
209+ fixture . detectChanges ( ) ;
210+
211+ const requiredLabelElement = fixture . debugElement . query ( By . css ( '.required-label' ) ) ;
212+ const optionalLabelElement = fixture . debugElement . query ( By . css ( '.optional-label' ) ) ;
213+
214+ const requiredCustom = requiredLabelElement . nativeElement . querySelector ( '.custom-required' ) ;
215+ const optionalCustom = optionalLabelElement . nativeElement . querySelector ( '.custom-optional' ) ;
216+
217+ expect ( requiredCustom ) . toBeTruthy ( ) ;
218+ expect ( optionalCustom ) . toBeTruthy ( ) ;
219+ expect ( requiredCustom . textContent ?. trim ( ) ) . toBe ( 'REQUIRED' ) ;
220+ expect ( optionalCustom . textContent ?. trim ( ) ) . toBe ( 'OPTIONAL' ) ;
221+ } ) ;
222+ } ) ;
90223} ) ;
91224
92225@Component ( {
@@ -112,3 +245,43 @@ export class NzTestFormLabelComponent {
112245 align : NzLabelAlignType = 'right' ;
113246 labelWrap = false ;
114247}
248+
249+ @Component ( {
250+ imports : [ NzFormModule , NgTemplateOutlet ] ,
251+ template : `
252+ <form nz-form [nzRequiredMark]="useCustomTemplate ? customRequiredMarkTemplate : requiredMark">
253+ <nz-form-item>
254+ <nz-form-label class="required-label" nzRequired>
255+ <span class="label-content">Required Field</span>
256+ </nz-form-label>
257+ </nz-form-item>
258+ <nz-form-item>
259+ <nz-form-label class="optional-label">
260+ <span class="label-content">Optional Field</span>
261+ </nz-form-label>
262+ </nz-form-item>
263+ </form>
264+
265+ <ng-template #customRequiredMarkTemplate let-label let-required="required">
266+ @if (required) {
267+ <span class="custom-required">REQUIRED</span>
268+ } @else {
269+ <span class="custom-optional">OPTIONAL</span>
270+ }
271+ <ng-container *ngTemplateOutlet="label" />
272+ </ng-template>
273+ `
274+ } )
275+ export class NzTestFormLabelRequiredMarkComponent implements AfterViewInit {
276+ requiredMark : NzRequiredMark = true ;
277+ useCustomTemplate = false ;
278+
279+ @ViewChild ( 'customRequiredMarkTemplate' , { static : true } )
280+ customRequiredMarkTemplate ! : TemplateRef < { $implicit : TemplateRef < void > ; required : boolean } > ;
281+
282+ ngAfterViewInit ( ) : void {
283+ if ( this . useCustomTemplate ) {
284+ this . requiredMark = this . customRequiredMarkTemplate ;
285+ }
286+ }
287+ }
0 commit comments