2016年10月26日星期三

思考 CSS 架构

你有没有在一个逐渐膨胀的 CSS 项目中感到混乱呢?保持样式风格统一和 HTML 的影响是比较困难的:尽管修改一个较小的问题,都可能创建更多丑陋的 hack,也可能 CSS 的小改变会影响 JavaScript 的功能。但是这些问题能在我们的项目开始的时候静心规划,就能很大程度上避免这些问题。让我们开始说 CSS 架构吧。

思考一个好的架构

一个好的 CSS 架构是具有良好的可扩展性。可扩展性是在任何项目开发中都是具有挑战性的,范围的扩大或者团队人数的增加,这些挑战在 CSS 中也不例外。层级和全局的特性使 CSS 很强大,反之在开发过程中也是脆弱的。如果你写了一段时间 CSS,你会发现当改变一行 CSS 来修复一个功能的时候会破坏一批其他的 CSS 功能,这将让你很头痛。细心的规划能提供下列的好处:

  • 更少的样式
  • 更少的样式冲突
  • 更长的维护周期
  • 更快的提升新团队成员
  • 团队成员之间更容易交流
  • 更平稳的项目交接

CSS 规则的类型

Jonathan Snook 对 CSS 规则进行分类的概念在他的书中很受欢迎 Scalable and Modular Architecture for CSS-可扩展的模块化 CSS 架构(SMACSS)。我们的结构按下面的类型进行分类能够帮助我们以及我们的团队更好的理解每一个样式的用途。我使用 7 种分类来定义规则集合,大多数是基于 SMACSS 推荐的做法,确保每一个风格都适合这些类别之一。

  • 基本样式 (Base Styles)
  • 对象 (Objects)
  • 组件 (Components)
  • 状态 (State)
  • 主题 (Themes)
  • 工具集 (Utilities)
  • JavaScript 勾子 (JavaScript hooks)

理解这些分类和目的,将有助于你写出更高抽象层次的样式。

基本样式 (Base Styles)

基本样式规则是创建在元素上。他们是你的网站想设置的全局默认样式。典型的,包括像:排版、box-sizing、你可能想统一所有浏览器元素的正常值。一个常见的错误,你并不想要太重的基本元素风格,并创建默认值。你真的想移除无序列表的标准强调样式或者只是在某些情况下移除它?

对象 (Objects)

对象规则只关注结构和布局。不被允许修饰类的样式。对象类的概念是 Nicole Sullivan 推广的,为了重用相同结构和布局的页面模式。在你的设计中寻找页面结构的模式,并创建可以在网站的多个组件或部分使用的对象类。通过把这些样式映射为对象类,你就可能避免冗余,减少你的CSS的大小。网格系统,无论是手工编写的或采用的一个框架,都适合使用对象类型。

组件 (Components)

组件是分离的、自成一体的 UI 零件。他们是面包和黄油的原子设计,将组成你的大多数样式。一个组件能小到一个按钮,或大到一个切换。创建鲁棒性的组件的关键是使它们独立于页面的任何其他部分,并自成一体。你应该能把一个组件放到页面的任何位置,它都将保持它的结构和设计。

状态 (State)

状态累是帮助修改一个组件的状态。定义手风琴的展开或收起,链接的有效或无效,元素的隐藏或显示(visible)。在 JavaScript 中常见的添加、删除状态 class。你只能更新一个状态 class 和允许样式像定义的样子,而不是用 JavaScript 去直接操作样式。

主题 (Themes)

主题类只需改变一个组件,使用唯一的颜色、字体或其他装饰。主题类能用来修改整个页面或只是一个的组件。主题不是在每一个项目中都必须的,但当你需要的时候再使用它们。

<blockquote class="c-pullquote t-light">
    <p>A great quote from someone special.</p>
</blockquote>

工具集 (Utilities)

工具集类是单一目的,帮助我们应用一个特殊样式规则。它们能用来修改间隙、增加字体大小、居中文本、添加一个浮动清除 (clearfix),隐藏等等。工具集能帮助你对布局进行微调,像添加组件之间的间隙或者清除浮动。它们也可以用来对现有组件进行微调,而不需要创建一个新的组件。

.u-sp {
    margin-bottom: 1em !important;
}

.u-clearfix:after {
    content: " ";
    display: block;
    clear: both;
    visibility: hidden;
    height: 0;
    font-size: 0;
}

.u-txt-center {
    text-align: center !important;
}

