1 | # API Test
|
2 |
|
3 | API testing made simple
|
4 |
|
5 | ## Install
|
6 | `npm install api-test --save-dev`
|
7 |
|
8 | ## Usage
|
9 | Create a test file 'test/api-test/sample.md' to test the 'item/get' endpoint, like this:
|
10 | ```
|
11 | # item/get
|
12 | ## Setup
|
13 | ### item in items
|
14 | name: 'Salad'
|
15 | price: 500
|
16 | ## Invalid request
|
17 | ### Post
|
18 | randomId()
|
19 | ### Out 400
|
20 | error:
|
21 | code: 200
|
22 | ## Valid request
|
23 | ### Post
|
24 | item.id
|
25 | ### Out
|
26 | name: item.name
|
27 | price: item.price
|
28 | ```
|
29 |
|
30 | And in your mocha testing code:
|
31 | ```javascript
|
32 | require('api-test')('test/api-test', {
|
33 | mongoUri: 'mongodb://localhost:27017/api_test',
|
34 | baseUrl: 'http://localhost:8000/'
|
35 | })
|
36 | ```
|
37 |
|
38 | ## Concepts
|
39 | Testing is, at the same time:
|
40 |
|
41 | * *very* great because it lets you trust code is ready for production!
|
42 | * extremely *boring* to write, because test code is dumb and repetitive
|
43 |
|
44 | This module tries to solve this by making testing code more concise and unifying testing and documentation.
|
45 |
|
46 | Markdown was choosen because it's easy to write/read and it's not code!
|
47 |
|
48 | ## Test structure
|
49 | A test is divided in two parts:
|
50 |
|
51 | ### Test setup
|
52 | This is an optional section called 'Setup' that lets you insert documents, declare variables and clear mongo collections to prepare the database before the test cases run.
|
53 |
|
54 | #### Inserting documents
|
55 | The syntax is simply:
|
56 | ```
|
57 | ### _docName_ in _collection_
|
58 | _docDescription_
|
59 | ```
|
60 |
|
61 | At the first insertion in a collection, it will be cleared. This is important to make every test isolated. You may refer to this object by its _docName_.
|
62 |
|
63 | The syntax for _docDescription_ is described bellow.
|
64 |
|
65 | Most of times, documents have a base strucuture with some default fields. You do not need to repeat yourself in this case, see the option `defaultDocuments` bellow.
|
66 |
|
67 | #### Clearing collections
|
68 | The syntax is simply:
|
69 | ```
|
70 | ### Clear _collection_
|
71 | ```
|
72 |
|
73 | Use this only when you won't insert any document in that collection, but want it to be cleared.
|
74 |
|
75 | All documents in that collection will be removed, indexes will be kept
|
76 |
|
77 | #### Declaring variables
|
78 | You can declare and define a variable to use in test cases, db insertions and more:
|
79 | ```
|
80 | ### _varName_ is
|
81 | _variableContent_
|
82 | ```
|
83 |
|
84 | This will make _varName_ available to every following object block.
|
85 |
|
86 | ### Test cases
|
87 | A test case has three optional sections:
|
88 |
|
89 | * `Post`: the JSON body to send by POST. Must start with a header like `### Post [_url_]`. Default: empty JSON object `{}`. The _url_ is optional and defaults to the test name
|
90 | * `Out`: the expected JSON output. Must start with a header like `### Out [_statusCode_]`. Default: no output checking. The _statusCode_ is optional and defaults to 200
|
91 | * `Finds`: optional DB assertions. Must start with a header like `### Find in _collection_`
|
92 |
|
93 | In all cases, the syntax is described bellow
|
94 |
|
95 | ## Skipping test cases
|
96 | By appending ` (skip)` to a test case name (see an [example](https://github.com/clubedaentrega/api-test/blob/master/test/api-test/recursive/user-login.md#wrong-password-skip)) it will be simply ignored. This puts them in a pending state, and is favoured over removing tests which you may forget to add back again.
|
97 |
|
98 | You can also append ` (skip)` to a test file header (see an [example](https://github.com/clubedaentrega/api-test/blob/master/test/api-test/recursive/skip.md)) to skip the whole file.
|
99 |
|
100 | ## Object syntax
|
101 | The syntax was designed to be concise and expressive. The values will be eval'ed as normal JS with a context with special variables (see `default context` bellow).
|
102 |
|
103 | The object can be a simple JS value, like:
|
104 | ```
|
105 | new Date
|
106 | ```
|
107 |
|
108 | Or an object with one property by line and tabs used to declare sub-objects:
|
109 | ```
|
110 | user:
|
111 | name:
|
112 | first: 'Happy'
|
113 | last: 'Customer'
|
114 | age: 37 + 2
|
115 | country: 'cm'.toUpperCase()
|
116 | ```
|
117 |
|
118 | Or mixins, like:
|
119 | ```
|
120 | user with name.first: 'Unhappy'
|
121 | ```
|
122 |
|
123 | Learn more about the syntax in the file [doc-syntax.md](https://github.com/clubedaentrega/api-test/blob/master/doc-syntax.md)
|
124 |
|
125 | ## Default context
|
126 |
|
127 | * `ObjectId()`: the mongo object id constructor
|
128 | * `randomId()`: return a random mongo-id as a 24-hex-char string
|
129 | * `randomStr([len=7], [alphabet=a-zA-Z0-9+/])`
|
130 | * `randomHex([len=7])`
|
131 | * `randomCode([len=7])`
|
132 | * `randomEmail([domain='example.com'])`
|
133 | * `randomUrl([base='http://example.com'])`
|
134 | * `random([min=0],[max=1])`
|
135 | * `randomInt([min=0],[max=100])`
|
136 | * `randomBool()`
|
137 | * `randomDate([interval=1day], [base=now])`
|
138 | * `randomOf(...values)`: return one of its arguments
|
139 | * `empty`: the empty object `{}`
|
140 | * `post`: the request body of the current test case
|
141 | * `out`: the response body of the current test case
|
142 | * `prev`: an object wity keys:
|
143 | * `post`: the request body of the previous request
|
144 | * `out`: the response body of the previous request
|
145 |
|
146 | ## Options
|
147 | * `mongoUri`: the mongo uri to connect to. The hostname SHOULD be 'localhost' and the db name SHOULD contains 'test'. If not, the code will ask for confirmation. This protects one from dropping production data, since the tests automatically clear collections, before inserting docs.
|
148 | * `baseUrl`: the base API url. Every request url will be composed from this base and the test name.
|
149 | * `name`: (optional) the test name (given to root `describe(name, ...)` call)
|
150 | * `defaultDocuments`: (optional) the default structure for documents in each collection. See [issue #1](https://github.com/clubedaentrega/api-test/issues/1) for details
|
151 | * `describe`, `it`, `before`: (optional) the mocha interface. Defaults to global mocha functions
|
152 | * `context`: (optional) define your own variables/functions accessible to object definitions
|
153 | * `recursive`: (optional) whether to look for *.md files inside subfolders (default: false)
|
154 | * `strict`: (optional) whether the output check should be strict and complain about unexpected keys (default: true)
|
155 | * `ca`: (optional) CA certificate (useful when using a self-signed certificate in the server)
|
156 | * `ignoredFindKeys`: (optional) document keys to ignore in finds (default: `['_id', '__v']`)
|
157 | * `filterFile`: (optional) a function that will be called for every file and should return true if this file should be parsed
|
158 | * `preParse`: (optional) a function that will be called with all pre-parsed tokens (Header and Obj). This lets you do crazy stuff with the parsing if you want
|
159 | * for more low-level options, see `index.js`
|
160 |
|
161 | ## Type checking
|
162 |
|
163 | If you don't know the exact value for an API response or field in the collection, you can check for its type:
|
164 | ```
|
165 | ## Testing types
|
166 | ### Post
|
167 | ...
|
168 | ### Out
|
169 | token: String
|
170 | ### Find in users
|
171 | password: String
|
172 | lastLogin: Date
|
173 | ```
|
174 |
|
175 | The valid type values are: `String`, `Number`, `Boolean`, `Object`, `Array`, `Date`, `RegExp`, `ObjectId`.
|
176 |
|
177 | ## Custom context
|
178 | You can use custom context to help writing tests. All default context variables and methods will still be accessible (unless overwritten).
|
179 |
|
180 | For example: if all endpoints return errors like this: `{error: {code: _code_, message: _aDebugString_}}`, you can pass as context:
|
181 | ```javascript
|
182 | options.context = {
|
183 | error: function (code) {
|
184 | return {
|
185 | error: {
|
186 | code: code,
|
187 | message: String
|
188 | }
|
189 | }
|
190 | }
|
191 | }
|
192 | ```
|
193 |
|
194 | And then write a test case like this:
|
195 | ```
|
196 | ## Invalid email should give error 200
|
197 | ### Post
|
198 | user:
|
199 | email: randomEmail()
|
200 | ### Out
|
201 | error(200)
|
202 | ```
|
203 |
|
204 | Instead of repeating yourself with:
|
205 | ```
|
206 | error:
|
207 | code: 200
|
208 | message: String
|
209 | ```
|
210 |
|
211 | ## Examples
|
212 | See more test examples in the folder [test/api-test](https://github.com/clubedaentrega/api-test/tree/master/test/api-test)
|
213 |
|
214 | ## Run test
|
215 | Run `npm test` in the project root folder. |
\ | No newline at end of file |