From c442d75a340d91f3eb830d2ac2e4d58f2babe569 Mon Sep 17 00:00:00 2001
From: Ray <11846445+A77AY@users.noreply.github.com>
Date: Thu, 24 Sep 2026 19:36:38 +0800
Subject: [PATCH] Fix label control logic and add tests for optional struct
presence
---
.../struct-form/struct-form.component.spec.ts | 58 +++++++++++++++++++
.../struct-form/struct-form.component.ts | 2 +-
2 files changed, 59 insertions(+), 1 deletion(-)
create mode 100644 projects/ng-thrift/src/lib/components/thrift-editor/components/struct-form/struct-form.component.spec.ts
diff --git a/projects/ng-thrift/src/lib/components/thrift-editor/components/struct-form/struct-form.component.spec.ts b/projects/ng-thrift/src/lib/components/thrift-editor/components/struct-form/struct-form.component.spec.ts
new file mode 100644
index 000000000..63c580696
--- /dev/null
+++ b/projects/ng-thrift/src/lib/components/thrift-editor/components/struct-form/struct-form.component.spec.ts
@@ -0,0 +1,58 @@
+import { Component, provideZonelessChangeDetection } from '@angular/core';
+import { TestBed } from '@angular/core/testing';
+import { FormControl, ReactiveFormsModule } from '@angular/forms';
+
+import { ThriftData } from '../../../../models';
+import { ThriftAstMetadata } from '../../../../types';
+
+import { StructFormComponent } from './struct-form.component';
+
+@Component({
+ imports: [ReactiveFormsModule, StructFormComponent],
+ template: ``,
+})
+class StructFormHost {
+ control = new FormControl>({});
+ metadata: ThriftAstMetadata[] = [
+ { name: 'test', path: 'test.thrift', ast: { struct: { Parent: [], Empty: [] } } },
+ ];
+ data = new ThriftData(
+ this.metadata,
+ 'test',
+ 'Empty',
+ { name: 'empty', type: 'Empty', option: 'optional' },
+ new ThriftData(this.metadata, 'test', 'Parent'),
+ );
+}
+
+describe('Optional struct presence', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({ providers: [provideZonelessChangeDetection()] });
+ });
+
+ it('checks an empty struct and preserves its value when toggled', async () => {
+ const fixture = TestBed.createComponent(StructFormHost);
+ await fixture.whenStable();
+ const checkbox: HTMLInputElement = fixture.nativeElement.querySelector('input');
+
+ expect(checkbox.checked).toBe(true);
+ expect(fixture.componentInstance.control.value).toEqual({});
+
+ checkbox.click();
+ await fixture.whenStable();
+ expect(fixture.componentInstance.control.value).toBeNull();
+
+ checkbox.click();
+ await fixture.whenStable();
+ expect(fixture.componentInstance.control.value).toEqual({});
+ });
+
+ it.each([null, undefined])('leaves an absent struct unchecked (%s)', async (value) => {
+ const fixture = TestBed.createComponent(StructFormHost);
+ fixture.componentInstance.control.setValue(value);
+ await fixture.whenStable();
+
+ const checkbox: HTMLInputElement = fixture.nativeElement.querySelector('input');
+ expect(checkbox.checked).toBe(false);
+ });
+});
diff --git a/projects/ng-thrift/src/lib/components/thrift-editor/components/struct-form/struct-form.component.ts b/projects/ng-thrift/src/lib/components/thrift-editor/components/struct-form/struct-form.component.ts
index fe727ddaf..b3feb925f 100644
--- a/projects/ng-thrift/src/lib/components/thrift-editor/components/struct-form/struct-form.component.ts
+++ b/projects/ng-thrift/src/lib/components/thrift-editor/components/struct-form/struct-form.component.ts
@@ -116,7 +116,7 @@ export class StructFormComponent>
handleIncomingValue(value: T) {
this.control.patchValue(value as never, { emitEvent: false });
- this.setLabelControl(!!(value && Object.keys(value).length));
+ this.setLabelControl(!isNil(value));
}
override validate(_control: AbstractControl): ValidationErrors | null {