.u-txt-larger {
    font-size: 130% !important;
}
<div class="promo u-sp"></div>
<div class="promo u-sp"></div>
<div class="promo"></div>

JavaScript Hooks

无论什么时候,解除你的 JavaScript 和样式的耦合。将类名既用于样式又用于 DOM 选择的 JavaScript 勾子,当 CSS 被重构的时候,JavaScript 的依赖就不清晰明了。相反,JavaScript 勾子类就是用来专注处理这类问题的。

<button class="btn btn--buy js-buy-now"></button>

类的命名

当你对类进行命名的时候,确保你的名字足够长,能够清晰表达(.pullquote 而不是缩写的 .pq 来表达意思),但是有一些是不需要的(.nav 不用 .navigation)。类命名的可读性能帮助团队成员现在和将来对你表达背后的逻辑的理解有重要的影响。

在编写 CSS 的时候创建具有描述性的、有意义的名称是最棘手的问题,如果能仔细考虑将很有帮助。本文有限不能够对命名的事情讨论得太深入,但是能看一下我们非常棒的文章,命名 CSS 真的很难-Ethan Muller,这篇文章对这个事情讲解得更详细。

BEM 的命名规范

BEM(Block Element Modifier)命名 CSS 组件的方式是非常流行、特别有帮助的规范。该规范来自于俄罗斯的搜索引擎-Yandex。这种命名方式非常简单:

[BLOCK]__[ELEMENT]-[MODIFIER]

你可能使用这种冗长的类名称很不习惯,但在你的项目中使用 BEM 将很快去掉这种担心。下面是一个使用 BEM 来命名组件的例子:

<div class="alert alert--warning">
    <h1 class="alert__title">
        <span class="alert__icon"></span>
        Alert Title
    </h1>
    <p class="alert__description">The password you entered is invalid.</p>
</div>

BEM 命名有三个主要的好处:

  • 可读性:大多数元素的类名使用清晰的描述,能使其他人更容易阅读你的 HTML 或者 CSS 文件。
  • 自描述:使用分等级的类命名,能使它非常清晰的描述这个组件属于哪一个基本组件。
  • 特殊性:它可能在你的组件的每一个元素添加一个类的方式有点过了,但是,通过这样做,你能保持你的每个选择器都有特异性,让覆盖权重更加直接。

命名空间

另外最好的实践就是当命名你的类名的时候,使用命名空间前缀来进行分类。这些前缀会在你的命名前添加一组字符,但是这个值能立刻标记每一个类的目的,在你看 HTML 或者样式的时候是很需要的。我使用下面这些命名空间:

  • 对象类:.o-
  • 组件:.c-
  • 状态类:.is- 或者 .has-
  • 主题:.t-
  • 工具类:.u-
  • JavaScript 勾子:.js-
<footer class="c-footer">
    <div class="o-container-wide">
        <a class="c-footer__logo" href="/">The Assist</a>
        <div class="c-social c-social--follow">
            <div class="c-social__label u-txt-center">Join the conversation</div>
            <ul class="c-social__list">
                <li class="c-social__item"></li>
                <li class="c-social__item is-active"></li>
                <li class="c-social__item"></li>
            </ul>
        </div>
        <p class="c-footer__credit"></p>
    </div>
</footer>

关于更多关于命名空间的信息,可以看 Harry Roberts's post on the subject

代码风格

像其他代码一样,你的 CSS 项目使用一致的编码风格是很重要的。这包括空格,缩进,命名约定,注释,等你能阅读一些好的规范,比如:GoogleGithub 或者 Nicolas Gallagher。使用他们或者创建你自己更适合的规范。

组织代码

对于较好的代码组织,您应该使用预处理工具(SassLessStylus)或者后处理器(PostCSS)去编译你的代码。他们有很多优点,包括一些功能,比如:变量、函数、混淆、导入以及嵌套。这些功能将能让你有更多的方式去组织 CSS 架构,比你只用 CSS 来做更容易。

使用导入,你能将你的样式分解到多个文件中。

@import "variables";
@import "mixins";
@import "normalize";
@import "typography";
@import "headings";
@import "headings";
@import "layout";
@import "carousel";

任何值需要多次使用的时候能定义变量。给你的变量名添加前缀,能帮助识别他们的目的,也为了使代码完成更有用。

// Colors
$c-warning: Red;
$c-primary: Blue;
$c-background: White;

