Skip to content
This repository has been archived by the owner on Mar 26, 2021. It is now read-only.

Feature/validate pointer #70

Merged
merged 8 commits into from
Oct 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
dist/
node_modules/
yarn.lock
validTypes.md
validTypes.md
package-lock.json
84 changes: 52 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,26 @@

## Getting Started

Install Strest using `yarn`

```bash
# Via Yarn
yarn global add strest-cli
```

Or via `npm`

```bash
# Via npm
npm i -g strest-cli
```

To test something, you have to create a REST-API first. If you already have an API to test, you can skip this step.
```bash
# Via Docker
docker build -t strest:dev .
docker run --env STREST_URL=https://jsonplaceholder.typicode.com -v ${PWD}:/data strest:dev /data/tests/success/Env/
docker run -v ${PWD}:/data strest:dev /data/tests/success/chaining/
```

We'll be using the [postman-echo](https://docs.postman-echo.com) test API in this tutorial.

To get started, create a file called `tutorial.strest.yml` _(The extension needs to be `.strest.yml` or `.strest.yaml`)_
To get started, we're using [this file](tests/success/postman.strest.yml) _(The extension needs to be `.strest.yml` or `.strest.yaml`)_

```yaml
version: 1 # only version at the moment
Expand All @@ -48,31 +51,30 @@ requests: # all test requests will be listed here
# log: true # uncomment this to log the response
```

_No more configuration needed, so you're ready to go!_

To run the test, open your terminal and type

```bash
strest tutorial.strest.yml
strest tests/success/postman.strest.yml
```

You may also run multiple test files at the same time by pointing to the directory, where the files are stored

```yaml
strest # this will recursively search for all .strest.yml files in the cwd and it's subdirectories
# or
strest someDir/
strest tests/success/chaining
```

Success! If you've done everything correctly, you'll get a response like this

```
[ Strest ] Found 1 test file(s)
[ Strest ] Schema validation: 1 of 1 file(s) passed
[ Strest ] Found 2 test file(s)
[ Strest ] Schema validation: 2 of 2 file(s) passed

✔ Testing testRequest succeeded (0.457s)
✔ Testing login succeeded (0.378s)
✔ Testing verify_login succeeded (0.334s)

[ Strest ] ✨ Done in 0.484s
[ Strest ] ✨ Done in 0.757s
```

## Writing .strest.yml test files
Expand All @@ -83,7 +85,7 @@ You can find a full __Documentation__ of how to write tests [here](SCHEMA.md)

