在 Karma 测试中获取 ExpressionChangedAfterItHasBeenCheckedError

问题描述 投票:0回答:1

我正在尝试在我的一个组件中执行一些测试。我正在使用一个通过管道传输到 ActivatedRoute 的 paramMap 的可观察对象,以便从 URL 获取 guid,并使用 switchMap 将响应中的值分配给组件变量。我的观点是使用 observable 在屏幕上显示数据,当我通过 cli 提供应用程序时,一切似乎都工作正常。

一旦我尝试对组件执行测试,Karma 的浏览器选项卡中就会显示 ExpressionChangedAfterItHasBeenCheckedError

我相信导致错误的原因是我正在更改 isBranded 变量的值,但我需要它在视图中显示正确的徽标。

我的组件代码:

@Component({
    selector: 'app-digital-payment',
    templateUrl: './digital-payment.component.html',
    styleUrls: ['./digital-payment.component.scss']
})
export class DigitalPaymentComponent implements OnInit {
    cdnUrl = environment.cdnUrl;
    isBranded = false;

    payment$: any;

    constructor(private service: DigitalPaymentService, private activeRoute: ActivatedRoute) {

    }

    ngOnInit() {
        this.payment$ = this.activeRoute.paramMap.pipe(switchMap((params: any) => {
            let guid = params.get('guid');

            return this.service.checkPaymentStatus(guid).pipe(map((data: any) => {
                this.isBranded = data.isBranded;

                return data;
            }));
        }));
    }
}

我的看法:

<header>
    <a class="logo">
        <img src="{{ cdnUrl }}/Image/not-branded-logo.svg" alt="Not Branded Logo" />
    </a>
    <a class="logo pull-right text-right" *ngIf="isBranded">
        <img src="{{ cdnUrl }}/Image/branded-logo.svg" alt="Branded Logo" />
    </a>
</header>

<section>
    <div class="payment-status {{ payment.class }}" *ngIf="payment$ | async as payment; else loading">
        <mat-icon *ngIf="payment.icon">{{ payment.icon }}</mat-icon>
        <h1>{{ payment.heading }}</h1>
        <p>{{ payment.text }}</p>
    </div>

    <ng-template #loading>
        <h1 class="loading-heading">Loading</h1>
        <p>Please wait until your request has been executed.</p>
    </ng-template>
</section>

我的服务:

@Injectable({
    providedIn: 'root'
})
export class DigitalPaymentService {
    private apiUrl: string = 'digitalpaymentexternal/';
    private statusBinding = {
        Success: {
            class: 'success',
            icon: 'check_circle_outline',
            heading: 'Successful',
            text: 'Your payment plan has been confirmed.'
        },
        Failed: {
            class: 'fail',
            icon: 'highlight_off',
            heading: 'Transaction failed',
            text: 'Please try a different payment method.'
        },
        Invalid: {
            class: 'fail',
            icon: 'error_outline',
            heading: 'Incorrect link',
            text: 'This link is invalid or it has been expired.'
        }
    };

    constructor(private requester: RequesterService) { }

    checkPaymentStatus(guid): Observable<any> {
        return this.requester.post<void>(this.apiUrl + 'CheckPaymentStatus', guid).pipe(map((data: any) => {
            return { ...this.statusBinding[data.status], isBranded: data.isBranded };
        }));
    }
}

还有我的组件测试代码:

describe('DigitalPaymentComponent', () => {
    let component: DigitalPaymentComponent;
    let fixture: ComponentFixture<DigitalPaymentComponent>;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [DigitalPaymentComponent],
            providers: [
                {
                    provide: DigitalPaymentService,
                    useValue: {
                        checkPaymentStatus: guid => of({ isBranded: true })
                    }
                },
                {
                    provide: ActivatedRoute,
                    useValue: {
                        paramMap: of(convertToParamMap({ guid: '00000000-0000-0000-0000-000000000000' }))
                    },
                },
            ]
        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(DigitalPaymentComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('should create', () => {
        expect(component).toBeTruthy();
    });
});
angular typescript testing karma-jasmine
1个回答
3
投票

可能的解决方案是在

this.cdr.detectChagnes();
ngOnInit()
内添加
ngAfterViewInit()
cdr
指的是
ChangeDetectorRef

constructor(..., private cdr: ChangeDetectionRef) {}

ngOnInit() {
    ...
    // for karma test to avoid ExpressionChangedAfterItHasBeenCheckedError error issue
    this.cdr.detectChagnes();
}
© www.soinside.com 2019 - 2024. All rights reserved.