Skip to content

snowyu/api-bdd-test.js

Repository files navigation

API BDD Test

Use the BDD(Cucumber) to test the RESTful API.

Installation

  1. Install in your project:

    npm install --save-dev api-bdd-test mocha chai supertest loopback-supertest

  2. mkdir test in your project root folder

  3. generate the mocha.opts file in the test folder:

    --timeout 10000
    --ui spec
    --growl
    --colors
    node_modules/api-bdd-test/index.js
    
  • Or run mocha --ui spec node_modules/api-bdd-test/index.js directly.
  1. generate the .api-bdd-test.json|.cson|.yml in the root folder or test folder:

    language: English
    server: "http://localhost:3000"
    root: "/api"
    libs: "./libs"
    steps: "./steps"
    features: "./features"

The feature specifications in the features folder for reading and testing. The language is the default bdd language used in the specifications. The server is the api server default url. The libs, steps and features are the folders to store. the defauls is to in the test folder.

Usage

  • test
    • ./features
      • a.feature
    • ./steps
      • a.steps.js
      • b-step.js
    • ./libs
      • some.lib.js
      • some.dict.js

features

  • tag with @only before the scenario to execute the scenario only.
  • tag with @pending before the scenario to stop the scenario.
  • tag with @before before the scenario to turn the scenario to a before feature hook.
  • tag with @after before the scenario to turn the scenario to a after feature hook.
  • tag with @beforeEach before the scenario to turn the scenario to a before each scenario hook.
  • tag with @afterEach before the scenario to turn the scenario to a after each scenario hook.
  • tag with @beforeStep before the scenario to turn the before each step hook.
  • tag with @afterStep before the scenario to turn the after each step hook.
@only
Scenario Calc two value

language supports with:

  • File name postfix: a.english.feature
  • first line of the file: # language: English

the server, root/app, resource could be setting in .api-bdd-test.json|.cson|.yml file. Or as the annotations in a feature file.