一些变量是需要全局定义的,应该存储在单独的变量文件中,但其他变量只被用于单个的组件,这就应该在使用它们的文件中定义。在 SASS 中,变量可以包含在嵌套的局部范围内。

.alert {
    $background-color: Red;
    $foreground-color: Cream;
    background-color: $background-color;
    color: $foreground-color;
}

注:其实这里准备来应该是 SCSS 语法,因为 SASS 语法是不需要花括号的。

源代码顺序

由于 CSS 层级样式的性质,你的样式顺序可能是一个问题。如果你不确定样式导入的顺序,你将发现你自己始终在级联问题上是头疼的。

最近,Harry Roberts 发布了一篇 a sensible method for ordering your styles (一种使用的排序方法)他称为 ITCSS (Inverted Triangle CSS),目的在于防止命名冲突、特殊性的问题,不好的风格以及无意的回退(可以看他的 Slide in-depth slides)。这个概念很简单:以影响最小范围和最低特殊性的样式规则作为排序的开始,一直到最靠近选择元素的和最高特殊性的样式结尾。这意味着你的变量定义和基本元素规则将总是在最开始,然而你的工具类和 IE hack 将总是在最后。

Harry 定义了七组,适合我们文件应该排序的分组:

  • 设置(Settings):变量和其他设置
  • 工具(Tools):自定义函数和混淆
  • 常用的(Generic):Font-face,box-sizing,normalize 等等
  • 元素(Elements):纯元素默认值,比如标题和链接
  • 对象类(Objects):布局和结构类
  • 组件(Componets):独立组件
  • (Trumps):工具类和其他规则,这意味着在其他一切都是放到最后的
@import "settings.global";
@import "settings.colors";
@import "tools.functions";
@import "tools.mixins";
@import "generic.box-sizing";
@import "generic.normalize";
@import "elements.headings";
@import "elements.links";
@import "objects.wrappers";
@import "objects.grid";
@import "components.nav";
@import "components.buttons";
@import "components.promos";
@import "trumps.utilities";
@import "trumps.ie8";

更深的挖掘

本文只介绍了从深度和广度上大量的主题,但是我希望它能够让你在组织和设计项目中的 CSS 的时候更多的思考。如果你想在以后深入这个主题,这篇文章有大量的资源链接,以及关注更多在这个领域的思想领袖的资源。

这篇文章主要是基于最近在相同主题的分享。能检出 slides for the presentation 或者观看下面的视频。

视频容易挂,这里我直接贴链接,大家可以直接点看在浏览器播放就行了。

https://player.vimeo.com/video/172444121?byline=0&portrait=0

原文出自:https://seesparkbox.com/foundry/thoughtful_css_architecture

2016年10月16日星期日

如何存储 React 组件的数据

主要讲解这几个部分:state、store、static、this、module-global data

前言

随着 React 和 Redux 的到来,一个共同的问题被问到:

我应该将数据保存在 Redux Store 中呢?还是应该保存成本地 state?

其实这个问题是说的不完整( 或者原文说的太简单 ),因为你能在组件中存储数据的方式还有两种:static 和 this.(其实就是静态数据,还是类的实例数据)

让我们来依次讨论一下,你应该在什么时候使用它们。

一、本地 state ( Local state )

ps:下面翻译的时候将 local state => 直接翻译成 state 吧,对于 state 其实的作用域是与组件挂钩的,直接翻译成本地 state 其实是不准确的。

当 React 在第一次被介绍的时候,我们就知道state。我们知道一个很重要的事情,就是当 state 的值改变的时候将触发组件的 re-render(重新渲染)。

这个 state 也能传递给子组件,子组件中通过 props 来获取传递的数据,这就允许你能够将你的组件分为:smart data-components(智能数据组件)and dumb presentational-components (填鸭式组件)。

这里有一个使用 state 来编写的 counter app(计数 APP):

import React from 'react'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      counter: 0
    }
    this.addOne = this.addOne.bind(this)
  }
  
  addOne() {
    this.setState({
      counter: this.state.counter + 1
    })
  }
  
  render() {
    return (
      <div>
        <button
          onClick={ this.addOne }>
          Increment
        </button>
        { this.state.counter }
      </div>
    )
  }
}

export default App

你的数据( counter 的值 )是存储在 App 组件中,也能向下传递给子组件。

& 应用场景

假如 counter 数据在你的 app 中是很重要的,以及这个数据会存储下来用于其他组件,那么你将不希望使用 state 来保存这个值。

