You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中使用Jest测试实现Control Value Accessor的第三方CDK组件时循环结构转JSON错误的排查与解决

Fixing the Circular Structure Error in Angular ControlValueAccessor Jest Test

Let's break down the issue and fix your test step by step:

What's Causing the Error?

The "Converting circular structure to JSON" error happens because you're incorrectly assigning a FormGroup directly to the component instance (component.cust = new FormGroup(...)). The <customer-file> component implements ControlValueAccessor, so it's designed to bind to a parent form's control via formControlName—not hold its own form group directly. This incorrect setup creates circular references between the form control and the component's internal providers, which Jest can't serialize during testing.

Corrected Test Implementation

We'll use a test host component to mimic how <customer-file> is used in your application—wrapped inside a parent form with a FormGroup that includes the cust control. This properly sets up the ControlValueAccessor binding without circular references.

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms';
import { Component } from '@angular/core';
import { customerFileComponent } from './customer-file.component';
import { FormModule, ButtonModule, NoopAnimationsModule } from 'your-module-path'; // Adjust imports as needed

// Test host component to wrap the customer-file component in a form context
@Component({
  template: `
    <form [formGroup]="parentForm">
      <customer-file formControlName="cust">
        <input type="file" (change)="onFileChange($event)" />
      </customer-file>
    </form>
  `
})
class TestHostComponent {
  parentForm = new FormGroup({
    cust: new FormControl(null)
  });

  onFileChange(event: Event) {
    // Dummy handler for the input's change event
  }
}

describe('customerFileComponent', () => {
  let hostFixture: ComponentFixture<TestHostComponent>;
  let hostComponent: TestHostComponent;
  let customerFileComponent: customerFileComponent;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [TestHostComponent, customerFileComponent],
      imports: [ReactiveFormsModule, FormModule, ButtonModule, NoopAnimationsModule],
    }).compileComponents();
  });

  beforeEach(() => {
    hostFixture = TestBed.createComponent(TestHostComponent);
    hostComponent = hostFixture.componentInstance;
    // Get the customer-file component instance from the host fixture
    customerFileComponent = hostFixture.debugElement.children[0].componentInstance;
    hostFixture.detectChanges();
  });

  it('should create', () => {
    expect(customerFileComponent).toBeTruthy();
  });

  // Example test to verify ControlValueAccessor functionality
  it('should update form control value when file is selected', () => {
    // Simulate a file selection (adjust based on your component's implementation)
    const testFile = new File(['test content'], 'test.txt', { type: 'text/plain' });
    const inputElement = hostFixture.nativeElement.querySelector('input[type="file"]');
    
    // Trigger file change event (Jest requires some setup for file inputs)
    Object.defineProperty(inputElement, 'files', { value: [testFile] });
    inputElement.dispatchEvent(new Event('change'));
    
    hostFixture.detectChanges();
    
    // Verify the form control has the expected value
    expect(hostComponent.parentForm.get('cust')?.value).toBeDefined();
    // Adjust the assertion based on how your component formats the file value
  });
});

Key Fixes Explained:

  1. Test Host Component: We created a wrapper component that uses <customer-file> exactly as it would be in your app—inside a form with a FormGroup and formControlName. This eliminates the circular reference issue.
  2. Removed Incorrect FormGroup Assignment: The line component.cust = new FormGroup(...) is gone, as it was the root cause of the circular structure.
  3. Proper Component Access: We retrieve the <customer-file> instance from the host fixture, ensuring we test the component in its intended context.
  4. Example Functionality Test: Added a test to verify the component correctly updates the form control when a file is selected (adjust this to match your component's specific behavior).

Additional Tips:

  • If you don't want to use a host component, you can directly interact with the ControlValueAccessor interface methods (writeValue, registerOnChange, etc.) on the component instance, but the host component approach is more representative of real-world usage.
  • Ensure all required modules (like ReactiveFormsModule) are imported in the test bed, as ControlValueAccessor relies on Angular's form infrastructure.

内容的提问来源于stack exchange,提问作者Learn AspNet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 23:27:44