30个最常用CSS选择器解析

2011/10/23 · CSS · 来源:
大范甘迪    
· CSS

你也许已经掌握了id、class、后台选择器这些基本的css选择器。但这远远不是css的全部。下面向大家系统的解析css中30个最常用的选择器,包括我们最头痛的浏览器兼容性问题。掌握了它们,才能真正领略css的巨大灵活性。

1. *

CSS

* { margin: 0; padding: 0; }

1
2
3
4
* {
    margin: 0;
    padding: 0;
   }

星状选择符会在页面上的每一个元素上起作用。web设计者经常用它将页面中所有元素的margin和padding设置为0。
*选择符也可以在子选择器中使用。

CSS

#container * { border: 1px solid black; }

1
2
3
#container * {
     border: 1px solid black;
   }

上面的代码中会应用于id为container元素的所有子元素中。
除非必要,我不建议在页面中过的的使用星状选择符,因为他的作用域太大,相当耗浏览器资源。
兼容浏览器:IE6+、Firefox、Chrome、Safari、Opera

2. #X

CSS

#container { width: 960px; margin: auto; }

1
2
3
4
#container {
      width: 960px;
      margin: auto;
   }

#号作用域有相应id的元素。id是我们最常用的css选择器之一。id选择器的优势是精准,高优先级(优先级基数为100,远高于class的10),
作为javascript脚本钩子的不二选择,同样缺点也很明显优先级过高,重用性差,所以在使用id选择器前,我们最好问下自己,真的到了非用id选择
器的地步? 兼容浏览器:IE6+、Firefox、Chrome、Safari、Opera

3. .X

CSS

.error { color: red; }

1
2
3
.error {
     color: red;
   }

这是一个class(类)选择器。class选择器与id选择器的不同是class选择器能作用于期望样式化的一组元素。
兼容浏览器:IE6+、Firefox、Chrome、Safari、Opera

4. X Y

CSS

li a { text-decoration: none; }

1
2
3
li a {
     text-decoration: none;
   }

这也是我们最常用的一种选择器——后代选择器。用于选取X元素下子元素Y,要留意的点是,这种方式的选择器将选取其下所有匹配的子元素,无视层级,所以有
的情况是不宜使用的,比如上述的代码去掉li下的所有a的下划线,但li里面还有个ul,我不希望ul下的li的a去掉下划线。使用此后代选择器的时候要
考虑是否希望某样式对所有子孙元素都起作用。这种后代选择器还有个作用,就是创建类似命名空间的作用。比如上述代码样式的作用域明显为li。
兼容浏览器:IE6+、Firefox、Chrome、Safari、Opera

5. X

CSS

a { color: red; } ul { margin-left: 0; }

1
2
a { color: red; }
ul { margin-left: 0; }

标签选择器。使用标签选择器作用于作用域范围内的所有对应标签。优先级仅仅比*高。
兼容浏览器:IE6+、Firefox、Chrome、Safari、Opera

6. X:visited和X:link

CSS

a:link { color: red; } a:visted { color: purple; }

1
2
a:link { color: red; }
a:visted { color: purple; }

使用:link伪类作用于未点击过的链接标签。:hover伪类作用于点击过的链接。
兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera

7. X+Y

CSS

ul + p { color: red; }

1
2
3
ul + p {
      color: red;
   }

相邻选择器,上述代码中就会匹配在ul后面的第一个p,将段落内的文字颜色设置为红色。(只匹配第一个元素)
兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera

8. X>Y

CSS

div#container > ul { border: 1px solid black; } <div
id=”container”> <ul> <li> List Item <ul> <li>
Child </li> </ul> </li> <li> List Item
</li> <li> List Item </li> <li> List Item
</li> </ul> </div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
div#container > ul {
     border: 1px solid black;
   }
 
<div id="container">
      <ul>
         <li> List Item
           <ul>
              <li> Child </li>
           </ul>
         </li>
         <li> List Item </li>
         <li> List Item </li>
         <li> List Item </li>
      </ul>
</div>

JavaScript

<span class="Apple-style-span" style="font-family:
Georgia, 'Times New Roman', 'Bitstream Charter',
Times, serif; font-size: 13px; line-height: 19px; white-space:
normal;">子选择器。与后代选择器X
Y不同的是,子选择器只对X下的直接子级Y起作用。在上面的css和html例子中,div#container&gt;ul仅对container中最近一级的ul起作用。从理论上来讲X
&gt; Y是值得提倡选择器,可惜IE6不支持。
兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera</span>