这最好的实践是处理用户接口 (UI, User Interface) 的状态数据。比如:使用一个 交互组件 去填写表单,这时候使用 state 是不错的选择。

另外的例子,就是在 UI 交互相关的数据中使用,比如你将在一个列表中记录当前选中的 tab (选项卡)的状态,你就能存储一个 state

在你选择 state 的使用时机,也能够这样考虑:你存储的数据是否会在其他组件中使用。如果一个值是只有一个组件(或者也许只有一个子组件),这时使用 state 来保持这个值(或者说状态)都是安全的。

总结:保持 UI 状态和暂时的数据(比如:表单的输入),能够使用 state

二、Redux store

随着发展,每个人开始选择单向数据流, 我们选择 Redux。

对于 Redux,我们将获得一个全局的 store。这个 store 将绑定在一个最高等级的组件中,然后将 App 的数据流入所有的子组件(其实整个 App 就已经是这个最高等级组件的子组件了)。你能 connect 全局 store,使用:connect wrap 和 mapStateToProps 方法.

首先,人们就将任何事情都交给了 Redux store。比如:Users, modals, forms, sockets...,主要你知道的。

下面是一个和之前相同的计数 App,然后使用了 Redux。主要需要注意的是 counter 数据,使用 mapStateToProps 映射了数据,并且使用 connect 方法包裹组件,this.state.counter 现在就变成了 this.props.counter,然后这个值就是通过全局 store 获取的,这个全局 store 将值传递给当前组件的 props。(如果想知道具体,我在 React.js 模式的文章中有介绍原理)。

import React from 'react'
import { connect } from 'react-redux'
import Actions from './Actions.js'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.addOne = this.addOne.bind(this)
  }
  
  addOne() {
    this.props.dispatch(Actions.addOne())
  }
  
  render() {
    return (
      <div>
        <button
          onClick={ this.addOne }>
          Increment
        </button>
        { this.props.counter }
      </div>
    )
  }
}

const mapStateToProps = store => {
  return {
    counter: store.counter
  }
}

export default connect(mapStateToProps)(App)

现在当你点击按钮的时候,通过一个 action => dispatched 使全局 store 更新。然后这个数据通过外层组件传递到当前组件。

值得注意的是:当 props 被更新的时候,这也将触发组件的 re-render(重新渲染)=> 这与你更新 state 的时候一样。

& 应用场景

对于 Redux store 是很好的保持了除 UI 状态数据外的应用状态。有一个不错的例子,比如用户的登录状态。对于在在登录状态改变的同时,多数组件需要访问这个数据信息做出响应。这些组件(至少有一个被渲染)将需要重新渲染与更新的信息。

Redux 触发事件在你需要跨组件或者跨路由的情况下是很有用的。比如有一个登录弹框,当你的 App 中有多个按钮点击都将触发弹出它的时候。而不是在你需要渲染这个弹框的多个地方做判断,你能通过一个顶层的 App 组件去使用 Redux action 去触发它并且修改 store 的值。

总结:你想将跨组件的保持数据的时候能够使用 store

三、this.

在 React 的开发中,使用 this 来保存数据的场景很少。人们经常忘记了 React 使用的是 JavaScript 的 ES2015 的语法。任何你能够用 JavaScript 做的事情,你都能在 React 做(这也是我非常喜欢 React 的原因呢 0^ freedom)。

下面的例子依然是一个计数应用,与之前的例子有点类似。

import React from 'react'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.counter = 0
    this.addOne = this.addOne.bind(this)
  }
  
  addOne() {
    this.counter += 1
    this.forceUpdate()
  }
  
  render() {
    return (
      <div>
        <button
          onClick={ this.addOne }>
          Increment
        </button>
        { this.counter }
      </div>
    )
  }
}

export default App

我们是在组件中使用 this 存储 counter 变量的值,并且使用 forceUpdate() 方法来触发组件的重新渲染。这是因为没有任何的 state 和 props 修改,因此没有自动触发重新渲染机制。

这个例子实际上不应该使用 this。如果你发现你必须使用 forceUpdate() 才能满足需求,你可能代码哪里出了问题。如果想值修改的时候自动触发重新渲染,你应该使用 state 或者 props/Redux store(其实严格一点来说,作者这里的表述是不清的,其实重新渲染与 Redux 并无关系,本质上就是 props 的更新流入组件)。

& 应用场景

