前言
这周一直在写数据校验,前台单元测试的时候,有时候v层没有渲染出数据,这时就需要手动让他渲染。
it('should create', () =>
// 如下断言保障了组件在初始化的过程中未发生异常
expect(component).toBeTruthy();
// 模拟生产环境后台异步返回数据
getTestScheduler().flush();
// 保障接收模拟数据后,组件重新渲染未发生异常
fixture.detectChanges();
});
我们可以从潘老师的博客中明白语句的具体含义。但是这还是不够,我们最终确认v层数据渲染了与否还是通过我们肉眼判断的,这就失去了单元测试的意义。为了进一步完善,我们还需要在单元测试中加入断言,断言当前v层成功渲染了数据。
css选择器
要断言当前v层的某一项成功渲染了数据,首先要获取这个v层元素。学习的教程中也有通过table元素和input元素断言的实例。但是我这里获取的是一个div里的值。具体v层代码如下
<div class="row">
<div class="col-md-2 text-right">
<label>科目</label>
</div>
<div class="col-md-8">
{{subject.course?.name}}
</div>
</div>
我们想要断言subject.course.name的值。但是这是一个普通的div,没有什么特殊的属性。这时我就想趁此机会了解一下css选择器。
css选择器可以通过多种形式来获取一个v层的元素,介绍几种常用的。
一、绝对定位
const nameInput: HTMLInputElement = fixture.debugElement.query(By.css('html >
body > div > div > form > input')).nativeElement;
这种定位就是通过一层一层的父子元素关系来找到某一元素,优点是可以准确地找到某一元素。但是,一旦v层相关的元素改变,这里也要跟着变。
二、相对定位
理解了绝对定位,相对定位也就好理解了。
const nameInput: HTMLInputElement = fixture.debugElement.query(By.css('div > table')).nativeElement;
他会匹配所有在某个div下的table元素。
三、属性定位
属性定位又可以分为id定位,class定位和(其他)属性定位。我们在实例中用的就是属性定位。
const nameInput: HTMLInputElement = fixture.debugElement.query(By.css('input[name="name"]')).nativeElement;
expect(nameInput.value).toEqual(student.name);
这里我们就是在匹配一个input元素,且此input的name属性为name。
具体可以看这篇文章:CSS 选择器
使用控制台获得css选择器
我们也可以使用控制台打印某一元素的位置。
找到这个元素,右键copy,有copy selector选项,让我们看看打印出来了什么
#root0 > div:nth-child(1) > div.col-md-8
找到了元素位置,剩下的断言就很好写了。
但是也遇到了点问题。
我先用的实例的代码
const subjectCourseNameDiv: HTMLDivElement = fixture.debugElement.query(By.css('#root0 > div:nth-child(1) > div.col-md-8')).nativeElement;
expect(subjectCourseNameDiv.value).toContain('科目名称');
但是断言总是过不去,说我断言的值为undefined。但是对subjectCourseNameDiv进行打印获取到的元素也没有问题。
这时我想到了input与div的不用,我们input是获取的属性的值比如要这样写
<input type="" name="" value="科目名称XXXX">
而div这么写
<div>科目名称XXXX</div>
一个是属性,一个是里面的值。然后去网上查一查div选择器的写法,不应该是subjectCourseNameDiv.value
,而是subjectCourseNameDiv.innerText
。
整体代码如下。
fit('should create', () => {
expect(component).toBeTruthy();
const subjectCourseNameDiv: HTMLDivElement = fixture.debugElement.query(By.css('#root0 > div:nth-child(1) > div.col-md-8')).nativeElement;
expect(subjectCourseNameDiv.innerText).toBe('');
getTestScheduler().flush();
fixture.autoDetectChanges();
expect(subjectCourseNameDiv.innerText).toContain('科目名称');
});
跑一遍单元测试,成功通过。高兴地提交代码。但是事情没有那么简单。
机器人测试过不去,我整体跑一遍单元测试,却在刚刚写的单元测试上报错,说没有找到对应元素。
我再单独跑这个单元测试,
测试通过。。。
思索一番后,猜测可能由于整体单元测试v层改变,导致找不到元素了。
我们要知道有什么变化。
打印一下这个的selector.
#root158 > div
这个数字是158,应该代表测试的接点数。这样我们写的肯定不对,这时我们可以使用相对定位。删除#root0 >
.
const subjectCourseNameDiv: HTMLInputElement = fixture.debugElement.query(By.css('div:nth-child(1) > div.col-md-8')).nativeElement;
单元测试通过。
总结
css选择器让我感觉到了html的对象化。原来刚学的时候总以为html与后端语言语法完全不一样。但是其实本质是一样的。这应该就是为什么学一种语言而通全部吧。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。