@metlo/testing
Advanced tools
Comparing version 0.0.3 to 0.1.0
@@ -1,5 +0,7 @@ | ||
import { Test, Result, Request } from "./types"; | ||
export { Test, Result, Request, TestResult, AuthAPIKeyParams, AuthBearerParams, Authorization, RequestBody, AuthBasicAuthParams, DataPair, } from "./types"; | ||
export { APIKeyAuthAddTo, AuthType, RequestBodyType } from "./enums"; | ||
export declare const runRequest: (request: Request, envVars: Map<string, string>) => Promise<Result>; | ||
export declare const runTest: (test: Test, envVars?: Map<string, string>) => Promise<Result[]>; | ||
import { TestConfig } from "./types/test"; | ||
export declare const dumpTestConfig: (config: TestConfig) => string; | ||
export declare const loadTestConfig: (path: string) => TestConfig; | ||
export declare const runTestPath: (paths: string[]) => Promise<void>; | ||
export { AssertionType } from "./types/enums"; | ||
export { KeyValType, TestConfig, TestRequest, TestResult, TestConfigSchema, } from "./types/test"; | ||
export { runTest } from "./runner"; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.runTest = exports.runRequest = exports.RequestBodyType = exports.AuthType = exports.APIKeyAuthAddTo = void 0; | ||
exports.runTest = exports.TestConfigSchema = exports.AssertionType = exports.runTestPath = exports.loadTestConfig = exports.dumpTestConfig = void 0; | ||
const tslib_1 = require("tslib"); | ||
const axios_1 = tslib_1.__importDefault(require("axios")); | ||
const form_data_1 = tslib_1.__importDefault(require("form-data")); | ||
const expect_1 = tslib_1.__importDefault(require("expect")); | ||
const vm2_1 = require("vm2"); | ||
const Tester_1 = tslib_1.__importDefault(require("./Tester")); | ||
const enums_1 = require("./enums"); | ||
const utils_1 = require("./utils"); | ||
var enums_2 = require("./enums"); | ||
Object.defineProperty(exports, "APIKeyAuthAddTo", { enumerable: true, get: function () { return enums_2.APIKeyAuthAddTo; } }); | ||
Object.defineProperty(exports, "AuthType", { enumerable: true, get: function () { return enums_2.AuthType; } }); | ||
Object.defineProperty(exports, "RequestBodyType", { enumerable: true, get: function () { return enums_2.RequestBodyType; } }); | ||
const makeAxiosRequestConfig = (request, envVars) => { | ||
let requestConfig = { | ||
url: (0, utils_1.processTemplate)(request.url, envVars), | ||
method: request.method, | ||
headers: Object.fromEntries(request.headers.map(e => [e.key, e.value])), | ||
params: {}, | ||
transformResponse: res => res, | ||
validateStatus: code => true, | ||
}; | ||
// Query Params | ||
if (request.params.length > 0) { | ||
requestConfig.params = Object.fromEntries(request.params.map(e => [e.key, e.value])); | ||
const chalk_1 = tslib_1.__importDefault(require("chalk")); | ||
const js_yaml_1 = tslib_1.__importDefault(require("js-yaml")); | ||
const fs_1 = tslib_1.__importDefault(require("fs")); | ||
const ora_1 = tslib_1.__importDefault(require("ora")); | ||
const test_1 = require("./types/test"); | ||
const runner_1 = require("./runner"); | ||
const spinner = (0, ora_1.default)(); | ||
const dumpTestConfig = (config) => { | ||
const parts = [ | ||
{ | ||
id: config.id, | ||
}, | ||
]; | ||
if (config.meta) { | ||
parts.push({ meta: config.meta }); | ||
} | ||
// Body | ||
if (request.body.type == enums_1.RequestBodyType.JSON) { | ||
requestConfig.data = request.body.data; | ||
requestConfig.headers["Content-Type"] = | ||
requestConfig.headers["Content-Type"] || "application/json"; | ||
if (config.env) { | ||
parts.push({ env: config.env }); | ||
} | ||
else if (request.body.type == enums_1.RequestBodyType.FORM_DATA) { | ||
let bodyFormData = new form_data_1.default(); | ||
const requestData = request.body.data; | ||
requestData.forEach(e => bodyFormData.append(e.key, e.value)); | ||
requestConfig.data = bodyFormData; | ||
requestConfig.headers["Content-Type"] = | ||
requestConfig.headers["Content-Type"] || "multipart/form-data"; | ||
if (config.test) { | ||
parts.push({ test: config.test }); | ||
} | ||
// Authorization | ||
if (request.authorization) { | ||
const auth = request.authorization; | ||
if (auth.type == enums_1.AuthType.API_KEY) { | ||
const params = auth.params; | ||
if (params.add_to == enums_1.APIKeyAuthAddTo.HEADERS) { | ||
requestConfig.headers[params.key] = params.value; | ||
} | ||
else if (params.add_to == enums_1.APIKeyAuthAddTo.QUERY_PARAMS) { | ||
requestConfig.params[params.key] = params.value; | ||
} | ||
} | ||
else if (auth.type == enums_1.AuthType.BEARER) { | ||
const params = auth.params; | ||
requestConfig.headers["Authorization"] = | ||
requestConfig.headers["Authorization"] || | ||
`Bearer ${params.bearer_token}`; | ||
} | ||
else if (auth.type == enums_1.AuthType.BASIC_AUTH) { | ||
const params = auth.params; | ||
requestConfig.auth = { | ||
username: params.username, | ||
password: params.password, | ||
}; | ||
} | ||
return parts.map(e => js_yaml_1.default.dump(e)).join("\n"); | ||
}; | ||
exports.dumpTestConfig = dumpTestConfig; | ||
const loadTestConfig = (path) => { | ||
const data = js_yaml_1.default.load(fs_1.default.readFileSync(path, "utf8")); | ||
const parseRes = test_1.TestConfigSchema.safeParse(data); | ||
if (!parseRes.success) { | ||
console.log(chalk_1.default.bold.red("Failed to load test...")); | ||
throw new Error(JSON.stringify(parseRes.error.flatten(), null, 4)); | ||
} | ||
return requestConfig; | ||
return parseRes.data; | ||
}; | ||
const runRequest = (request, envVars) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { | ||
let requestConfig = makeAxiosRequestConfig(request, envVars); | ||
try { | ||
const start = Date.now(); | ||
const response = yield (0, axios_1.default)(requestConfig); | ||
const end = Date.now(); | ||
let testResults = []; | ||
if (request.tests) { | ||
const m = new Tester_1.default(requestConfig, response); | ||
const vm = new vm2_1.VM({ | ||
timeout: 100000, | ||
sandbox: { | ||
m, | ||
expect: expect_1.default, | ||
}, | ||
}); | ||
testResults = vm.run(`${request.tests}\nm.run()`); | ||
exports.loadTestConfig = loadTestConfig; | ||
const runTestPath = (paths) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { | ||
for (let path of paths) { | ||
spinner.start(chalk_1.default.dim("Loading test...")); | ||
const test = (0, exports.loadTestConfig)(path); | ||
spinner.succeed(chalk_1.default.green("Done loading test...")); | ||
spinner.stop(); | ||
spinner.start(chalk_1.default.dim("Running test...")); | ||
const res = yield (0, runner_1.runTest)(test); | ||
spinner.succeed(chalk_1.default.green("Done running test...")); | ||
spinner.stop(); | ||
if (res.success) { | ||
console.log(chalk_1.default.bold.green("All Tests Succeeded!")); | ||
} | ||
return { | ||
body: response.data, | ||
headers: Object.entries(response.headers).map(([key, value]) => ({ | ||
key, | ||
value: value, | ||
})), | ||
testResults, | ||
code: response.status, | ||
statusText: response.statusText, | ||
duration: end - start, | ||
}; | ||
else { | ||
console.log(chalk_1.default.bold.red("Some Tests Failed.")); | ||
console.log(JSON.stringify(res.results, null, 4)); | ||
} | ||
} | ||
catch (e) { | ||
return { | ||
body: "", | ||
headers: [], | ||
testResults: [], | ||
code: 0, | ||
statusText: "", | ||
duration: 0, | ||
error: e.message, | ||
}; | ||
} | ||
}); | ||
exports.runRequest = runRequest; | ||
const runTest = (test, envVars) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { | ||
let output = []; | ||
envVars = envVars || new Map(); | ||
for (let i = 0; i < test.requests.length; i++) { | ||
const res = yield (0, exports.runRequest)(test.requests[i], envVars); | ||
output.push(res); | ||
} | ||
return output; | ||
}); | ||
exports.runTest = runTest; | ||
exports.runTestPath = runTestPath; | ||
var enums_1 = require("./types/enums"); | ||
Object.defineProperty(exports, "AssertionType", { enumerable: true, get: function () { return enums_1.AssertionType; } }); | ||
var test_2 = require("./types/test"); | ||
Object.defineProperty(exports, "TestConfigSchema", { enumerable: true, get: function () { return test_2.TestConfigSchema; } }); | ||
var runner_2 = require("./runner"); | ||
Object.defineProperty(exports, "runTest", { enumerable: true, get: function () { return runner_2.runTest; } }); | ||
//# sourceMappingURL=index.js.map |
@@ -1,1 +0,6 @@ | ||
export declare const processTemplate: (base: string, envVars: Map<string, string>) => string; | ||
import { AxiosResponse } from "axios"; | ||
import { Context } from "types/context"; | ||
export declare const ALLOWED_DATA_TYPES: string[]; | ||
export declare const processEnvVars: (base: string, envVars: Record<string, string>) => string; | ||
export declare const executeScript: (script: string, resp: AxiosResponse, ctx: Context) => any; | ||
export declare const stringReplacement: (string: string, envVars: Context["envVars"]) => string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.processTemplate = void 0; | ||
const processTemplate = (base, envVars) => { | ||
for (let [key, value] of envVars) { | ||
exports.stringReplacement = exports.executeScript = exports.processEnvVars = exports.ALLOWED_DATA_TYPES = void 0; | ||
const tslib_1 = require("tslib"); | ||
const vm2_1 = tslib_1.__importDefault(require("vm2")); | ||
const Handlebars = tslib_1.__importStar(require("handlebars")); | ||
const SCRIPT_DEFAULT_TIMEOUT = 1000; | ||
exports.ALLOWED_DATA_TYPES = ["string", "bigint", "number", "boolean", "undefined", "null"]; | ||
const processEnvVars = (base, envVars) => { | ||
for (let [key, value] of Object.entries(envVars)) { | ||
base = base.replace(`{{${key}}}`, value); | ||
@@ -10,3 +15,28 @@ } | ||
}; | ||
exports.processTemplate = processTemplate; | ||
exports.processEnvVars = processEnvVars; | ||
const createVM = (resp, ctx) => { | ||
const vm = new vm2_1.default.VM({ timeout: SCRIPT_DEFAULT_TIMEOUT, allowAsync: false, eval: false, wasm: false, }); | ||
const sandboxItems = {}; | ||
Object.entries(ctx.envVars).forEach(([k, v]) => vm.freeze(v, k)); | ||
vm.freeze(resp, "resp"); | ||
return vm; | ||
}; | ||
const executeScript = (script, resp, ctx) => { | ||
const vm = createVM(resp, ctx); | ||
const execResponse = vm.run(script); | ||
if (exports.ALLOWED_DATA_TYPES.includes((typeof execResponse).toLowerCase())) { | ||
return execResponse; | ||
} | ||
else { | ||
const errMsg = `Returned invalid type of response from JS code. Required one of ${exports.ALLOWED_DATA_TYPES.join(",")},found ${typeof execResponse}`; | ||
throw new Error(errMsg); | ||
} | ||
}; | ||
exports.executeScript = executeScript; | ||
const stringReplacement = (string, envVars) => { | ||
const template = Handlebars.compile(string); | ||
const templated = (template(envVars)); | ||
return templated; | ||
}; | ||
exports.stringReplacement = stringReplacement; | ||
//# sourceMappingURL=utils.js.map |
{ | ||
"name": "@metlo/testing", | ||
"version": "0.0.3", | ||
"version": "0.1.0", | ||
"license": "MIT", | ||
@@ -10,7 +10,12 @@ "main": "dist/index.js", | ||
"watch": "tsc -w", | ||
"format": "prettier --write './src/**/*.{ts,tsx}'" | ||
"format": "prettier --write './src/**/*.{ts,tsx}'", | ||
"test": "ts-node src/index.ts" | ||
}, | ||
"devDependencies": { | ||
"@types/axios": "^0.14.0", | ||
"@types/chalk": "^2.2.0", | ||
"@types/js-yaml": "^4.0.5", | ||
"@types/lodash.get": "^4.4.7", | ||
"prettier": "^2.7.1", | ||
"ts-node": "^10.9.1", | ||
"tslib": "^2.4.0", | ||
@@ -20,6 +25,12 @@ "typescript": "^4.7.4" | ||
"dependencies": { | ||
"axios": "^0.27.2", | ||
"axios": "^1.2.1", | ||
"chalk": "^4.1.2", | ||
"expect": "^29.0.2", | ||
"vm2": "^3.9.11" | ||
"handlebars": "^4.7.7", | ||
"js-yaml": "^4.1.0", | ||
"lodash.get": "^4.4.2", | ||
"ora": "^5.4.1", | ||
"vm2": "^3.9.13", | ||
"zod": "^3.20.2" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
78354
58
1716
9
8
3
1
+ Addedchalk@^4.1.2
+ Addedhandlebars@^4.7.7
+ Addedjs-yaml@^4.1.0
+ Addedlodash.get@^4.4.2
+ Addedora@^5.4.1
+ Addedzod@^3.20.2
+ Addedansi-regex@5.0.1(transitive)
+ Addedargparse@2.0.1(transitive)
+ Addedaxios@1.7.7(transitive)
+ Addedbase64-js@1.5.1(transitive)
+ Addedbl@4.1.0(transitive)
+ Addedbuffer@5.7.1(transitive)
+ Addedcli-cursor@3.1.0(transitive)
+ Addedcli-spinners@2.9.2(transitive)
+ Addedclone@1.0.4(transitive)
+ Addeddefaults@1.0.4(transitive)
+ Addedhandlebars@4.7.8(transitive)
+ Addedieee754@1.2.1(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedis-interactive@1.0.0(transitive)
+ Addedis-unicode-supported@0.1.0(transitive)
+ Addedjs-yaml@4.1.0(transitive)
+ Addedlodash.get@4.4.2(transitive)
+ Addedlog-symbols@4.1.0(transitive)
+ Addedmimic-fn@2.1.0(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedneo-async@2.6.2(transitive)
+ Addedonetime@5.1.2(transitive)
+ Addedora@5.4.1(transitive)
+ Addedproxy-from-env@1.1.0(transitive)
+ Addedreadable-stream@3.6.2(transitive)
+ Addedrestore-cursor@3.1.0(transitive)
+ Addedsafe-buffer@5.2.1(transitive)
+ Addedsignal-exit@3.0.7(transitive)
+ Addedsource-map@0.6.1(transitive)
+ Addedstring_decoder@1.3.0(transitive)
+ Addedstrip-ansi@6.0.1(transitive)
+ Addeduglify-js@3.19.3(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
+ Addedwcwidth@1.0.1(transitive)
+ Addedwordwrap@1.0.0(transitive)
+ Addedzod@3.23.8(transitive)
- Removedaxios@0.27.2(transitive)
Updatedaxios@^1.2.1
Updatedvm2@^3.9.13