- [How to write Tests](SCHEMA.md)
- [Validation Types](VALIDATION.md)
- [Examples](examples/)
- [Examples](tests/success/)
- [Trello Board](https://trello.com/b/lqi6Aj9F)

## Using & Connecting multiple requests
Expand Down Expand Up @@ -149,6 +151,8 @@ As you could see, the usage is very simple. Just use `Value(requestName.jsonKey)

You can use this syntax __*anywhere*__ regardless of whether it is inside of some string like `https://localhost/posts/Value(postKey.key)/...` or as a standalone term like `Authorization: Value(login.token)`

This can also be used across files as demonstrated [here](tests/success/chaining)

## Using random values with Faker

If you need to generate some random values, you are able to do so by using [Faker API](http://marak.github.io/faker.js/) templates.
Expand All @@ -160,7 +164,7 @@ version: 1

requests:
userRequest:
url: http://localhost:3001/user
url: https://postman-echo.com/get
method: GET
data:
params:
Expand All @@ -174,16 +178,18 @@ Visit [Faker.js Documentation](http://marak.github.io/faker.js/) for more method

**Usage**

```bash
export STREST_URL=https://jsonplaceholder.typicode.com
strest tests/success/Env/environ.strest.yml
```

```yaml
version: 1

# ensure the ENV var is set: `export STREST_URL=https://jsonplaceholder.typicode.com`
requests:
userRequest:
url: Env(MY_TEST_URL)/user
environment:
url: Env(STREST_URL)/todos/1
method: GET
data:
params:
fromEnvironment: Env(MY_ENV_VAR)
```

## Replacing values with predefined custom variables
Expand Down Expand Up @@ -228,13 +234,36 @@ requests:
...
validate:
json:
user:
user:
name: Type(String) # name has to be of type String
id: Type(Null | Number | String) # id has to be of type Number, String or Null
iconUrl: Type(String.Url)
someOtherData: "match this string"
```

### JSON Path Validation

```yml
version: 1

requests:
jsonpath:
url: https://jsonplaceholder.typicode.com/posts
method: POST
data:
json:
myArray:
- foo: 1
bar: 1
- foo: 2
bar: 2
validate:
jsonpath:
myArray.1.foo: 2
```

Read [jsonpath](https://github.com/dchester/jsonpath#jpvalueobj-pathexpression-newvalue) for more info and see [this file](tests/success/validate/jsonpath.strest.yml) for more complex example

### Header Validation

```yaml
Expand Down Expand Up @@ -329,15 +358,6 @@ config:

```

## Docker

Use docker instead of setting up node.

```bash
docker build -t strest:dev .
docker run --env testURL=https://jsonplaceholder.typicode.com -v ${PWD}:/data strest:dev /data/tests/success/successRequestEnv.strest.yaml
```

## License

Strest is [MIT Licensed](LICENSE)
30 changes: 29 additions & 1 deletion SCHEMA.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- [`code`](#code)
- [`raw`](#validate)
- [`json`](#validate)
- ['jsonpath'](#validate)
- [`log`](#log)
- [`delay`](#delay)

Expand Down Expand Up @@ -202,8 +203,10 @@ someRequest:
Validate the incoming response either by a specific value or by a [`Type`](VALIDATION.md).
[More information](README.md#ResponseValidation) about how to validate responses.

### `code`
#### `code`

Expect the returned status code to be a specific number or in a range of numbers.

```yaml
# Example (simple)
someRequest:
Expand All @@ -219,6 +222,31 @@ someRequest:
code: 2xx # expect the request to return a response code which is in the range of 200-299
```

#### `jsonpath`

Specify a [jsonpath](https://github.com/dchester/jsonpath#jpvalueobj-pathexpression-newvalue) lookup. The first match from the jsonpath is evaluated. This currently deos not support objects.

```yml
version: 1

requests:
jsonpath:
url: https://jsonplaceholder.typicode.com/posts
method: POST
data:
json:
myArray:
- foo: 1
bar: 1
- foo: 2
bar: 2
validate:
jsonpath:
myArray.1.foo: 2
```

Read [jsonpath](https://github.com/dchester/jsonpath#jpvalueobj-pathexpression-newvalue) for more info and see [this file](tests/success/validate/jsonpath.strest.yml) for more complex example

### `log`

If set to `true`, the following information will be logged into the console for this request.
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "strest-cli",
"version": "1.11.0",
"version": "1.12.0",
"description": "A new dimension of REST API testing",
"main": "dist/main.js",
"repository": "https://github.com/eykhagen/strest",
Expand All @@ -17,12 +17,14 @@
},
"dependencies": {
"@types/faker": "^4.1.3",
"@types/jsonpath": "^0.2.0",
"axios": "^0.18.0",
"chalk": "^2.4.1",
"commander": "^2.17.1",
"faker": "^4.1.0",
"joi": "^13.6.0",
"js-yaml": "^3.12.0",
"jsonpath": "^1.0.0",
"ora": "^3.0.0",
"qs": "^6.5.2",
"recursive-readdir": "^2.2.2"
Expand Down
7 changes: 5 additions & 2 deletions src/configSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ const validateSchema = Joi.object().keys({
code: Joi.alternatives().try(Joi.string(), Joi.number()).optional(),
headers: Joi.object().optional(),
json: Joi.object().optional(),
raw: Joi.alternatives().try(Joi.string().optional(), Joi.string().regex(/^ENV/gmi)).optional()
raw: Joi.alternatives().try(Joi.string().optional(), Joi.string().regex(/^ENV/gmi)).optional(),
jsonpath: Joi.object().optional(),
})
.without('json', 'raw')
.without('raw', 'json');
.without('raw', 'json')
.without('raw', 'jsonpath')
.without('jsonpath', 'raw');

const requestsSchema = Joi.object().keys({
url: Joi.string().required(),
Expand Down
34 changes: 33 additions & 1 deletion src/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as faker from 'faker';
import { colorizeMain, colorizeCustomRed } from './handler';
import { requestObjectSchema as requestObjectSchema } from './configSchema';
import { config } from './configLoader';

import * as jp from 'jsonpath';

/**
* All Data that any request returns, will be stored here. After that it can be used in the following methods
Expand Down Expand Up @@ -444,6 +444,32 @@ const validateResponse = (validateSchema: any, dataToProof: any) => {
return null;
}

/**
* Validate a response with the given schema
* @param validateSchema
* @param response
*/
const validateJp = (validateSchema: any, dataToProof: any) => {
/**
* Example:
* validate:
* jq:
* foo.bar: 1
*/

let proofObject: any = validateSchema;

for (let key in proofObject) {
let value = proofObject[key];
let jsonPathValue = jp.value(dataToProof, key)
if(jsonPathValue === value){
} else {
return validationError(`The JSON response value should have been ${chalk.bold(value)} but instead it was ${chalk.bold(jsonPathValue)}`);
}
}
return null;
}

/**
* Validate a response with the given schema
* @param validateSchema
Expand Down Expand Up @@ -544,6 +570,12 @@ const performRequest = async (requestObject: requestObjectSchema, requestName: s
return { isError: true, message: err, code: 1 }
}
}
if(requestObject.validate.jsonpath){
const err = validateJp(requestObject.validate.jsonpath, response.data);
if(err !== null) {
return { isError: true, message: err, code: 1 }
}
}
if(requestObject.validate.headers){
const err = validateHeaders(requestObject.validate, response.headers);
if(err !== null) {
Expand Down
6 changes: 6 additions & 0 deletions tests/success/Env/environ.strest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 1
# ensure the ENV var is set: `export STREST_URL=https://jsonplaceholder.typicode.com`
requests:
environment:
url: Env(STREST_URL)/todos/1
method: GET
10 changes: 10 additions & 0 deletions tests/success/Fake/name.strest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 1

requests:
userRequest:
url: https://postman-echo.com/get
method: GET
data:
params:
name: Fake(name.firstName) Fake(name.lastName)
log: true
16 changes: 16 additions & 0 deletions tests/success/Value/value.strest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: 1

requests:
value1:
url: https://postman-echo.com/get
method: GET
data:
params:
foo: bar
value2:
url: https://postman-echo.com/get
method: GET
data:
params:
baz: Value(value1.args.foo)
log: true
9 changes: 9 additions & 0 deletions tests/success/chaining/login.strest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,12 @@ requests:
headers:
Authorization: Basic cG9zdG1hbjpwYXNzd29yZA==
method: GET
verify_login:
url: https://jsonplaceholder.typicode.com/posts
method: POST
data:
json:
expect: Value(login.authenticated)
validate:
json:
expect: "true"
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: 1

# This file assumes login.strest.yml was executed.
requests:
verify_login:
verify_login_chained:
url: https://jsonplaceholder.typicode.com/posts
method: POST
data:
Expand Down
6 changes: 0 additions & 6 deletions tests/success/environ.strest.yaml

This file was deleted.

Loading