1
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Georgia, &#039;Times New Roman&#039;, &#039;Bitstream Charter&#039;, Times, serif; font-size: 13px; line-height: 19px; white-space: normal;&quot;&gt;子选择器。与后代选择器X Y不同的是,子选择器只对X下的直接子级Y起作用。在上面的css和html例子中,div#container&amp;gt;ul仅对container中最近一级的ul起作用。从理论上来讲X &amp;gt; Y是值得提倡选择器,可惜IE6不支持。 兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera&lt;/span&gt;

9. X ~ Y

CSS

ul ~ p { color: red; }

1
2
3
ul ~ p {
      color: red;
   }

相邻选择器,与前面提到的X+Y不同的是,X~Y匹配与X相同级别的所有Y元素,而X+Y只匹配第一个。
兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera

10. X[title]

CSS

a[title] { color: green; }

1
2
3
a[title] {
      color: green;
   }

属性选择器。比如上述代码匹配的是带有title属性的链接元素。

兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera

11. X[title=foo]

CSS

a[href=”] { color: #1f6053; }

1
2
3
a[href="http://css9.net"] {
     color: #1f6053;
}

属性选择器。 上面的代码匹配所有拥有href属性,且href为 
的所有链接。

这个功能很好,但是多少又有些局限。如果我们希望匹配href包含css9.net的所有链接该怎么做呢?看下一个选择器。
兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera

12. X[title*=css9.net]

CSS

a[href*=”css9.net”] { color: #1f6053; }

1
2
3
a[href*="css9.net"] {
     color: #1f6053;
   }

属性选择器。正如我们想要的,上面代码匹配的是href中包含”css9.net”的所有链接。

兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera

13. X[href^=http]

CSS

a[href^=”http”] { background: url(path/to/external/icon.png)
no-repeat; padding-left: 10px; }

1
2
3
4
a[href^="http"] {
      background: url(path/to/external/icon.png) no-repeat;
      padding-left: 10px;
   }

属性选择器。上面代码匹配的是href中所有以http开头的链接。
兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera

13. X[href$=.jpg]

1
 

CSS

a[href^=”http”] { background: url(path/to/external/icon.png)
no-repeat; padding-left: 10px; }

1
2
3
4
a[href^="http"] {
      background: url(path/to/external/icon.png) no-repeat;
      padding-left: 10px;
   }

JavaScript

<span class="Apple-style-span" style="font-family:
Georgia, 'Times New Roman', 'Bitstream Charter',
Times, serif; font-size: 13px; line-height: 19px; white-space:
normal;">属性选择器。在属性选择器中使用$,用于匹配结尾为特定字符串的元素。在上面代码中匹配的是所有链接到扩展名为.jpg图片的链接。(注意,这里仅仅是.jpg图片,如果要作用于所有图片链接该怎么做呢,看下一个选择器。)</span>

1
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Georgia, &#039;Times New Roman&#039;, &#039;Bitstream Charter&#039;, Times, serif; font-size: 13px; line-height: 19px; white-space: normal;&quot;&gt;属性选择器。在属性选择器中使用$,用于匹配结尾为特定字符串的元素。在上面代码中匹配的是所有链接到扩展名为.jpg图片的链接。(注意,这里仅仅是.jpg图片,如果要作用于所有图片链接该怎么做呢,看下一个选择器。)&lt;/span&gt;

兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera

14. X[data-*=foo]

在上一个选择器中提到如何匹配所有图片链接。如果使用X[href$=.jpg]实现,需要这样做:

CSS

a[href$=”.jpg”], a[href$=”.jpeg”], a[href$=”.png”],
a[href$=”.gif”] { color: red; }

1
2
3
4
5
6
a[href$=".jpg"],
a[href$=".jpeg"],
a[href$=".png"],
a[href$=".gif"] {
     color: red;
  }
1
 

JavaScript

<span class="Apple-style-span" style="font-family:
Georgia, 'Times New Roman', 'Bitstream Charter',
Times, serif; font-size: 13px; line-height: 19px; white-space:
normal;">看上去比较麻烦。另一个解决办法是为所有的图片链接加一个特定的属性,例如‘data-file’</span>

1
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Georgia, &#039;Times New Roman&#039;, &#039;Bitstream Charter&#039;, Times, serif; font-size: 13px; line-height: 19px; white-space: normal;&quot;&gt;看上去比较麻烦。另一个解决办法是为所有的图片链接加一个特定的属性,例如‘data-file’&lt;/span&gt;

html代码

XHTML

<a href=”path/to/image.jpg” data-filetype=”image”> 图片链接
</a>

1
<a href="path/to/image.jpg" data-filetype="image"> 图片链接 </a>

css代码如下:

CSS

a[data-filetype=”image”] { color: red; }

1
2
3
a[data-filetype="image"] {
      color: red;
   }

这样所有链接到图片的链接字体颜色为红色。

兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera

15. X[foo~=bar]

属性选择器。属性选择器中的波浪线符号可以让我们匹配属性值中用空格分隔的多个值中的一个。看下面例子:

html代码

XHTML

<a href=”path/to/image.jpg” data-info=”external image”> Click Me,
Fool </a>

1
<a href="path/to/image.jpg" data-info="external image"> Click Me, Fool </a>

css代码

CSS

a[data-info~=”external”] { color: red; } a[data-info~=”image”] {
border: 1px solid black; }

1
2
3
4
5
6
a[data-info~="external"] {
      color: red;
   }
a[data-info~="image"] {
      border: 1px solid black;
   }

在上面例子中,匹配data-info属性中包含“external”链接的字体颜色为红色。匹配data-info属性中包含“image”的链接设置黑色边框。

兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera

  1. X:checked

checked伪类用来匹配处于选定状态的界面元素,如radio、checkbox。

CSS

input[type=radio]:checked { border: 1px solid black; }

1
2
3
input[type=radio]:checked {
      border: 1px solid black;
   }

上面代码中匹配的是所有处于选定状态的单选radio,设置1px的黑色边框。

兼容浏览器:IE9+、Firefox、Chrome、Safari、Opera

  1. X:after和X:before

这两个伪类与content结合用于在元素的前面或者后面追加内容,看一个简单的例子:

CSS

h1:after {content:url(/i/logo.gif)}

1
h1:after {content:url(/i/logo.gif)}

上面的代码实现了在h1标题的后面显示一张图片。

我们也经常用它来实现清除浮动,写法如下:

CSS

.clearfix:after { content: “”; display: block; clear: both; visibility:
hidden; font-size: 0; height: 0; } .clearfix { *display: inline-block;
_height: 1%; }

1
2
3
4
5
6
7
8
9
10
11
12
.clearfix:after {
       content: "";
       display: block;
       clear: both;
       visibility: hidden;
       font-size: 0;
       height: 0;
      }
.clearfix {
      *display: inline-block;
     _height: 1%;
   }

JavaScript

<strong style="font-family: Georgia, 'Times New
Roman', 'Bitstream Charter', Times, serif; font-size:
13px; line-height: 19px; white-space: normal;"> </strong>

1
&lt;strong style=&quot;font-family: Georgia, &#039;Times New Roman&#039;, &#039;Bitstream Charter&#039;, Times, serif; font-size: 13px; line-height: 19px; white-space: normal;&quot;&gt; &lt;/strong&gt;

JavaScript

<strong style="font-family: Georgia, 'Times New
Roman', 'Bitstream Charter', Times, serif; font-size:
13px; line-height: 19px; white-space: normal;">19.
X:hover</strong>

1
&lt;strong style=&quot;font-family: Georgia, &#039;Times New Roman&#039;, &#039;Bitstream Charter&#039;, Times, serif; font-size: 13px; line-height: 19px; white-space: normal;&quot;&gt;19. X:hover&lt;/strong&gt;

CSS

div:hover { background: #e3e3e3; }

1
2
3
div:hover {
     background: #e3e3e3;
   }

:hover伪类设定当鼠标划过时元素的样式。上面代码中设定了div划过时的背景色。

需要注意的是,在ie 6中,:hover只能用于链接元素。

这里分享一个经验,在设定链接划过时出现下滑线时,使用border-bottom会比text-decoration显得更漂亮些。代码如下:

CSS

a:hover { border-bottom: 1px solid black; }

1
2
3
a:hover {
    border-bottom: 1px solid black;
   }

兼容浏览器:IE6+、Firefox、Chrome、Safari、Opera

20. X:not(selector)

CSS

div:not(#container) { color: blue; }

1
2
3
div:not(#container) {
      color: blue;
   }

否定伪类选择器用来在匹配元素时排除某些元素。在上面的例子中,设定除了id为container的div元素字体颜色为blue。

兼容浏览器:IE9+、Firefox、Chrome、Safari、Opera

21. X::pseudoElement

::伪类用于给元素片段添加样式。比如一个段落的第一个字母或者第一行。需要注意的是,这个::伪类只能用于块状元素。

下面的代码设定了段落中第一个字母的样式:

CSS

p::first-letter { float: left; font-size: 2em; font-weight: bold;
font-family: cursive; padding-right: 2px; }

1
2
3
4
5
6
7
p::first-letter {
      float: left;
      font-size: 2em;
      font-weight: bold;
      font-family: cursive;
      padding-right: 2px;
   }
1
 

JavaScript

<span class="Apple-style-span" style="font-family:
Georgia, 'Times New Roman', 'Bitstream Charter',
Times, serif; font-size: 13px; line-height: 19px; white-space:
normal;">下面的代码中设定了段落中第一行的样式:</span>

1
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Georgia, &#039;Times New Roman&#039;, &#039;Bitstream Charter&#039;, Times, serif; font-size: 13px; line-height: 19px; white-space: normal;&quot;&gt;下面的代码中设定了段落中第一行的样式:&lt;/span&gt;

CSS

p::first-line { font-weight: bold; font-size: 1.2em; }

1
2
3
4
p::first-line {
      font-weight: bold;
      font-size: 1.2em;
  }

兼容浏览器:IE6+、Firefox、Chrome、Safari、Opera

(IE6竟然支持,有些意外啊。)

22. X:nth-child(n)

CSS

li:nth-child(3) { color: red; }

1
2
3
li:nth-child(3) {
      color: red;
   }

这个伪类用于设定一个序列元素(比如li、tr)中的第n个元素(从1开始算起)的样式。在上面例子中,设定第三个列表元素li的字体颜色为红色。

看一个更灵活的用法,在下面例子中设定第偶数个元素的样式,可以用它来实现隔行换色:

CSS

tr:nth-child(2n) { background-color: gray; }

1
2
3
tr:nth-child(2n) {
      background-color: gray;
   }

兼容浏览器:IE9+、Firefox、Chrome、Safari

23. X:nth-last-child(n)

CSS

li:nth-last-child(2) { color: red; }

1
2
3
li:nth-last-child(2) {
      color: red;
   }

与X:nth-child(n)功能类似,不同的是它从一个序列的最后一个元素开始算起。上面例子中设定倒数第二个列表元素的字体颜色。

兼容浏览器:IE9+、Firefox、Chrome、Safari、Opera

24. X:nth-of-type(n)

CSS

ul:nth-of-type(3) { border: 1px solid black; }

1
2
3
ul:nth-of-type(3) {
      border: 1px solid black;
   }

与X:nth-child(n)功能类似,不同的是它匹配的不是某个序列元素,而是元素类型。例如上面的代码设置页面中出现的第三个无序列表ul的边框。

兼容浏览器:IE9+、Firefox、Chrome、Safari

25. X:nth-last-of-type(n)

CSS

ul:nth-last-of-type(3) { border: 1px solid black; }

1
ul:nth-last-of-type(3) { border: 1px solid black; }

与X:nth-of-type(n)功能类似,不同的是它从元素最后一次出现开始算起。上面例子中设定倒数第三个无序列表的边框

兼容浏览器:IE9+、Firefox、Chrome、Safari、Opera

26. X:first-child

:first-child伪类用于匹配一个序列的第一个元素。我们经常用它来实现一个序列的第一个元素或最后一个元素的上(下)边框,如:

CSS

ul:nth-last-of-type(3) { border: 1px solid black; }

1
2
3
ul:nth-last-of-type(3) {
      border: 1px solid black;
   }

兼容浏览器:IE7+、Firefox、Chrome、Safari、Opera

27. X:last-child

CSS

ul > li:last-child { border-bottom:none; }

1
2
3
ul > li:last-child {
      border-bottom:none;
  }

与:first-child类似,它匹配的是序列中的最后一个元素。

兼容浏览器:IE9+、Firefox、Chrome、Safari、Opera

28. X:only-child

CSS

div p:only-child { color: red; }

1
2
3
div p:only-child {
      color: red;
   }

这个伪类用的比较少。在上面例子中匹配的是div下有且仅有一个的p,也就是说,如果div内有多个p,将不匹配。

CSS

<div><p> My paragraph here. </p></div>
<div> <p> Two paragraphs total. </p> <p> Two
paragraphs total. </p> </div>

1
2
3
4
5
6
<div><p> My paragraph here. </p></div>
 
<div>
      <p> Two paragraphs total. </p>
      <p> Two paragraphs total. </p>
</div>

在上面代码中第一个div中的段落p将会被匹配,而第二个div中的p则不会。

兼容浏览器:IE9+、Firefox、Chrome、Safari、Opera

29. X:only-of-type

CSS

li:only-of-type { font-weight: bold; }

1
2
3
li:only-of-type {
      font-weight: bold;
   }

这个伪类匹配的是,在它上级容器下只有它一个子元素,它没有邻居元素。例如上面代码匹配仅有一个列表项的列表元素。

兼容浏览器:IE9+、Firefox、Chrome、Safari、Opera

30. X:first-of-type

:first-of-type伪类与:nth-of-type(1)效果相同,匹配出现的第一个元素。我们来看个例子:

XHTML

<div> <p> My paragraph here. </p> <ul>
<li> List Item 1 </li> <li> List Item 2 </li>
</ul> <ul> <li> List Item 3 </li> <li>
List Item 4 </li> </ul> </div>

1
2
3
4
5
6
7
8
9
10
11
<div>
      <p> My paragraph here. </p>
      <ul>
         <li> List Item 1 </li>
         <li> List Item 2 </li>
      </ul>
      <ul>
         <li> List Item 3 </li>
         <li> List Item 4 </li>
      </ul>
</div>
1
 

JavaScript

<span class="Apple-style-span" style="font-family:
Georgia, 'Times New Roman', 'Bitstream Charter',
Times, serif; font-size: 13px; line-height: 19px; white-space:
normal;">在上面的html代码中,如果我们希望仅匹配List Item
2列表项该如何做呢:</span>

1
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Georgia, &#039;Times New Roman&#039;, &#039;Bitstream Charter&#039;, Times, serif; font-size: 13px; line-height: 19px; white-space: normal;&quot;&gt;在上面的html代码中,如果我们希望仅匹配List Item 2列表项该如何做呢:&lt;/span&gt;

方案一:

CSS

ul:first-of-type > li:nth-child(2) { font-weight: bold; }

1
2
3
ul:first-of-type > li:nth-child(2) {
      font-weight: bold;
  }

方案二:

CSS

p + ul li:last-child { font-weight: bold; }

1
2
3
p + ul li:last-child {
      font-weight: bold;
   }

方案三:

CSS

ul:first-of-type li:nth-last-child(1) { font-weight: bold; }

1
2
3
ul:first-of-type li:nth-last-child(1) {
      font-weight: bold;
   }

兼容浏览器:IE9+、Firefox、Chrome、Safari、Opera。

总结:

如果你正在使用老版本的浏览器,如IE
6,在使用上面css选择器时一定要注意它是否兼容。不过,这不应成为阻止我们学习使用它的理由。在设计时,你可以参考浏览器兼容性列表,也可以通过脚本手段让老版本的浏览器也支持它们。

另一点,我们在使用javascript类库的选择器时,例如jquery,要尽可能的使用这些原生的css3选择器,因为类库的选择器引擎会通过浏览器内置解析它们,这样会获得更快的速度。

 

赞 10 收藏
评论

澳门微尼斯人手机版 1

测试你的前端代码 – part3(端到端测试)

2017/06/05 · 基础技术 ·
测试

原文出处: Gil
Tayar   译文出处:胡子大哈   

上一篇文章《测试你的前端代码 –
part2(单元测试)》中,我介绍了关于单元测试的基本知识,从本文介绍端到端测试(E2E
测试)。

2017 年 20 个最佳的极简 CSS 框架

2017/07/10 · CSS ·
框架

原文出处: HENRI
WIJAYA   译文出处:IT程序狮   

澳门微尼斯人手机版 2

无论是在产品设计,还是在研发上,极简主义的应用简直无处不在。如果你和我一样热衷极简主义,那么本文分享的内容,一定是你的“菜”。在文章中,我们将与大家分享
20 个最佳的极简 CSS
框架,它们能够为你提供建站必备的组件,帮助你节省时间。Have Fun!


端到端测试

在第二部分中,我们使用 Mocha
测试了应用中最核心的逻辑,calculator模块。本文中我们将使用端到端测试整个应用,实际上是模拟了用户所有可能的操作进行测试。

在我们的例子中,计算器展示出来的前端即为整个应用,因为没有后端。所以端到端测试就是说直接在浏览器中运行应用,通过键盘做一系列计算操作,且保证所展示的输出结果都是正确的。

是否需要像单元测试那样,测试各种组合呢?并不是,我们已经在单元测试中测试过了,端到端测试不是检查某个单元是否
ok,而是把它们放到一起,检查还是否能够正确运行。

1. Spectre

澳门微尼斯人手机版 3

这是一个轻量级、响应式的现代 CSS
框架,用于快速建站和扩展程序的开发。它通过最佳编码实践和一致性的设计语言,为排版与元素、基于
Flexbox 的响应布局系统、CSS 组件提供了基本样式。

项目地址:【传送门】

需要多少端到端测试

首先给出结论:端到端测试不需要太多。

第一个原因,如果已经通过了单元测试和集成测试,那么可能已经把所有的模块都测试过了。那么端到端测试的作用就是把所有的单元测试绑到一起进行测试,所以不需要很多端到端测试。

第二个原因,这类测试一般都很慢。如果像单元测试那样有几百个端到端测试,那运行测试将会非常慢,这就违背了一个很重要的测试原则——测试迅速反馈结果。

第三个原因,端到端测试的结果有时候会出现
flaky的情况。Flaky
测试是指通常情况下可以测试通过,但是偶尔会出现测试失败的情况,也就是不稳定测试。单元测试几乎不会出现不稳定的情况,因为单元测试通常是简单输入,简单输出。一旦测试涉及到了
I/O,那么不稳定测试可能就出现了。那可以减少不稳定测试吗?答案是肯定的,可以把不稳定测试出现的频率减少到可以接受的程度。那能够彻底消除不稳定测试吗?也许可以,但是我到现在还没见到过[笑着哭]。

所以为了减少我们测试中的不稳定因素,尽量减少端到端测试。10
个以内的端到端测试,每个都测试应用的主要工作流。

2. Layers

澳门微尼斯人手机版 4

Layers CSS是一个针对实例的 CSS 框架。它具备轻量级、零依赖等特性。

项目地址:【传送门】

写端到端测试代码

好了,废话不多说,开始介绍写端到端代码。首先需要准备好两件事情:1.
一个浏览器;2. 运行前端代码的服务器。

因为要使用 Mocha 进行端到端测试,就和之前单元测试一样,需要先对浏览器和
web 服务器进行一些配置。使用 Mocha 的
before 钩子设置初始化状态,使用
after钩子清理测试后状态。before 和 after
钩子分别在测试的开始和结束时运行。

下面一起来看下 web 服务器的设置。

3. Milligram

澳门微尼斯人手机版 5

Milligram
提供了极简样式设置,便于你快速、简洁的开启建站之旅。虽然它不是一个 UI
框架,但它的设计理念却是以提供优秀的性能、高效的开发效率以及最少的属性重置而构建的。同时,它也是轻量的,在
Gzip 压缩后,它只有 2KB 大小。

项目地址:【传送门】

设置 Web 服务器

配置一个 Node Web 服务器,首先想到的就是
express了,话不多说,直接上代码:

JavaScript

let server before((done) = > { const app = express() app.use(‘/’,
express.static(path.resolve(__dirname, ‘../../dist’))) server =
app.listen(8080, done) }) after(() = > { server.close() })

1
2
3
4
5
6
7
8
9
10
let server
before((done) = > {
    const app = express()
    app.use(‘/’, express.static(path.resolve(__dirname, ‘../../dist’)))
    server = app.listen(8080, done)
})
after(() = > {
    server.close()
})

代码中,before 钩子中创建一个 express 应用,指向 dist
文件夹,并且监听 8080 端口,结束的时候在 after 钩子中关闭服务器。

dist 文件夹是什么?是我们打包 JS 文件的地方(使用 Webpack打包),HTML
文件,CSS 文件也都在这里。可以看一下 package.json 的代码:

JavaScript

{ “name”: “frontend-testing”, “scripts”: { “build”: “webpack && cp
public/* dist”, “test”: “mocha ‘test/**/test-*.js’ && eslint test
lib”, … },

1
2
3
4
5
6
7
{
      "name": "frontend-testing",
      "scripts": {
        "build": "webpack && cp public/* dist",
        "test": "mocha ‘test/**/test-*.js’ && eslint test lib",
    …
      },

对于端到端测试,要记得在执行 npm test 之前,先执行
npm run build。其实这样很不方便,想一下之前的单元测试,不需要做这么复杂的操作,就是因为它可以直接在
node 环境下运行,既不用转译,也不用打包。

出于完整性考虑,看一下 webpack.config.js 文件,它是用来告诉 webpack
怎样处理打包:

JavaScript

module.exports = { entry: ‘./lib/app.js’, output: { filename:
‘bundle.js’, path: path.resolve(__dirname, ‘dist’) }, … }

1
2
3
4
5
6
7
8
module.exports = {
    entry: ‘./lib/app.js’,
    output: {
        filename: ‘bundle.js’,
        path: path.resolve(__dirname, ‘dist’)
    },
    …
}

上面的代码指的是,Webpack 会读取 app.js 文件,然后将 dist
文件夹中所有用到的文件都打包到 bundle.js 中。dist
文件夹会同时应用在生产环境和端到端测试环境。这里要注意一个很重要的事情,端到端测试的运行环境要尽量和生产环境保持一致。

4. Cutestrap

澳门微尼斯人手机版 6

如果你在寻找功能丰富的组件,那么 Bootstrap、Foundation
这类框架将会是你的最佳选择。但是,如果你想选择的框架大小是在
normalize.css 与一个完整框架范围之间, Cutestrap
或许是个不错的选择。它在压缩后仅有 8K 大小,可作为 Bootstrap
的轻量级替代方案。

项目地址:【传送门】

设置浏览器

现在我们已经设置完了后端,应用已经有了服务器提供服务了,现在要在浏览器中运行我们的计算器应用。用什么包来驱动自动执行程序呢,我经常使用
selenium-webdriver,这是一个很流行的包。

首先看一下如何使用驱动:

JavaScript

const { prepareDriver, cleanupDriver } =
require(‘../utils/browser-automation’) //… describe(‘calculator app’,
function () { let driver … before(async() = > { driver = await
prepareDriver() }) after(() = > cleanupDriver(driver)) it(‘should
work’, async function () { await driver.get(”)
//… }) })

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const {
    prepareDriver, cleanupDriver
} = require(‘../utils/browser-automation’)
//…
describe(‘calculator app’, function () {
    let driver
        …
    before(async() = > {
        driver = await prepareDriver()
    })
    after(() = > cleanupDriver(driver))
    it(‘should work’, async
    function () {
        await driver.get(‘http://localhost:8080’)
        //…
    })
})

before 中,准备好驱动,在 after
中把它清理掉。准备好驱动后,会自动运行浏览器(Chrome,稍后会看到),清理掉以后会关闭浏览器。这里注意,准备驱动的过程是异步的,返回一个
promise,所以我们使用 async/await
功能来使代码看起来更美观(Node7.7,第一个本地支持 async/await 的版本)。

最后在测试函数中,传递网址:http:/localhost:8080,还是使用 await,让
driver.get 成为异步函数。

你是否有好奇 prepareDrivercleanupDriver
函数长什么样呢?一起来看下:

JavaScript

const webdriver = require(‘selenium-webdriver’) const chromeDriver =
require(‘chromedriver’) const path = require(‘path’) const
chromeDriverPathAddition = `: $ { path.dirname(chromeDriver.path) }`
exports.prepareDriver = async() = > { process.on(‘beforeExit’, () =
> this.browser && this.browser.quit()) process.env.PATH +=
chromeDriverPathAddition return await new webdriver.Builder()
.disableEnvironmentOverrides() .forBrowser(‘chrome’) .setLoggingPrefs({
browser: ‘ALL’, driver: ‘ALL’ }) .build() } exports.cleanupDriver =
async(driver) = > { if (driver) { driver.quit() } process.env.PATH =
process.env.PATH.replace(chromeDriverPathAddition, ”) }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const webdriver = require(‘selenium-webdriver’)
const chromeDriver = require(‘chromedriver’)
const path = require(‘path’)
const chromeDriverPathAddition = `: $ {
    path.dirname(chromeDriver.path)
}`
exports.prepareDriver = async() = > {
    process.on(‘beforeExit’, () = > this.browser && this.browser.quit())
    process.env.PATH += chromeDriverPathAddition
    return await new webdriver.Builder()
        .disableEnvironmentOverrides()
        .forBrowser(‘chrome’)
        .setLoggingPrefs({
        browser: ‘ALL’,
        driver: ‘ALL’
    })
        .build()
}
exports.cleanupDriver = async(driver) = > {
    if (driver) {
        driver.quit()
    }
    process.env.PATH = process.env.PATH.replace(chromeDriverPathAddition, ”)
}

可以看到,上面这段代码很笨重,而且只能在 Unix
系统上运行。理论上,你可以不用看懂,直接复制/粘贴到你的测试代码中就可以了,这里我还是深入讲一下。

前两行引入了 webdriver 和我们使用的浏览器驱动 chromedriver。Selenium
Webdriver 的工作原理是通过 API(第一行中引入的
selenium-webdriver)调用浏览器,这依赖于被调浏览器的驱动。本例中被调浏览器驱动是
chromedriver,在第二行引入。

chrome driver 不需要在机器上装了 Chrome,实际上在你运行 npm install
的时候,已经装了它自带的可执行 Chrome 程序。接下来 chromedriver
的目录名需要添加进环境变量中,见代码中的第 9
行,在清理的时候再把它删掉,见代码中第 22 行。

设置了浏览器驱动以后,我们来设置 web driver,见代码的 11 – 15 行。因为
build 函数是异步的,所以它也使用
await。到现在为止,驱动部分就已经设置完毕了。

5. Mobi

澳门微尼斯人手机版 7

Mobi.css 是一个轻量级、可扩展、移动优先的 CSS
框架。它专注于细节,对于内容丰富的网页能够提供优质的用户体验。虽然,它专注移动端,但桌面客户端的体验也是很棒的。

项目地址:【传送门】

测试吧!

设置完驱动以后,该看一下测试的代码了。完整的测试代码在这里,下面列出部分代码:

JavaScript

// … const retry = require(‘promise-retry’) // … it(‘should work’,
async function () { await driver.get(”) await
retry(async() = > { const title = await driver.getTitle()
expect(title).to.equal(‘Calculator’) }) //…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// …
const retry = require(‘promise-retry’)
// …
it(‘should work’, async
function () {
    await driver.get(‘http://localhost:8080’)
    await retry(async() = > {
        const title = await driver.getTitle()
        expect(title).to.equal(‘Calculator’)
    })
    //…

这里的代码调用计算器应用,检查应用标题是不是 “Calculator”。代码中第 6
行,给浏览器赋地址:http://localhost:8080,记得要使用 await。再看第
9 行,调用浏览器并且返回浏览器的标题,在第 10 行中与预期的标题进行比较。

这里还有一个问题,这里引入了 promise-retry
模块进行重试,为什么需要重试?原因是这样的,当我们告诉浏览器执行某命令,比如定位到一个
URL,浏览器会去执行,但是是异步执行。浏览器执行的非常快,这时候对于开发人员来讲,确切地知道浏览器“正在执行”,要比仅仅知道一个结果更重要。正是因为浏览器执行的非常快,所以如果不重试的话,很容易被
await 所愚弄。在后面的测试中 promise-retry
也会经常使用,这就是为什么在端到端测试中需要重试的原因。

6. Hack

澳门微尼斯人手机版 8

Hack 是一个极度简易的 CSS
框架。这有一些示例,你可以了解下。

项目地址:【传送门】

发表评论

电子邮件地址不会被公开。 必填项已用*标注