the genernal api steps:

  • /(GET|HEAD|DEL(?:ETE)?)\s+$string/
  • /(GET|HEAD|DEL(?:ETE)?|POST|PATCH|PUT)\s+$string[:]\n$object/
    • the object is cson format
    • data: send to
    • heads:
    • type: accepting the canonicalized MIME type name complete with type/subtype, or simply the extension name such as "xml", "json", "png", etc, defaults to 'json'
    • queries:
    • fields:
    • accepts:
    • attachments:
    • explain to see http://visionmedia.github.io/superagent/
  • /(?:last|prev(?:ious)?)\\s+results?\s+(?:should\s+)?(be|is|are|includes?)\n$object/
  • /(?:last|prev(?:ious)?)\s+status\s*(?:code)?\\s*(?:should\\s+)?((?:be|is)(?:n't|\s+not)?)\s*[:]?\s*$integer/
  • keep the result.body.id to 'myvar'

eg,

Feature: Standard API Test

@before
Scenario: empty data before feature running
  Given DELETE "bottle"

Scenario: POST and Get result

  # POST 'http://127.0.0.1:3000/api/bottle'
  # with data
  #
  Given POST "bottle":
  ----
  type: 'json'
  data:
    id: 10
    a: 13
  ----
  Then The last status code should be: 200
  And The last status code should be not: 400
  And The last result should be:
  ----
  id: 10
  a: 13
  ----
  And keep the result of "body.id" to "myid"
  And keep the `result.body.id` to "myid1"
  And keep the result to "myres"
  And expect the stored `myid` equal 10
  And expect the stored `myid1` equal 10
  And expect the stored `myid` is not equal 0
  And expect the kept `myid` least 1

the genernal Chinese api steps:

  • 新建资源:"resource",其内容为\n$object
  • 编辑(ID|编号)是:"the-id"的资源:"resource",其内容为\n$object
  • 删除(ID|编号)是:"the-id"的资源:"resource"
  • 检[查测]是否存在资源\\s*[::]?[(( ]$identifier(?:[)) ]\\s*[,,.。])?\\s*[::]?$string
  • /上次[的]?(?:状态[码]?|status)[为是::]\s*$identifier/
  • /上次[的]?(?:结果|body)([为是::]|包[括含][::]?)\s*\n$object/
  • (?:获[取得]|取[得]?)(?:id|ID|编号)[为是::]?$string的?资源\\s*[::]?[((]?$identifier(?:[))]?\\s*[,,.。])?[的其]?(?:内容|结果)[为是]?\\n$object
  • (?:获[取得]|取得?)资源\\s*[::]?[((]?$identifier(?:[))]?\\s*[,,.。])?\\s*[::]?$string
  • ([不]?会?存在|没有?|有)(?:id|ID|编号)[为是::]?$string的?资源\\s*[::]?[((]?$identifier(?:[))]?\\s*[,,.。])?
  • /登[录陆]\s*用户[::]\s*$string\s*[,,]\s*密码[::]\s*$string/
  • /注销用户|退出系统/
  • /(?:记[住下忆]?|保[存留])结果的(?:属性)?$string到[::]?$string/
  • 记住结果到"myvar"
  • 保存的"mvar"等于xxx
  • /(不?存在)(?:记[住下忆]?|保[存留]的)?\s*$string$/
  • 列[出举]资源\\s*[::]?[(( ]$identifier(?:[)) ]\\s*[,,.。])?
  • [搜查][索询找]资源\\s*'+resNameRegEx+'按?(?:指定|如下)?(?:条件|设置)[::]?$object
  • 记住`result.body[0].id`到"myvar"
  • 获得id为"id",过滤条件为"xxx"的资源: bottle

steps and libs

The all scripts in the libs folder will be loaded. The a.steps.js script in the steps folder will be loaded for a.feature. The steps script file extend name should be end with [.-]step[s]?\\.(js|coffee)

The libs script(extend name should be end with[.-](lib[s]?|dict[s]?)\.(js|coffee)) should be like this:

var Dictionary = Yadda.Dictionary;
var converters = Yadda.converters;

module.exports = function(dictionary){
  dictionary
  .define('integer', /(\d+)/, converters.integer);

  this
  .define('Expect $integer to be an integer', function(i, next) {
    assert.equal(typeof i, 'number');
    assert(i % 1 === 0);
    next();
  });
}

The steps script(file name should be #{featureName}(.#{lang})?.step[s]?.(js|coffee)) should be like this:

//the `this` is the Yadda.Library() (bind to current language)
//the dict is the Yadda.Dictionary()
module.exports = function(dict){
  this.given("$integer green bottles are standing on the wall", function(number_of_bottles) {
    wall = new Wall(number_of_bottles);
    wall.printStatus();
   })
  .when("$integer green bottle accidentally falls", function(number_of_falling_bottles) {
      wall.fall(number_of_falling_bottles);
      console.log("%s bottle falls", number_of_falling_bottles);
  })
  .then("there are $integer green bottles standing on the wall", function(number_of_bottles) {
      assert.equal(number_of_bottles, wall.bottles);
      wall.printStatus();
  });
}

limits

  • no back ref in regexp.
  • no optional group on $xxx defininition. eg, $string? should be wrong.
  • report the <-- Undefined Step error:
    1. Duplication Regexp Step
    2. Optional Group in the regexp step.

History

V0.5.1

  • [Broken] the resNameRegEx(Chinese) force use limiter to get the identifier.

V 0.4.0

  • Add Special Scenarios
    • add the before/after annotations for feature hook
    • add the beforeEach/afterEach annotations for Scenario hook
    • add the beforeStep/afterStep annotations for step hook

V 0.3.0

  • referernce the variaible which stored by steps. use the "``" delimiter instead.
    • it's an one line coffee-script code in this delimiter.
      • \"#{myid}"``

TODO

About

Use the BDD(Cucumber) to test the RESTful API.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published