使用 this 来保存数据的时候,能够在改变的时候不需要去触发重新渲染的场景。比如:sockets 是很好的一个使用 this 保存数据的场景。

import React from 'react'
import { Socket } from 'phoenix'

class App extends React.Component {
  componentDidMount() {
    this.socket = new Socket('http://localhost:4000/socket')
    this.socket.connect()
    this.configureChannel("lobby")
  }
  
  componentWillUnmount() {
    this.socket.leave()
  }
  
  configureChannel(room) {
    this.channel = this.socket.channel(`rooms:${room}`)
    this.channel.join()
      .receive("ok", () => {
        console.log(`Succesfully joined the ${room} chat room.`)
      })
      .receive("error", () => {
        console.log(`Unable to join the ${room} chat room.`)
      })
  }
  
  render() {
    return (
      <div>
        My App
      </div>
    )
  }
}

export default App

大多数人们没有他们之前一直在使用 this 定义方法。放你定义 render(),你实际上是:this.prototype.render = function () { },但是这在 ES2015 的 class 语法机制下是隐式的。

总结:在不需要数据改变的时候去触发重新渲染机制的时候,能够使用 this 去保存数据。

四、Static(静态的方式)

静态方法和属性也许是最少使用的(静下来,我知道他们不是真正在 class 下的一个机制),大多数是因为他们没有被频繁使用。但是他们不是很复杂。如果你用过 PropTypes,你就定义了一个 static 属性。

下面有两份代码块实际上是长得一样的。人们经常使用的方式是第一种,第二种是你能使用 static 关键字来定义。

class App extends React.Component {
  render() {
    return (<div>{ this.props.title }</div>)
  }
}

App.propTypes = {
  title: React.PropTypes.string.isRequired
}
class App extends React.Component {
  static propTypes {
    title: React.PropTypes.string.isRequired
  }
  
  render() {
    return (<div>{ this.props.title }</div>)
  }
}

正如你看到的,static 并不复杂。他们是一种另外的方式去声明一个类的值。这主要的不同是 static 不要像 this 那样去实例化一个类再去访问值。

class App extends React.Component {
  constructor() {
    super()
    this.prototypeProperty = {
      baz: "qux"
    }
  }
  static staticProperty = {
    foo: "bar"
  };
  
  render() {
    return (<div>My App</div>)
  }
}

const proto = new App();
const proto2 = proto.prototypeProperty // => { baz: "qux" }

const stat = App.staticProperty // => { foo: "bar" }

在这个例子中,你能看获取 staticProperty 的值,我们只组要直接通过类名去访问,而不是实例后。但是访问 proto.prototypeProperty 就必须要 new App().

& 应用场景

静态方法和属性是很少被使用,主要被用来定义工具方法或者特定类型的所有组件。

propTypes 是一个工具例子,比如一个 Button 组件,每一个按钮的渲染都需要相似的值。

另外个案例就是如果你关注获取的数据。如果你是使用 GraphQL 或者 Falcor,你能具体描述需要服务端返回什么数据。这种方法你能不用接受大量组件不需要的数据。

class App extends React.Component {
  static requiredData = [
    "username",
    "email",
    "thumbnail_url"
  ]
  
  render() {
    return(<div></div>)
  }
}

因此在例子中,在特殊组件请求数据之前,你能使用 App.requiredData 快速获取必要的 query 的值。

总结:你也许几乎不会使用 static 来保存数据。

五、其他方式...

其实是有另一个选择,我没有在标题中说明,因为你不应该这样做:你可以存储在一个全局变量,然后通过一个文件进行导出。

这是一个特别的场景,然后大多数情况下你不应该这样做。

import React from 'react'

let counter = 0

class App extends React.Component {
  constructor(props) {
    super(props)
    this.addOne = this.addOne.bind(this)
  }
  
  addOne() {
    counter += 1
    this.forceUpdate()
  }
  
  render() {
    return (
      <div>
        <button
          onClick={ this.addOne }>
          Increment
        </button>
        { counter }
      </div>
    )
  }
}

export default App

你能够看到和使用 this 是类似的,除了使用的是一个全局的变量。

如果你需要跨组件的共享数据以及保存一个全局变量,大多数更好的是使用 Redux store

总结:不要使用全局变量。

原文出自:https://medium.freecodecamp.com/where-do-i-belong-a-guide-to-saving-react-component-data-in-state-store-static-and-this-c49b335e2a00#.yvhqqxdkh

2016年10月15日星期六

