angular - 如何修复 Angular 测试中的“ViewDestroyedError:尝试使用已破坏的视图”错误?
问题描述
首先,有一长串类似的问题(1、2、3、4、5、6、7、8等等),但实际上没有一个问题有适用于我的案例的答案,还有许多其他问题没有得到解答一点也不。
说明和源代码链接
npm run test
从项目目录运行时
- 预期结果:
- 所有测试都通过,没有错误
- 实际行为:
- 在 Chromium 中,测试在下面评论为
// FAILING TEST!
未通过并报告Uncaught Error: ViewDestroyedError: Attempt to use a destroyed view
(链接到真实项目中的 travis 报告) - 在谷歌浏览器中测试通过了,但是如果你打开控制台F12(
- 在 Chromium 中,测试在下面评论为
代码
app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {
hide: boolean = false;
someSubscription: Subscription;
constructor(private appServiceService: AppServiceService) { }
ngOnInit() {
this.someSubscription = this.appServiceService.shouldHide().subscribe(shouldHide => this.hide = shouldHide);
}
ngOnDestroy() {
this.someSubscription.unsubscribe();
}
}
app.component.html
<div class="row" id="jmb-panel" *ngIf="!hide">
Hello
</div>
app.component.spec
describe('AppComponent', () => {
let component: AppComponent;
let componentDe: DebugElement;
let fixture: ComponentFixture<AppComponent>;
const behaviorSubject = new BehaviorSubject<boolean>(false);
const appServiceStub = {
shouldHide: () => { spy.shouldHideSpyFn(); return behaviorSubject.asObservable() }
};
const spy = { shouldHideSpyFn: () => { } };
let spyShouldHide: jasmine.Spy;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [AppComponent],
schemas: [NO_ERRORS_SCHEMA],
providers: [{ provide: AppServiceService, useValue: appServiceStub }]
}).compileComponents();
}));
beforeEach(() => {
behaviorSubject.next(false);
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
componentDe = fixture.debugElement;
fixture.detectChanges();
spyShouldHide = spyOn(spy, 'shouldHideSpyFn');
});
it('should call AppServiceService#shouldHide on init', () => {
component.ngOnInit();
fixture.detectChanges();
expect(spyShouldHide).toHaveBeenCalledTimes(1);
});
it('should not render div if the AppServiceService#shouldHide observables emit true', () => {
appServiceStub.shouldHide().subscribe((li) => {
if (li) {
fixture.detectChanges();
expect(componentDe.query(By.css('#jmb-panel'))).toBeNull();
}
});
behaviorSubject.next(true);
});
// FAILING TEST!
it('should render div if the AppServiceService#shouldHide observables emit true', () => {
appServiceStub.shouldHide().subscribe((li) => {
if (!li) {
fixture.detectChanges();
expect(componentDe.query(By.css('#jmb-panel'))).not.toBeNull('Jumbotron panel should not be null');
}
});
behaviorSubject.next(false);
});
it('should create', () => {
fixture.detectChanges();
expect(component).toBeTruthy();
});
});
补充说明:
在发布的规范中指定测试的顺序很重要!如果更改测试顺序,则所有测试都可能通过。这是不正确的:所有测试都应该独立于它们指定的顺序通过。事实上,在实际项目中,测试是随机失败的:当 jasmine 建立的测试顺序是这样设置的。出于这个原因,我无法通过更改测试顺序来“解决”这个问题。
问题
为什么会发生这个错误,这是什么意思?,更重要的是,
在angular中实现测试时,我们如何避免/修复此错误?
解决方案
您为所有测试创建一个 BehaviorSubject,在其中订阅它并且永远不会取消订阅,以便在执行所有测试时它保持活动状态。
Angular 在每个上运行 TestBed.resetTestingModule() ,beforeEach
这基本上会破坏您的 Angular 应用程序并导致 AppComponent 视图被破坏。但是您的订阅仍然存在。
beforeEach(() => {
behaviorSubject.next(false); (3) // will run all subscriptions from previous tests
...
});
...
// FAILING TEST!
it('should render jumbotron if the user is not logged in', () => {
appServiceStub.shouldHide().subscribe((li) => { // (1)
// will be executed
1) once you've subscribed since it's BehaviorSubject
2) when you call behaviorSubject.next in the current test
3) when you call behaviorSubject.next in beforeEach block
which causes the error since AppComponent has been already destoryed
fixture.detectChanges();
....
});
behaviorSubject.next(false); // (2)
});
要解决该问题,您必须在每个测试中取消订阅,或者不要对所有测试使用相同的主题:
let behaviorSubject;
...
beforeEach(async(() => {
behaviorSubject = new BehaviorSubject<boolean>(false)
TestBed.configureTestingModule({
...
}).compileComponents();
}));
推荐阅读
- android - 如何在 Android Jetpack Compose 中更改特定应用变体的颜色?
- git - git diff:指定不同的荧光笔作为命令行选项
- wpf - 如何在自定义用户控件中为 ListBox ItemTemplate 属性设置适当的上下文
- firebase - Firebase 数据库连接被服务器强行终止:不同区域 #flutter
- javascript - 如何可视化 JavaScript 包装器对象?
- google-apps-script - 如何在脚本中解析关于合并单元格的 html 表
- powershell - 关于powershell文本操作的问题
- java - JAVA:我正在尝试制作一个项目,根据失去的睡眠时间计算给定晚上的智商损失
- php - 奇怪的 php 行为(变量参考)
- typescript - 如何使现有的两个接口变得相等?