├── test
├── .gitkeep
└── lib
│ ├── core
│ ├── test.txt
│ ├── mergeHeaders.spec.js
│ └── output.spec.js
│ └── utils
│ └── mixin.spec.js
├── .gitignore
├── .travis.yml
├── index.js
├── .editorconfig
├── lib
├── utils
│ ├── checkFunctionReturnFalse.js
│ └── mixin.js
├── core
│ ├── RequestElement.js
│ ├── printError.js
│ ├── printHead.js
│ ├── request.js
│ ├── mergeHeaders.js
│ ├── work.js
│ ├── filterQueue.js
│ ├── outputResult.js
│ └── printResult.js
├── const
│ └── defaultHeaders.js
├── api
│ ├── done.js
│ └── push.js
└── reqman.js
├── examples
├── getHelloworld.js
├── getGithub.js
├── getSimple.js
├── getOutput.js
├── getInvalid.js
├── post.js
└── getValid.js
├── server
└── server.js
├── LICENSE
├── package.json
├── Readme_cn.md
└── README.md
/test/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/lib/core/test.txt:
--------------------------------------------------------------------------------
1 | testtest
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | coverage
3 | .idea
4 | npm-debug.log
5 | package-lock.json
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "8"
4 | script:
5 | - npm run test
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Reqman
3 | * Copyright(c) 2018 Lisniuse
4 | * MIT Licensed
5 | */
6 |
7 | 'use strict';
8 |
9 | module.exports = require('./lib/reqman');
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | charset = utf-8
4 | indent_style = space
5 | indent_size = 4
6 | end_of_line = lf
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 |
--------------------------------------------------------------------------------
/test/lib/core/mergeHeaders.spec.js:
--------------------------------------------------------------------------------
1 | const mergeHeaders = require('../../../lib/core/mergeHeaders')
2 |
3 | console.log(mergeHeaders({
4 | A: 1
5 | },{
6 | B: 2
7 | },{
8 | c: 3
9 | }));
--------------------------------------------------------------------------------
/test/lib/utils/mixin.spec.js:
--------------------------------------------------------------------------------
1 | const mixin = require('../../../lib/utils/mixin')
2 |
3 | class Test {
4 | constructor() {
5 | this.a = 1
6 | }
7 | }
8 |
9 | mixin(Test, "public", "b", function () {
10 | return this.a;
11 | });
12 | let test = new Test();
13 | console.log(test.b());
--------------------------------------------------------------------------------
/lib/utils/checkFunctionReturnFalse.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 |
3 | /**
4 | * @description Check that a function returns false.
5 | * @return {Void}
6 | */
7 |
8 | function checkFunctionReturn(fn) {
9 | return fn.toString().includes('return false');
10 | }
11 |
12 | module.exports = checkFunctionReturn;
13 |
--------------------------------------------------------------------------------
/test/lib/core/output.spec.js:
--------------------------------------------------------------------------------
1 | const outputResult = require('../../../lib/core/outputResult');
2 | const RequestElement = require('../../../lib/core/RequestElement');
3 |
4 | let requestElement = new RequestElement({
5 | name: 'a',
6 | result: 'test'
7 | })
8 |
9 | outputResult(requestElement, './test.txt')
10 |
--------------------------------------------------------------------------------
/lib/core/RequestElement.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Represents the request element in the request chain.
3 | */
4 |
5 | class RequestElement {
6 | constructor(options = {}) {
7 | this.name = options.name || '';
8 | this.optionsFn = options.optionsFn || '';
9 | this.options = options.options || {};
10 | this.result = options.result || {};
11 | this.output = '';
12 | }
13 | }
14 |
15 | module.exports = RequestElement;
16 |
--------------------------------------------------------------------------------
/lib/const/defaultHeaders.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @description This is the default request header, and you can override it in api.
3 | */
4 |
5 | const defaultHeaders = {
6 | 'Accept-Encoding': 'gzip, deflate, br',
7 | 'Cache-Control': 'max-age=0',
8 | 'Connection': 'keep-alive',
9 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'
10 | }
11 |
12 | module.exports = defaultHeaders;
13 |
--------------------------------------------------------------------------------
/examples/getHelloworld.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const server = require("../server/server");
4 | const Reqman = require("../lib/reqman");
5 |
6 | //run server on 3000.
7 | server("Hello World!");
8 |
9 | //Just need to set up a basic domain
10 | const req = new Reqman({
11 | baseUrl: "http://127.0.0.1:3000"
12 | });
13 |
14 | req
15 | .push(function () {
16 | return {
17 | method: "GET",
18 | url: `/`
19 | }
20 | })
21 | .done(function () {
22 | console.log("exit!");
23 | process.exit(1);
24 | })
25 |
--------------------------------------------------------------------------------
/examples/getGithub.js:
--------------------------------------------------------------------------------
1 | //Importing Reqman, remember to capitalize the first letter because Reqman is a class.
2 | const Reqman = require('../lib/reqman');
3 |
4 | //new Reqman,and then the parameter is passed in a base address.
5 | const req = new Reqman({
6 | baseUrl: "https://github.com"
7 | });
8 |
9 | //For example, you can use reqman to grab the github address of this project, like this:
10 | req
11 | .push(function () {
12 | return {
13 | method: "GET",
14 | url: `/lisniuse/reqman`
15 | }
16 | })
17 | .done();
18 |
--------------------------------------------------------------------------------
/lib/core/printError.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 |
3 | /**
4 | * @description A function that outputs the wrong log.
5 | * @param {Object} result http result
6 | * @return {Void}
7 | */
8 |
9 | function printError(err, queueElement) {
10 | console.log(chalk.bold(`${chalk.green(">>>")} [${queueElement.name}] ${chalk.bgGreen(queueElement.options.method)}: ${queueElement.options.url}`))
11 | console.log(chalk.bold(chalk.red('[REQMAN ERROR]: \n\n' + JSON.stringify(err, null, 2))));
12 | console.log("\n");
13 | }
14 |
15 | module.exports = printError;
16 |
--------------------------------------------------------------------------------
/lib/core/printHead.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 | const WordTable = require('word-table');
3 |
4 | /**
5 | * @description Print request time
6 | * @return {Void}
7 | */
8 |
9 | function printHead(requestQueue) {
10 | let queusNames = requestQueue.map(i => i.name);
11 | let tableHeader = ['Request time', new Date().toLocaleString()];
12 | let tableBody = [
13 | ["Request chain", queusNames.join(' → ')]
14 | ];
15 | let wt = new WordTable(tableHeader, tableBody);
16 | console.log(chalk.bold(chalk.cyan(wt.string())));
17 | console.log("\n");
18 | }
19 |
20 | module.exports = printHead;
21 |
--------------------------------------------------------------------------------
/lib/core/request.js:
--------------------------------------------------------------------------------
1 | const fly = require('flyio');
2 |
3 | /**
4 | * @description Used to send http requests.
5 | * @param {Object} options request options.
6 | * @return {Void}
7 | */
8 |
9 | async function request(options = {
10 | headers: {},
11 | method: 'GET',
12 | url: '/'
13 | }) {
14 | let method = options.method.toLowerCase();
15 | let headers = this._mergeHeaders(this._defaultHeader, options.headers);
16 | let promiseResult = fly.request(options.url, options.data, {
17 | method: method,
18 | headers: headers
19 | });
20 | return promiseResult;
21 | }
22 |
23 | module.exports = request;
24 |
--------------------------------------------------------------------------------
/examples/getSimple.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const server = require("../server/server");
4 | const Reqman = require("../lib/reqman");
5 |
6 | //run server on 3000.
7 | server();
8 |
9 | //Just need to set up a basic domain.
10 | const req = new Reqman({
11 | baseUrl: "http://127.0.0.1:3000"
12 | });
13 |
14 | req.
15 | push(function (prevElement) {
16 | return {
17 | method: "POST",
18 | url: `/?a=1`
19 | }
20 | })
21 | .push('name b', function (prevElement) {
22 | return {
23 | method: "GET",
24 | url: `/`,
25 | data: {
26 | a: '2'
27 | }
28 | }
29 | })
30 | .done(function () {
31 | process.exit(1);
32 | })
33 |
--------------------------------------------------------------------------------
/lib/utils/mixin.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 |
3 | /**
4 | * @description Mix a method or parameter into an object.
5 | * @param {Function} callback callback
6 | * @return {Function}
7 | */
8 |
9 | function mixin(targetClass, descriptor, propertyName, propertyValue) {
10 | Object.defineProperty(targetClass.prototype, propertyName, {
11 | enumerable: descriptor === 'public' ? true : false,
12 | configurable: true,
13 | writable: true,
14 | value: propertyValue
15 | });
16 | return function (descriptor, propertyName, propertyValue) {
17 | return mixin(targetClass, descriptor, propertyName, propertyValue);
18 | };
19 | }
20 |
21 | module.exports = mixin;
22 |
--------------------------------------------------------------------------------
/examples/getOutput.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const server = require("../server/server");
4 | const Reqman = require("../lib/reqman");
5 |
6 | //run server on 3000.
7 | server();
8 |
9 | //Just need to set up a basic domain.
10 | const req = new Reqman({
11 | output: './result.txt',
12 | baseUrl: "http://127.0.0.1:3000"
13 | });
14 |
15 | req.
16 | push(function (prevElement) {
17 | return {
18 | method: "POST",
19 | url: `/?a=1`
20 | }
21 | })
22 | .push('name b', function (prevElement) {
23 | return {
24 | method: "GET",
25 | url: `/`,
26 | data: {
27 | a: '2'
28 | }
29 | }
30 | })
31 | .done(function () {
32 | process.exit(1);
33 | })
34 |
--------------------------------------------------------------------------------
/lib/core/mergeHeaders.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 |
3 | /**
4 | * @description Used to merge request header information.
5 | * @param {Array} args As an array of headers.
6 | * @return {Object} Return a new headers object.
7 | */
8 |
9 | function mergeHeaders(...args) {
10 | let _args = [];
11 | args.forEach(headers => {
12 | if (_.isObject(headers)) {
13 | let _headers = {};
14 | for (const key in headers) {
15 | if (headers.hasOwnProperty(key)) {
16 | const value = headers[key];
17 | _headers[key.toLowerCase()] = value;
18 | }
19 | }
20 | _args.push(_headers);
21 | }
22 | });
23 | return _.merge(..._args);
24 | }
25 |
26 | module.exports = mergeHeaders;
27 |
--------------------------------------------------------------------------------
/examples/getInvalid.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const server = require("../server/server");
4 | const Reqman = require("../lib/reqman");
5 |
6 | //run server on 3000.
7 | server();
8 |
9 | //Just need to set up a basic domain.
10 | const req = new Reqman({
11 | baseUrl: "http://127.0.0.1:3000",
12 | specList: {
13 | type: 'invalid', //invalid or valid
14 | list: ['bob'] //Only jack exists.
15 | },
16 | });
17 |
18 | req.
19 | push('bob', function (prevElement) {
20 | return {
21 | method: "POST",
22 | url: `/?name=bob`
23 | }
24 | })
25 | .push('jack', function (prevElement) {
26 | return {
27 | method: "GET",
28 | url: `/`,
29 | data: {
30 | name: 'jack'
31 | }
32 | }
33 | })
34 | .done(function () {
35 | process.exit(1);
36 | })
37 |
--------------------------------------------------------------------------------
/examples/post.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const server = require("../server/server");
4 | const Reqman = require("../lib/reqman");
5 |
6 | //run server on 3000.
7 | server();
8 |
9 | //Just need to set up a basic domain
10 | const req = new Reqman({
11 | baseUrl: "http://127.0.0.1:3000"
12 | });
13 |
14 | req
15 | .push(function () {
16 | return {
17 | method: "POST",
18 | headers: {
19 | "content-type": "application/json"
20 | },
21 | url: `/`,
22 | data: {
23 | bar: 'foo'
24 | }
25 | }
26 | })
27 | .push(function () {
28 | return {
29 | method: "POST",
30 | url: `/`,
31 | data: {
32 | bar: 'foo'
33 | }
34 | }
35 | })
36 | .done(function () {
37 | console.log("exit!");
38 | process.exit(1);
39 | })
40 |
--------------------------------------------------------------------------------
/examples/getValid.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const server = require("../server/server");
4 | const Reqman = require("../lib/reqman");
5 |
6 | //run server on 3000.
7 | server();
8 |
9 | //Just need to set up a basic domain.
10 | const req = new Reqman({
11 | baseUrl: "http://127.0.0.1:3000",
12 | specList: {
13 | type: 'valid', //invalid or valid
14 | list: ['bob'] //Only bob exists.
15 | },
16 | });
17 |
18 | //Request chain.
19 | req.
20 | push('bob', function (prevElement) {
21 | return {
22 | method: "POST",
23 | url: `/?name=bob`
24 | }
25 | })
26 | .push('jack', function (prevElement) {
27 | return {
28 | method: "GET",
29 | url: `/`,
30 | data: {
31 | name: 'jack'
32 | }
33 | }
34 | })
35 | .done(function () {
36 | process.exit(1);
37 | })
38 |
--------------------------------------------------------------------------------
/lib/api/done.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @description This is the last step in the callback function, which is used to do some closing work.
3 | * @param {Function} callback callback
4 | * @return {Void}
5 | */
6 |
7 | async function done(callback) {
8 | let requestQueue = this._filterQueue();
9 | let len = requestQueue.length;
10 | this._printHead(requestQueue);
11 | for (let index = 0; index < len; index++) {
12 | let item = requestQueue[index];
13 | const next = async () => {
14 | let prev = len > 1 && index > 0 ? requestQueue[index - 1] : null;
15 | item.options = item.optionsFn.call(this, prev);
16 | await this._work(item);
17 | }
18 | await next();
19 | }
20 | if (callback && callback.constructor === Function) {
21 | callback.call(this);
22 | } else {
23 | process.exit(1);
24 | }
25 | }
26 |
27 | module.exports = done;
28 |
--------------------------------------------------------------------------------
/lib/api/push.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 | const checkFunctionReturnFalse = require('../utils/checkFunctionReturnFalse');
3 | const RequestElement = require('../core/RequestElement');
4 |
5 | /**
6 | * @description Insert request into request chain
7 | * @param {Function} options request options
8 | * @return {this}
9 | */
10 |
11 | function push(requestName, optionsFn = false) {
12 | let name = requestName;
13 | if (_.isFunction(name)) {
14 | optionsFn = requestName;
15 | name = this.requestQueue.length.toString();
16 | }
17 | if (this.hasOnly) {
18 | return this;
19 | }
20 | if (!_.isFunction(optionsFn)) {
21 | return this;
22 | }
23 | if (checkFunctionReturnFalse(optionsFn)) {
24 | return this;
25 | }
26 | this.requestQueue.push(new RequestElement({
27 | name: name,
28 | optionsFn: optionsFn
29 | }));
30 | return this;
31 | }
32 |
33 | module.exports = push;
34 |
--------------------------------------------------------------------------------
/lib/core/work.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 | const chalk = require('chalk');
3 |
4 | /**
5 | * @description Element-by-element request processing.
6 | * @param {Object} queueElement Queue element.
7 | * @return {Void}
8 | */
9 |
10 | async function work(queueElement) {
11 | let options = queueElement.options;
12 | let baseUrl = options.baseUrl || this.options.baseUrl;
13 | let outputPath = options.output || this.options.output;
14 | options.url = baseUrl + options.url;
15 | let result = "";
16 | try {
17 | result = await this._request(options);
18 | } catch (err) {
19 | this._printError(err, queueElement);
20 | process.exit(1);
21 | }
22 | queueElement.result = result;
23 | this._printResult(queueElement);
24 | if (outputPath) {
25 | this._outputResult(queueElement, outputPath);
26 | }
27 | if (_.isFunction(options.complete)) {
28 | options.complete.call(this, queueElement);
29 | }
30 | }
31 |
32 | module.exports = work;
33 |
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const Koa = require('koa');
4 | const app = new Koa();
5 |
6 | module.exports = async function (resStr) {
7 | app.use(async ctx => {
8 | if (resStr) {
9 | ctx.body = resStr;
10 | return;
11 | }
12 | async function getBody() {
13 | return new Promise(function (reslove, reject) {
14 | let postdata = "";
15 | ctx.req.addListener('data', (data) => {
16 | postdata += data;
17 | })
18 | ctx.req.addListener("end", function () {
19 | reslove(postdata);
20 | });
21 | });
22 | }
23 | let bodyData = await getBody();
24 | bodyData = bodyData !== "" ? bodyData : 'no body';
25 | let response = `
26 | Log for koa services:\n
27 | [header]: \n ${JSON.stringify(ctx.header)}\n
28 | [query data]: \n ${JSON.stringify(ctx.query)}\n
29 | [body data]: \n ${bodyData}
30 | `;
31 | ctx.body = response;
32 | });
33 | app.listen(3000);
34 | }
35 |
--------------------------------------------------------------------------------
/lib/core/filterQueue.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 |
3 | /**
4 | * @description Function is to filter out the queue.
5 | * @return {Array} queue array.
6 | */
7 |
8 | function filterQueue() {
9 | let newQueue = [];
10 | let requestQueue = this.requestQueue;
11 | let specList = this.options.specList;
12 | let hasSpecList = _.isObject(specList) && specList.list.length > 0;
13 | let len = requestQueue.length;
14 |
15 | for (let index = 0; index < len; index++) {
16 | let item = requestQueue[index];
17 | const push = () => {
18 | newQueue.push(item);
19 | }
20 | if (hasSpecList) {
21 | if (specList.type === 'invalid' || !specList.type) {
22 | if (!_.includes(specList.list, item.name)) {
23 | push();
24 | }
25 | } else if (specList.type === 'valid') {
26 | if (_.includes(specList.list, item.name)) {
27 | push();
28 | }
29 | }
30 | } else {
31 | push();
32 | }
33 | }
34 |
35 | return newQueue;
36 | }
37 |
38 | module.exports = filterQueue;
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-present ZhiBing
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/lib/core/outputResult.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const WordTable = require('word-table');
3 |
4 | /**
5 | * @description Output content to a file
6 | * @param {QueueElement} QueueElement QueueElement object
7 | * @param {String} filePath file output path
8 | * @return {Void}
9 | */
10 |
11 | function outputResult(queueElement, filePath) {
12 | let request = queueElement.result.request;
13 | let response = queueElement.result.response;
14 | let options = queueElement.options;
15 | let content = "";
16 | let tableHeader = ['Name', 'Method', 'Url', 'Data'];
17 | let tableBody = [
18 | [queueElement.name, request.method, request.url, JSON.stringify(options.data) || 'None']
19 | ];
20 | // basic usage
21 | let wt = new WordTable(tableHeader, tableBody);
22 | content += wt.string();
23 | content += '\n[*response body*] \n';
24 | let res = typeof response.body === "object" ? JSON.stringify(response.body) : response.body;
25 | res = res.replace(/(^\s*)|(\s*$)/g, "");
26 | if (res[0] === "{") {
27 | res = JSON.parse(res);
28 | content += JSON.stringify(res, null, 2);
29 | } else {
30 | content += res;
31 | }
32 | content += "\n";
33 | fs.appendFileSync(filePath, content, 'utf-8');
34 | }
35 |
36 | module.exports = outputResult;
37 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "reqman",
3 | "description": "Reqman is a tool that can quickly help back-end engineers with api testing, as well as a nodejs-based crawler tool.",
4 | "version": "0.9.3",
5 | "author": "ZhiBing <17560235@qq.com>",
6 | "license": "MIT",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/lisniuse/reqman.git"
10 | },
11 | "homepage": "https://github.com/lisniuse/reqman",
12 | "keywords": [
13 | "test",
14 | "apitest",
15 | "request",
16 | "web",
17 | "restful",
18 | "api",
19 | "backend"
20 | ],
21 | "dependencies": {
22 | "chalk": "^2.4.1",
23 | "flyio": "^0.6.13",
24 | "lodash": "^4.17.10",
25 | "opencollective-postinstall": "^2.0.2",
26 | "word-table": "^1.0.3"
27 | },
28 | "devDependencies": {
29 | "eslint": "^5.2.0",
30 | "koa": "^2.5.2"
31 | },
32 | "engines": {
33 | "node": ">= 8.0.0"
34 | },
35 | "files": [
36 | "LICENSE",
37 | "README.md",
38 | "Readme_cn.md",
39 | "index.js",
40 | "lib/"
41 | ],
42 | "scripts": {
43 | "test": "",
44 | "postinstall": "opencollective-postinstall || true"
45 | },
46 | "collective": {
47 | "type": "opencollective",
48 | "url": "https://opencollective.com/reqman"
49 | }
50 | }
--------------------------------------------------------------------------------
/lib/reqman.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mixin = require('./utils/mixin');
4 | const apiPush = require('./api/push');
5 | const apiDone = require('./api/done');
6 | const corePrintError = require('./core/printError');
7 | const coreOutputResult = require('./core/outputResult');
8 | const corePrintResult = require('./core/printResult');
9 | const corePrintHead = require('./core/printHead');
10 | const coreFilterQueue = require('./core/filterQueue');
11 | const coreRequest = require('./core/request');
12 | const coreWork = require('./core/work');
13 | const coreMergeHeaders = require('./core/mergeHeaders');
14 | const constDefaultHeader = require('./const/defaultHeaders');
15 |
16 | /**
17 | * Main class
18 | */
19 | class Reqman {
20 |
21 | /**
22 | * @description Necessary parameters, usually only need one basic domain
23 | * @param {Object} options options
24 | */
25 |
26 | constructor(options = {
27 | baseUrl: '', //Basic request address.
28 | output: '', //Outputs all results to a file with the specified path.
29 | specList: false, //Special list.
30 | }) {
31 | //Initialization parameter.
32 | this.options = options;
33 | this.store = {};
34 | this.requestQueue = [];
35 | this._defaultHeader = constDefaultHeader;
36 | }
37 |
38 | }
39 |
40 | mixin(Reqman, "public", "push", apiPush)
41 | ("public", "done", apiDone)
42 | ("private", "_work", coreWork)
43 | ("private", "_printError", corePrintError)
44 | ("private", "_outputResult", coreOutputResult)
45 | ("private", "_printResult", corePrintResult)
46 | ("private", "_printHead", corePrintHead)
47 | ("private", "_mergeHeaders", coreMergeHeaders)
48 | ("private", "_filterQueue", coreFilterQueue)
49 | ("private", "_request", coreRequest);
50 |
51 | module.exports = Reqman;
52 |
--------------------------------------------------------------------------------
/lib/core/printResult.js:
--------------------------------------------------------------------------------
1 | const chalk = require('chalk');
2 | const WordTable = require('word-table');
3 | const _ = require('lodash');
4 |
5 | /**
6 | * @description Add a line number to the text
7 | * @param {String} str Source string
8 | * @return {String} String with line number
9 | */
10 |
11 | function addLineNumber(str) {
12 |
13 | function prefixInteger(num, n) {
14 | let lineNumber = (Array(n).join(0) + num).slice(-n);
15 | return chalk.white(lineNumber + ' | ');
16 | }
17 |
18 | let strArr = str.split("\n");
19 | let newStr = "";
20 | let zeroLen = strArr.length.toString().split('').length;
21 | strArr.forEach((s, index) => {
22 | newStr += `${prefixInteger(index, zeroLen)}${s} \n`;
23 | });
24 | return newStr;
25 | }
26 |
27 | /**
28 | * @description Log output function.
29 | * @param {Object} result http result
30 | * @return {Void}
31 | */
32 |
33 | function printResult(queueElement) {
34 | let request = queueElement.result.request;
35 | let response = queueElement.result.response;
36 | let options = queueElement.options;
37 | let tableHeader = ['Name', 'Method', 'Url', 'Data'];
38 | let tableBody = [
39 | [queueElement.name, request.method, request.url, JSON.stringify(options.data) || 'None']
40 | ];
41 | let wt = new WordTable(tableHeader, tableBody);
42 | console.log(chalk.green(wt.string()));
43 | console.log(chalk.bold(chalk.yellow('[ response body ] \n')));
44 | if ( options.showInfo === false ) {
45 | console.log(chalk.gray('[hidden]'));
46 | } else {
47 | let res = typeof response.body === "object" ? JSON.stringify(response.body) : response.body;
48 | res = res.replace(/(^\s*)|(\s*$)/g, "");
49 | if (res[0] === "{") {
50 | res = JSON.parse(res);
51 | console.log(chalk.gray(addLineNumber(JSON.stringify(res, null, 2))));
52 | } else {
53 | console.log(chalk.gray(addLineNumber(res)));
54 | }
55 | }
56 | console.log("\n");
57 | }
58 |
59 | module.exports = printResult;
60 |
--------------------------------------------------------------------------------
/Readme_cn.md:
--------------------------------------------------------------------------------
1 | [English](./README.md) | [简体中文](./Readme_cn.md)
2 |
3 | # Reqman
4 |
5 | Reqman是一个可以快速帮助后端工程师进行api测试的工具,同时也是一个基于nodejs的爬虫工具。
6 |
7 | [](http://badge.fury.io/js/reqman)
8 |
9 | [](https://www.npmjs.com/package/reqman)
10 |
11 | ## 安装
12 |
13 | 这是一个通过 [npm registry](https://www.npmjs.com/) 提供的 [Node.js](https://nodejs.org/en/) 模块。
14 |
15 | 在安装之前,下载并安装Node.js。需要[Node.js 8.0](https://nodejs.org/en/download/)或更高版本。
16 |
17 | 使用[`npm install`](https://docs.npmjs.com/getting-started/installing-npm-packages-locally)命令完成安装:
18 |
19 | ```bash
20 | $ npm install reqman
21 | ```
22 |
23 | ## 引入使用
24 |
25 | ```javascript
26 | // 使用的是 Node.js `require()`
27 | const Reqman = require('reqman');
28 |
29 | // Using ES6 imports
30 | import Reqman from 'reqman';
31 | ```
32 |
33 | ## 特性
34 |
35 | * ✔︎ 链式API
36 | * ✔︎ 开箱即用
37 | * ✔︎ 可爬虫、可模拟请求
38 | * ✔︎ 适用于复杂强耦合场景
39 | * ✔︎ 基于nodejs强大请求库 [request](https://github.com/request/request)
40 |
41 | ## 超简单的入门教程
42 |
43 | Reqman被设计成像 [request](https://github.com/request/request) 一样,是进行http调用的最简单的方式。它支持https,默认情况下遵循重定向。
44 |
45 | 你只需要在返回一个``object`` 的 ``push`` 方法的参数中编写一个匿名函数,返回你的请求参数即可。
46 |
47 | ### 例子1:单个请求
48 |
49 | [点击这里查看这个例子源码](./examples/getGithub.js)
50 |
51 | ```javascript
52 | //引入Reqman,记得第一个字母要大写,因为是Reqman是一个类。
53 | const Reqman = require('reqman');
54 |
55 | //new Reqman,然后参数传入一个基地址。
56 | const req = new Reqman({
57 | baseUrl: "https://github.com"
58 | });
59 |
60 | //举个例子,你可以用reqman抓取本项目的github地址,像这样:
61 | req
62 | .push(function () {
63 | return {
64 | method: "GET",
65 | url: `/lisniuse/reqman`
66 | }
67 | })
68 | .done();
69 |
70 | ```
71 |
72 | 如果你指定showInfo参数为false,那么就不会打印结果到屏幕上,像这样:
73 |
74 | ```javascript
75 | req
76 | .push(function () {
77 | return {
78 | method: "GET",
79 | url: `/lisniuse/reqman`,
80 | showInfo: false
81 | }
82 | })
83 | .done();
84 | ```
85 |
86 | ### 例子2: 链式API
87 |
88 | 链API中,第一个请求的结果作为第二个请求的参数。就像这样:
89 |
90 | ```javascript
91 | const Reqman = require('reqman');
92 |
93 | //需要设置一个请求基地址
94 | const req = new Reqman({
95 | baseUrl: "http://127.0.0.1:3000"
96 | });
97 |
98 | //登陆的用户账号密码
99 | const user = {
100 | username: "admin",
101 | password: "admin"
102 | }
103 |
104 | req
105 | //请求登陆地址
106 | .push(function () {
107 | return {
108 | method: "POST",
109 | url: `/api/login`,
110 | data: user, //传入刚刚定义的user对象到data
111 | complete: function (selfElement) { //返回该队列的requestElement对象
112 | let response = selfElement.result.response;
113 | let body = JSON.parse(response.body);
114 | //注意:建议不要把公共变量直接挂到reqman的实例上,可能会覆盖requman的属性和方法,reqman提供了一个store对象用于存储请求过程中需要存储的公共变量。
115 | this.store.userToken = body.data.token; //拿到用户token
116 | }
117 | }
118 | })
119 | //然后我们以登陆之后的获取到的token来更新用户的信息。
120 | .push(function () {
121 | return {
122 | method: "POST",
123 | url: `/api/user/updateInfo`,
124 | headers: {
125 | 'Authorization': this.store.userToken //之后的请求中可以直接使用store里的变量
126 | },
127 | data: {
128 | nickname: "jack ma" //更新昵称为 jack ma
129 | }
130 | }
131 | })
132 | .done()//just do it.
133 |
134 | ```
135 |
136 | ### 例字3:完整体现reqman的api和特性的例子
137 |
138 | ```javascript
139 | 'use strict'
140 |
141 | const req = new Reqman({
142 | baseUrl: "http://127.0.0.1:3000",
143 | output: "./request-result.txt", //将请求后返回的结果同时追加写入到指定的文件路径
144 | specList: {
145 | type: 'valid', //参数:invalid 或 valid。定义有效或者无效的请求。
146 | list: ['bob'] //让名为bob的请求有效,其余的请求失效。如果type为invalid,则相反。
147 | }
148 | });
149 |
150 | //请求链
151 | req.
152 | //定义一个名为bob的请求,prevElement参数表示上一个请求的requestElement对象。
153 | push('bob', function (prevElement) {
154 | return {
155 | method: "POST",
156 | url: `/?name=bob`,
157 | headers: { //附带自定义headers
158 | 'content-type': 'application/octet-stream'
159 | },
160 | complete: function (selfElement) { //请求完毕后的回调函数
161 |
162 | }
163 | }
164 | })
165 | //定义一个名为jack的请求,prevElement参数表示上一个请求的requestElement对象。
166 | .push('jack', function (prevElement) {
167 | return {
168 | baseUrl: 'http://127.0.0.1:4000', //为该请求自定义基地址
169 | output: "./jack-result.txt", //为该请求自定义输出文件路径
170 | method: "GET",
171 | url: `/`,
172 | data: {
173 | name: 'jack'
174 | },
175 | showInfo: false, //不将返回的body信息打印出来
176 | complete: function (selfElement) { //请求完毕后的回调函数
177 | //do something...
178 | }
179 | }
180 | })
181 | .done(function () {
182 | //退出程序
183 | process.exit(1);
184 | })
185 |
186 | ```
187 |
188 | ### 更多例子
189 |
190 | 更多例子在项目的 [examples](./examples) 文件夹中,你可以直接运行:
191 |
192 | ```bash
193 | node getHelloworld.js
194 | ```
195 |
196 | ## License
197 |
198 | The MIT License (MIT)
199 |
200 | Copyright (c) 2015-present ZhiBing \<17560235@qq.com>
201 |
202 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
203 |
204 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
205 |
206 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
207 |
208 | [back to top](#reqman)
209 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [English](./README.md) | [简体中文](./Readme_cn.md)
2 |
3 | # Reqman
4 |
5 | Reqman is a tool that can quickly help back-end engineers with api testing, as well as a nodejs-based crawler tool.
6 |
7 | [](https://opencollective.com/reqman) [](http://badge.fury.io/js/reqman)
8 |
9 | [](https://www.npmjs.com/package/reqman)
10 |
11 | ## Installation
12 |
13 | This is a [Node.js](https://nodejs.org/en/) module available through the
14 | [npm registry](https://www.npmjs.com/).
15 |
16 | Before installing, [download and install Node.js](https://nodejs.org/en/download/).
17 | Node.js 8.0 or higher is required.
18 |
19 | Installation is done using the
20 | [`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
21 |
22 | ```bash
23 | $ npm install reqman
24 | ```
25 |
26 | ## Importing
27 |
28 | ```javascript
29 | // Using Node.js `require()`
30 | const Reqman = require('reqman');
31 |
32 | // Using ES6 imports
33 | import Reqman from 'reqman';
34 | ```
35 |
36 | ## Features
37 |
38 | * ✔︎ Chained API
39 | * ✔︎ Out of the box
40 | * ✔︎ Crawler, can simulate requests
41 | * ✔︎ Suitable for complex and strong coupling scenarios
42 | * ✔︎ Powerful request library [request](https://github.com/request/request) based on nodejs
43 |
44 | ## Super simple to use
45 |
46 | Reqman is designed to be like [request](https://github.com/request/request) and is the easiest way to make http calls. It supports https, to follow redirection by default.
47 |
48 | All you have to do is write an anonymous function in the parameters of the ``push`` method that returns a ``object`` and return your request parameters.
49 |
50 | ### Example 1: a single request
51 |
52 | [Click here to view this example source code](./examples/getGithub.js)
53 |
54 | ```javascript
55 | //Importing Reqman, remember to capitalize the first letter because Reqman is a class.
56 | const Reqman = require('reqman');
57 |
58 | //new Reqman,and then the parameter is passed in a base address.
59 | const req = new Reqman({
60 | baseUrl: "https://github.com"
61 | });
62 |
63 | //For example, you can use reqman to grab the github address of this project, like this:
64 | req
65 | .push(function () {
66 | return {
67 | method: "GET",
68 | url: `/lisniuse/reqman`
69 | }
70 | })
71 | .done();
72 |
73 | ```
74 |
75 | If you specify the showInfo parameter as false, the results will not be printed to the screen, like this:
76 |
77 | ```javascript
78 | req
79 | .push(function () {
80 | return {
81 | method: "GET",
82 | url: `/lisniuse/reqman`,
83 | showInfo: false
84 | }
85 | })
86 | .done();
87 |
88 | ```
89 |
90 | ### Example 2: Chained API
91 |
92 | In the chained API, the result of the first request is used as the argument to the second request. like this:
93 |
94 | ```javascript
95 | const Reqman = require('reqman');
96 |
97 | const req = new Reqman({
98 | baseUrl: "http://127.0.0.1:3000"
99 | });
100 |
101 | //Define account password
102 | const user = {
103 | username: "admin",
104 | password: "admin"
105 | }
106 |
107 | req
108 | //Request a login api
109 | .push(function () {
110 | return {
111 | method: "POST",
112 | url: `/api/login`,
113 | data: user, //Pass in the user object just defined to data
114 | complete: function (selfElement) { //Return the requestElement object of the queue
115 | let response = selfElement.result.response;
116 | let body = JSON.parse(response.body);
117 | //Note: It is recommended not to hang public variables directly on the reqman instance, which may override the requman properties and methods. Reqman provides a store object to store the public variables that need to be stored during the request process.
118 | this.store.userToken = body.data.token; //Get the user token
119 | }
120 | }
121 | })
122 | //Then we update the user's information with the token obtained after login.
123 | .push(function () {
124 | return {
125 | method: "POST",
126 | url: `/api/user/updateInfo`,
127 | headers: {
128 | 'Authorization': this.store.userToken //The variables in the store can be directly used in subsequent requests.
129 | },
130 | data: {
131 | nickname: "jack ma" //Update nickname jack ma
132 | }
133 | }
134 | })
135 | .done()//just do it.
136 |
137 | ```
138 |
139 | ### Example 3: Example of a complete representation of reqman's api and features
140 |
141 | ```javascript
142 | 'use strict'
143 |
144 | const req = new Reqman({
145 | baseUrl: "http://127.0.0.1:3000",
146 | output: "./request-result.txt", //Append the result returned after the request to the specified file path at the same time.
147 | specList: {
148 | type: 'valid', //Parameters: invalid or valid. Define valid or invalid requests.
149 | list: ['bob'] //Let the request named bob be valid and the rest of the requests invalid. If type is invalid, the opposite is true.
150 | }
151 | });
152 |
153 | req.
154 | //Define a request named bob, and the prevElement parameter represents the requestElement object of the previous request.
155 | push('bob', function (prevElement) {
156 | return {
157 | method: "POST",
158 | url: `/?name=bob`,
159 | headers: { //With custom headers
160 | 'content-type': 'application/octet-stream'
161 | },
162 | complete: function (selfElement) { //Callback function after request
163 |
164 | }
165 | }
166 | })
167 | //Define a request named jack, and the prevElement parameter represents the requestElement object of the previous request.
168 | .push('jack', function (prevElement) {
169 | return {
170 | baseUrl: 'http://127.0.0.1:4000', //Customize the base address for this request
171 | output: "./jack-result.txt", //Customize the output file path for this request
172 | method: "GET",
173 | url: `/`,
174 | data: {
175 | name: 'jack'
176 | },
177 | showInfo: false, //Do not print the returned body information
178 | complete: function (selfElement) { //Callback function after request
179 | //do something...
180 | }
181 | }
182 | })
183 | .done(function () {
184 | //exit the program
185 | process.exit(1);
186 | })
187 |
188 | ```
189 |
190 | ### More examples
191 |
192 | More [examples](./examples) in the projects folder of the project, you can run this command directly:
193 |
194 | ```bash
195 | node getHelloworld.js
196 | ```
197 |
198 | ## Contributors
199 |
200 | ### Code Contributors
201 |
202 | This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
203 |
204 |
205 | ### Financial Contributors
206 |
207 | Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/reqman/contribute)]
208 |
209 | #### Individuals
210 |
211 |
212 |
213 | #### Organizations
214 |
215 | Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/reqman/contribute)]
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 | ## License
229 |
230 | The MIT License (MIT)
231 |
232 | Copyright (c) 2015-present ZhiBing \<17560235@qq.com>
233 |
234 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
235 |
236 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
237 |
238 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
239 |
240 | [back to top](#reqman)
241 |
--------------------------------------------------------------------------------