(译)在你的项目中编写测试-TypeScript

前言

这篇文章的原作者感觉有一些不太适合或者过期的地方,已经修正,代码放入了我的 github 中,运行成功后的代码,大家如果能直接下载看懂,就不用看文章了~节约时间嘛,如果想看看文章的可以继续。

测试源码

这篇文章和之前写的 TypeScript + TDD 那篇不一样的是更加简单,直接测试,不需要其他什么多余配置。

开始

TypeScript 是让我着迷的,我最近需要开始准备使用 TypeScript 来编写项目,并且需要测试。在这篇文章中,我将解释如何开始一个简单的测试,在我们使用 TypeScript 来编写的时候,其中,我们能使用 TypeScript 的 import 语法,以及类型接口来帮助我们。

我们有大量的 JavaScript 测试工具和框架,比如:mochajasmine等等。主要是 BDD/TDD 的方式来运行测试。他们能使使用 node 自己的assert(断言)库, 或者其他扩展的断言库,比如 chai。我当前实现选择的是 mocha 和 chai,因为他们和我想要的一样,容易配置和运行 TypeScript 的测试。我是尝试过 Jasmine 但是我不能像我想的那样工作(可能是因为我缺乏如何使用的窍门)。如果能使用 Jasmine 来配置,将是很棒的。

值得注意的是:以下的是跨平台的,因此只要你在代码中看到 $ 标记,表示是运行在你的终端中,比如 Mac 的 TerminalUbuntu/Linux 的 ShellWindows 的 CommandPrompt/PowerShell 之中。

安装开发依赖(development dependencies)

我是使用 mocha 作为我们的测试框架或者测试运行器,以及 chai 作为我们的断言库。我们将使用第三方库 ts-node 帮助我们运行 TypeScript 的测试。我们将它们作为开发依赖进行全局安装。

$ npm install mocha chai ts-node typescript --save-dev

安装类型定义文件(type definitions)

在我们写 TypeScript 测试之前(后面就不这样翻译了,直接翻译成测试吧,比较和语言不想关联太多),对于我们的测试框架和断言库,他们是有点讨厌类型声明,真是这样么?让我们用 typings 来做这个事。尽管你可能用过这个开发 TypeScript。它是一个定义类型的管理者,用来做 TypeScript 的类型判断。让我们现在来安装它:

$ npm install typings --save-dev

现在我们装好了 typings, 让我们开始建立一些必要的类型定义。我们将 mocha 作为全局模块(我们在使用它的时候不需要导入),以及 chai 直接依赖(我们需要在测试中导入它)。我们将从 DefinitelyTyped 安装 mocha 的类型定义,这是一个类型定义的库,然后我们将使用 npm registry 来安装 chai 的类型定义.

/* 不按这种方式了,不好用,使用接下来的方式 */
$ typings install dt~mocha --global --save
$ typings install npm~chai --save

在 TypeScript 2.0 中,我们能够用其他方式来添加类型定义,因此我们也能够用下面的方式来替代之前提到的 typings 安装的方式。新的方式不依赖 typings npm package 或者 module(包和模块).我们将使用下面的命令:

$ npm install @types/chai @types/mocha --save-dev

开始写我们的第一个 TypeScript 测试

为了解释测试,让我写一些基本的 hello world 函数。我只测试一个 function,因此我是指需要创建一个返回 "Hello World" 字符串的函数。

/* src/hello.ts */
export function hello(): string {
  return 'Hello World!';
}

export default hello;

让我们写一个测试,现在我们需要一个测试方法:

/* src/__test__/hello-test.ts */
import hello from '../hello';
import { expect } from 'chai';
import 'mocha';

describe('Hello function', () => {
  it('should return hello world', () => {
    const result = hello();
    expect(result).to.equal('Hello World!');
  });
});

运行我们的测试

让我们使用 nom run test 来运行我们的测试。我们只需要调用 mochats-node。编辑 package.json

{
  "scripts": {
    "test": "./node_modules/.bin/mocha -r ./node_modules/ts-node/register src/__test__/**/*.ts"
  },
}

我只给 mocha 注册了 ts-node,以及最后参数是定义 mocha 应该运行测试的 src 文件夹中的 test.ts。你能够根据你的项目情况进行修改。

简单的测试结果:

测试结果

原文出自:https://journal.artfuldev.com/write-tests-for-typescript-projects-with-mocha-and-chai-in-typescript-86e053bdb2b6#.n41jb19wz