diff --git a/package-lock.json b/package-lock.json index d3ed0bc10..385fc649b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "packages/bruno-query", "packages/bruno-js", "packages/bruno-lang", + "packages/bruno-tests", "packages/bruno-testbench", "packages/bruno-toml", "packages/bruno-graphql-docs" @@ -5421,6 +5422,10 @@ "resolved": "packages/bruno-testbench", "link": true }, + "node_modules/@usebruno/tests": { + "resolved": "packages/bruno-tests", + "link": true + }, "node_modules/@usebruno/toml": { "resolved": "packages/bruno-toml", "link": true @@ -6167,6 +6172,16 @@ "version": "1.12.0", "license": "MIT" }, + "node_modules/axios": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/babel-jest": { "version": "29.3.1", "dev": true, @@ -6347,6 +6362,22 @@ ], "license": "MIT" }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "license": "BSD-3-Clause", @@ -7460,6 +7491,26 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "dependencies": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie-signature": { "version": "1.0.6", "license": "MIT" @@ -8745,7 +8796,6 @@ }, "node_modules/eventemitter3": { "version": "4.0.7", - "dev": true, "license": "MIT" }, "node_modules/events": { @@ -8843,6 +8893,14 @@ "node": ">= 0.10.0" } }, + "node_modules/express-basic-auth": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.2.1.tgz", + "integrity": "sha512-L6YQ1wQ/mNjVLAmK3AG1RK6VkokA1BIY6wmiH304Xtt/cLTps40EusZsU1Uop+v9lTDPxdtzbFmdXfFO3KEnwA==", + "dependencies": { + "basic-auth": "^2.0.1" + } + }, "node_modules/express-xml-bodyparser": { "version": "0.3.0", "license": "MIT", @@ -9214,14 +9272,15 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.2", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], - "license": "MIT", "engines": { "node": ">=4.0" }, @@ -10231,6 +10290,19 @@ "node": ">= 0.8" } }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/http-proxy-agent": { "version": "5.0.0", "dev": true, @@ -18557,6 +18629,39 @@ "js-yaml": "bin/js-yaml.js" } }, + "packages/bruno-tests": { + "version": "0.0.1", + "license": "MIT", + "dependencies": { + "axios": "^1.5.1", + "body-parser": "^1.20.0", + "cookie-parser": "^1.4.6", + "cors": "^2.8.5", + "express": "^4.18.1", + "express-basic-auth": "^1.2.1", + "express-xml-bodyparser": "^0.3.0", + "http-proxy": "^1.18.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "multer": "^1.4.5-lts.1" + } + }, + "packages/bruno-tests/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "packages/bruno-tests/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "packages/bruno-toml": { "name": "@usebruno/toml", "version": "0.1.0", @@ -22804,6 +22909,37 @@ } } }, + "@usebruno/tests": { + "version": "file:packages/bruno-tests", + "requires": { + "axios": "^1.5.1", + "body-parser": "^1.20.0", + "cookie-parser": "^1.4.6", + "cors": "^2.8.5", + "express": "^4.18.1", + "express-basic-auth": "^1.2.1", + "express-xml-bodyparser": "^0.3.0", + "http-proxy": "^1.18.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "multer": "^1.4.5-lts.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + } + } + }, "@usebruno/toml": { "version": "file:packages/bruno-toml", "requires": { @@ -23328,6 +23464,16 @@ "aws4": { "version": "1.12.0" }, + "axios": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "requires": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "babel-jest": { "version": "29.3.1", "dev": true, @@ -23441,6 +23587,21 @@ "base64-js": { "version": "1.5.1" }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, "bcrypt-pbkdf": { "version": "1.0.2", "requires": { @@ -24287,6 +24448,22 @@ "cookie": { "version": "0.5.0" }, + "cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "requires": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "dependencies": { + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + } + } + }, "cookie-signature": { "version": "1.0.6" }, @@ -25116,8 +25293,7 @@ } }, "eventemitter3": { - "version": "4.0.7", - "dev": true + "version": "4.0.7" }, "events": { "version": "3.3.0", @@ -25203,6 +25379,14 @@ } } }, + "express-basic-auth": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.2.1.tgz", + "integrity": "sha512-L6YQ1wQ/mNjVLAmK3AG1RK6VkokA1BIY6wmiH304Xtt/cLTps40EusZsU1Uop+v9lTDPxdtzbFmdXfFO3KEnwA==", + "requires": { + "basic-auth": "^2.0.1" + } + }, "express-xml-bodyparser": { "version": "0.3.0", "requires": { @@ -25449,7 +25633,9 @@ } }, "follow-redirects": { - "version": "1.15.2" + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==" }, "forever-agent": { "version": "0.6.1" @@ -26094,6 +26280,16 @@ "toidentifier": "1.0.1" } }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, "http-proxy-agent": { "version": "5.0.0", "dev": true, diff --git a/package.json b/package.json index a623adc66..5c4ced347 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "packages/bruno-query", "packages/bruno-js", "packages/bruno-lang", + "packages/bruno-tests", "packages/bruno-testbench", "packages/bruno-toml", "packages/bruno-graphql-docs" diff --git a/packages/bruno-tests/.gitignore b/packages/bruno-tests/.gitignore new file mode 100644 index 000000000..253e9824f --- /dev/null +++ b/packages/bruno-tests/.gitignore @@ -0,0 +1,107 @@ +# JUnit +collection/junit.xml + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port diff --git a/packages/bruno-tests/.nvmrc b/packages/bruno-tests/.nvmrc new file mode 100644 index 000000000..9a2a0e219 --- /dev/null +++ b/packages/bruno-tests/.nvmrc @@ -0,0 +1 @@ +v20 diff --git a/packages/bruno-tests/collection/auth/basic/via auth/Basic Auth 200.bru b/packages/bruno-tests/collection/auth/basic/via auth/Basic Auth 200.bru new file mode 100644 index 000000000..de5612b1f --- /dev/null +++ b/packages/bruno-tests/collection/auth/basic/via auth/Basic Auth 200.bru @@ -0,0 +1,21 @@ +meta { + name: Basic Auth 200 + type: http + seq: 1 +} + +post { + url: {{host}}/api/auth/basic/protected + body: json + auth: basic +} + +auth:basic { + username: bruno + password: {{basic_auth_password}} +} + +assert { + res.status: 200 + res.body.message: Authentication successful +} diff --git a/packages/bruno-tests/collection/auth/basic/via auth/Basic Auth 401.bru b/packages/bruno-tests/collection/auth/basic/via auth/Basic Auth 401.bru new file mode 100644 index 000000000..0c8388c97 --- /dev/null +++ b/packages/bruno-tests/collection/auth/basic/via auth/Basic Auth 401.bru @@ -0,0 +1,21 @@ +meta { + name: Basic Auth 400 + type: http + seq: 2 +} + +post { + url: {{host}}/api/auth/basic/protected + body: json + auth: none +} + +auth:basic { + username: bruno + password: invalid +} + +assert { + res.status: 401 + res.body: Unauthorized +} diff --git a/packages/bruno-tests/collection/auth/basic/via script/Basic Auth 200.bru b/packages/bruno-tests/collection/auth/basic/via script/Basic Auth 200.bru new file mode 100644 index 000000000..04d12f226 --- /dev/null +++ b/packages/bruno-tests/collection/auth/basic/via script/Basic Auth 200.bru @@ -0,0 +1,26 @@ +meta { + name: Basic Auth 200 + type: http + seq: 1 +} + +post { + url: {{host}}/api/auth/basic/protected + body: json + auth: none +} + +assert { + res.status: eq 200 + res.body.message: Authentication successful +} + +script:pre-request { + const username = "bruno"; + const password = "della"; + + const authString = `${username}:${password}`; + const encodedAuthString = require('btoa')(authString); + + req.setHeader("Authorization", `Basic ${encodedAuthString}`); +} diff --git a/packages/bruno-tests/collection/auth/basic/via script/Basic Auth 401.bru b/packages/bruno-tests/collection/auth/basic/via script/Basic Auth 401.bru new file mode 100644 index 000000000..e560115d2 --- /dev/null +++ b/packages/bruno-tests/collection/auth/basic/via script/Basic Auth 401.bru @@ -0,0 +1,26 @@ +meta { + name: Basic Auth 401 + type: http + seq: 2 +} + +post { + url: {{host}}/api/auth/basic/protected + body: json + auth: none +} + +assert { + res.status: 401 + res.body: Unauthorized +} + +script:pre-request { + const username = "bruno"; + const password = "invalid"; + + const authString = `${username}:${password}`; + const encodedAuthString = require('btoa')(authString); + + req.setHeader("Authorization", `Basic ${encodedAuthString}`); +} diff --git a/packages/bruno-tests/collection/auth/bearer/via auth/Bearer Auth 200.bru b/packages/bruno-tests/collection/auth/bearer/via auth/Bearer Auth 200.bru new file mode 100644 index 000000000..1ca671163 --- /dev/null +++ b/packages/bruno-tests/collection/auth/bearer/via auth/Bearer Auth 200.bru @@ -0,0 +1,24 @@ +meta { + name: Bearer Auth 200 + type: http + seq: 1 +} + +get { + url: {{host}}/api/auth/bearer/protected + body: none + auth: bearer +} + +auth:bearer { + token: {{bearer_auth_token}} +} + +assert { + res.status: 200 + res.body.message: Authentication successful +} + +script:post-response { + bru.setEnvVar("foo", "bar"); +} diff --git a/packages/bruno-tests/collection/auth/bearer/via auth/Bearer Auth 401.bru b/packages/bruno-tests/collection/auth/bearer/via auth/Bearer Auth 401.bru new file mode 100644 index 000000000..4b2a98657 --- /dev/null +++ b/packages/bruno-tests/collection/auth/bearer/via auth/Bearer Auth 401.bru @@ -0,0 +1,24 @@ +meta { + name: Bearer Auth 401 + type: http + seq: 2 +} + +get { + url: {{host}}/api/auth/bearer/protected + body: none + auth: none +} + +auth:bearer { + token: {{bearerAuthToken}}zz +} + +assert { + res.status: 401 + res.body.message: Unauthorized +} + +script:post-response { + bru.setEnvVar("foo", "bar"); +} diff --git a/packages/bruno-tests/collection/auth/bearer/via headers/Bearer Auth 200.bru b/packages/bruno-tests/collection/auth/bearer/via headers/Bearer Auth 200.bru new file mode 100644 index 000000000..a837bdd7e --- /dev/null +++ b/packages/bruno-tests/collection/auth/bearer/via headers/Bearer Auth 200.bru @@ -0,0 +1,28 @@ +meta { + name: Bearer Auth 200 + type: http + seq: 1 +} + +get { + url: {{host}}/api/auth/bearer/protected + body: json + auth: none +} + +headers { + Authorization: Bearer your_secret_token +} + +vars:pre-request { + a-c: foo +} + +assert { + res.status: 200 + res.body.message: Authentication successful +} + +script:post-response { + bru.setEnvVar("foo", "bar"); +} diff --git a/packages/bruno-tests/collection/auth/bearer/via headers/Bearer Auth 401.bru b/packages/bruno-tests/collection/auth/bearer/via headers/Bearer Auth 401.bru new file mode 100644 index 000000000..5bfc64038 --- /dev/null +++ b/packages/bruno-tests/collection/auth/bearer/via headers/Bearer Auth 401.bru @@ -0,0 +1,20 @@ +meta { + name: Bearer Auth 401 + type: http + seq: 2 +} + +get { + url: {{host}}/api/auth/bearer/protected + body: json + auth: none +} + +assert { + res.status: 401 + res.body.message: Unauthorized +} + +script:post-response { + bru.setEnvVar("foo", "bar"); +} diff --git a/packages/bruno-tests/collection/auth/cookie/Check.bru b/packages/bruno-tests/collection/auth/cookie/Check.bru new file mode 100644 index 000000000..eb7f16f3f --- /dev/null +++ b/packages/bruno-tests/collection/auth/cookie/Check.bru @@ -0,0 +1,11 @@ +meta { + name: Check + type: http + seq: 2 +} + +get { + url: {{host}}/api/auth/cookie/protected + body: none + auth: none +} diff --git a/packages/bruno-tests/collection/auth/cookie/Login.bru b/packages/bruno-tests/collection/auth/cookie/Login.bru new file mode 100644 index 000000000..230486495 --- /dev/null +++ b/packages/bruno-tests/collection/auth/cookie/Login.bru @@ -0,0 +1,11 @@ +meta { + name: Login + type: http + seq: 1 +} + +post { + url: {{host}}/api/auth/cookie/login + body: none + auth: none +} diff --git a/packages/bruno-tests/collection/bruno.json b/packages/bruno-tests/collection/bruno.json new file mode 100644 index 000000000..79602ccd3 --- /dev/null +++ b/packages/bruno-tests/collection/bruno.json @@ -0,0 +1,31 @@ +{ + "version": "1", + "name": "bruno-testbench", + "type": "collection", + "proxy": { + "enabled": false, + "protocol": "http", + "hostname": "{{proxyHostname}}", + "port": 4000, + "auth": { + "enabled": false, + "username": "anoop", + "password": "password" + }, + "bypassProxy": "" + }, + "scripts": { + "moduleWhitelist": ["crypto"], + "filesystemAccess": { + "allow": true + } + }, + "clientCertificates": { + "enabled": true, + "certs": [] + }, + "presets": { + "requestType": "http", + "requestUrl": "http://localhost:6000" + } +} diff --git a/packages/bruno-tests/collection/collection.bru b/packages/bruno-tests/collection/collection.bru new file mode 100644 index 000000000..e31b64995 --- /dev/null +++ b/packages/bruno-tests/collection/collection.bru @@ -0,0 +1,22 @@ +headers { + check: again +} + +auth { + mode: none +} + +auth:basic { + username: bruno + password: {{basicAuthPassword}} +} + +auth:bearer { + token: {{bearerAuthToken}} +} + +docs { + # bruno-testbench 🐶 + + This is a test collection that I am using to test various functionalities around bruno +} diff --git a/packages/bruno-tests/collection/echo/echo json.bru b/packages/bruno-tests/collection/echo/echo json.bru new file mode 100644 index 000000000..09a8ed90c --- /dev/null +++ b/packages/bruno-tests/collection/echo/echo json.bru @@ -0,0 +1,48 @@ +meta { + name: echo json + type: http + seq: 1 +} + +post { + url: {{host}}/api/echo/json + body: json + auth: none +} + +headers { + foo: bar +} + +auth:basic { + username: asd + password: j +} + +auth:bearer { + token: +} + +body:json { + { + "hello": "bruno" + } +} + +assert { + res.status: eq 200 +} + +script:pre-request { + bru.setVar("foo", "foo-world-2"); +} + +tests { + test("should return json", function() { + const data = res.getBody(); + expect(res.getBody()).to.eql({ + "hello": "bruno" + }); + }); + +} diff --git a/packages/bruno-tests/collection/echo/echo plaintext.bru b/packages/bruno-tests/collection/echo/echo plaintext.bru new file mode 100644 index 000000000..56a23d345 --- /dev/null +++ b/packages/bruno-tests/collection/echo/echo plaintext.bru @@ -0,0 +1,27 @@ +meta { + name: echo plaintext + type: http + seq: 3 +} + +post { + url: {{host}}/api/echo/text + body: text + auth: none +} + +body:text { + hello +} + +assert { + res.status: eq 200 +} + +tests { + test("should return plain text", function() { + const data = res.getBody(); + expect(res.getBody()).to.eql("hello"); + }); + +} diff --git a/packages/bruno-tests/collection/echo/echo xml parsed.bru b/packages/bruno-tests/collection/echo/echo xml parsed.bru new file mode 100644 index 000000000..586541664 --- /dev/null +++ b/packages/bruno-tests/collection/echo/echo xml parsed.bru @@ -0,0 +1,35 @@ +meta { + name: echo xml parsed + type: http + seq: 4 +} + +post { + url: {{host}}/api/echo/xml-parsed + body: xml + auth: none +} + +body:xml { + + bruno + +} + +assert { + res.status: eq 200 +} + +tests { + test("should return parsed xml", function() { + const data = res.getBody(); + expect(res.getBody()).to.eql({ + "hello": { + "world": [ + "bruno" + ] + } + }); + }); + +} diff --git a/packages/bruno-tests/collection/echo/echo xml raw.bru b/packages/bruno-tests/collection/echo/echo xml raw.bru new file mode 100644 index 000000000..6a02ac238 --- /dev/null +++ b/packages/bruno-tests/collection/echo/echo xml raw.bru @@ -0,0 +1,15 @@ +meta { + name: echo xml raw + type: http + seq: 5 +} + +post { + url: {{host}}/api/echo/xml-raw + body: xml + auth: none +} + +body:xml { + bruno +} diff --git a/packages/bruno-tests/collection/environments/Local.bru b/packages/bruno-tests/collection/environments/Local.bru new file mode 100644 index 000000000..113502138 --- /dev/null +++ b/packages/bruno-tests/collection/environments/Local.bru @@ -0,0 +1,5 @@ +vars { + host: http://localhost:80 + bearer_auth_token: your_secret_token + basic_auth_password: della +} diff --git a/packages/bruno-tests/collection/environments/Prod.bru b/packages/bruno-tests/collection/environments/Prod.bru new file mode 100644 index 000000000..557e3f0a6 --- /dev/null +++ b/packages/bruno-tests/collection/environments/Prod.bru @@ -0,0 +1,6 @@ +vars { + host: https://testbench-sanity.usebruno.com + bearer_auth_token: your_secret_token + basic_auth_password: della + foo: bar +} diff --git a/packages/bruno-tests/collection/file.json b/packages/bruno-tests/collection/file.json new file mode 100644 index 000000000..a967fac5b --- /dev/null +++ b/packages/bruno-tests/collection/file.json @@ -0,0 +1,3 @@ +{ + "hello": "bruno" +} diff --git a/packages/bruno-tests/collection/ping.bru b/packages/bruno-tests/collection/ping.bru new file mode 100644 index 000000000..96a6eb89f --- /dev/null +++ b/packages/bruno-tests/collection/ping.bru @@ -0,0 +1,63 @@ +meta { + name: ping + type: http + seq: 1 +} + +get { + url: {{host}}/ping + body: none + auth: none +} + +auth:awsv4 { + accessKeyId: a + secretAccessKey: b + sessionToken: c + service: d + region: e + profileName: f +} + +vars:pre-request { + m4: true + pong: pong +} + +assert { + res.status: eq 200 + ~res.body: eq {{pong}} +} + +script:pre-request { + console.log(bru.getEnvName()); +} + +tests { + test("should ping pong", function() { + const data = res.getBody(); + expect(data).to.equal(bru.getVar("pong")); + }); +} + +docs { + # API Documentation + + ## Introduction + + Welcome to the API documentation for [Your API Name]. This document provides instructions on how to make requests to the API and covers available authentication methods. + + ## Authentication + + Before making requests to the API, you need to authenticate your application. [Your API Name] supports the following authentication methods: + + ### API Key + + To use API key authentication, include your API key in the request headers as follows: + + ```http + GET /api/endpoint + Host: api.example.com + Authorization: Bearer YOUR_API_KEY + +} diff --git a/packages/bruno-tests/collection/preview/html/bruno.bru b/packages/bruno-tests/collection/preview/html/bruno.bru new file mode 100644 index 000000000..a259f231a --- /dev/null +++ b/packages/bruno-tests/collection/preview/html/bruno.bru @@ -0,0 +1,23 @@ +meta { + name: bruno + type: http + seq: 1 +} + +get { + url: https://www.usebruno.com + body: none + auth: none +} + +assert { + res.status: eq 200 +} + +tests { + test("should return parsed xml", function() { + const headers = res.getHeaders(); + expect(headers['content-type']).to.eql("text/html; charset=utf-8"); + }); + +} diff --git a/packages/bruno-tests/collection/preview/image/bruno.bru b/packages/bruno-tests/collection/preview/image/bruno.bru new file mode 100644 index 000000000..bb773d91c --- /dev/null +++ b/packages/bruno-tests/collection/preview/image/bruno.bru @@ -0,0 +1,19 @@ +meta { + name: bruno + type: http + seq: 1 +} + +get { + url: https://www.usebruno.com/images/landing-2.png + body: none + auth: none +} + +tests { + test("should return parsed xml", function() { + const headers = res.getHeaders(); + expect(headers['content-type']).to.eql("image/png"); + }); + +} diff --git a/packages/bruno-tests/collection/readme.md b/packages/bruno-tests/collection/readme.md new file mode 100644 index 000000000..1ad4a6e88 --- /dev/null +++ b/packages/bruno-tests/collection/readme.md @@ -0,0 +1,15 @@ +# bruno-sanity collection + +API Collection to run sanity tests on Bruno. + +### Test + +```bash +npm i @usebruno/cli -g + +# Test locally +bru run --env Local + +# Test on production +bru run --env Prod --output junit.xml --format junit +``` diff --git a/packages/bruno-tests/collection/redirects/Disable Redirect.bru b/packages/bruno-tests/collection/redirects/Disable Redirect.bru new file mode 100644 index 000000000..31aedd2f2 --- /dev/null +++ b/packages/bruno-tests/collection/redirects/Disable Redirect.bru @@ -0,0 +1,26 @@ +meta { + name: Disable Redirect + type: http + seq: 1 +} + +get { + url: {{host}}/redirect-to-ping + body: none + auth: none +} + +assert { + res.status: 302 +} + +script:pre-request { + req.setMaxRedirects(0); +} + +tests { + test("should disable redirect to ping", function() { + const data = res.getBody(); + expect(data).to.equal('Found. Redirecting to /ping'); + }); +} diff --git a/packages/bruno-tests/collection/redirects/Test Redirect.bru b/packages/bruno-tests/collection/redirects/Test Redirect.bru new file mode 100644 index 000000000..a2b5bd9be --- /dev/null +++ b/packages/bruno-tests/collection/redirects/Test Redirect.bru @@ -0,0 +1,23 @@ +meta { + name: Test Redirect + type: http + seq: 2 +} + +get { + url: {{host}}/redirect-to-ping + body: none + auth: none +} + +assert { + res.status: 200 + res.body: pong +} + +tests { + test("should redirect to ping", function() { + const data = res.getBody(); + expect(data).to.equal('pong'); + }); +} diff --git a/packages/bruno-tests/package.json b/packages/bruno-tests/package.json new file mode 100644 index 000000000..0135eeb61 --- /dev/null +++ b/packages/bruno-tests/package.json @@ -0,0 +1,33 @@ +{ + "name": "@usebruno/tests", + "version": "0.0.1", + "description": "", + "main": "src/index.js", + "scripts": { + "start": "node ." + }, + "repository": { + "type": "git", + "url": "git+https://github.com/usebruno/bruno-testbench.git" + }, + "keywords": [], + "author": "", + "license": "MIT", + "bugs": { + "url": "https://github.com/usebruno/bruno-testbench/issues" + }, + "homepage": "https://github.com/usebruno/bruno-testbench#readme", + "dependencies": { + "axios": "^1.5.1", + "body-parser": "^1.20.0", + "cookie-parser": "^1.4.6", + "cors": "^2.8.5", + "express": "^4.18.1", + "express-basic-auth": "^1.2.1", + "express-xml-bodyparser": "^0.3.0", + "http-proxy": "^1.18.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "multer": "^1.4.5-lts.1" + } +} diff --git a/packages/bruno-tests/readme.md b/packages/bruno-tests/readme.md new file mode 100644 index 000000000..0b09a96b2 --- /dev/null +++ b/packages/bruno-tests/readme.md @@ -0,0 +1,28 @@ +# bruno-tests + +This package is used to test the Bruno CLI. +We have a collection that sits in the `collection` directory. + +### Test Server + +This will start the server on port 80 which exposes endpoints that the collection will hit. + +```bash +# install node dependencies +npm install + +# start server +npm start +``` + +### Run Bru CLI on Collection + +```bash +cd collection + +node ../../bruno-cli/bin/bru.js run --env Local --output junit.xml --format junit +``` + +### License + +[MIT](LICENSE) diff --git a/packages/bruno-tests/src/auth/basic.js b/packages/bruno-tests/src/auth/basic.js new file mode 100644 index 000000000..1b0a3928f --- /dev/null +++ b/packages/bruno-tests/src/auth/basic.js @@ -0,0 +1,19 @@ +const express = require('express'); +const router = express.Router(); +const basicAuth = require('express-basic-auth'); + +const users = { + bruno: 'della' +}; + +const basicAuthMiddleware = basicAuth({ + users, + challenge: true, // Sends a 401 Unauthorized response when authentication fails + unauthorizedResponse: 'Unauthorized' +}); + +router.post('/protected', basicAuthMiddleware, (req, res) => { + res.status(200).json({ message: 'Authentication successful' }); +}); + +module.exports = router; diff --git a/packages/bruno-tests/src/auth/bearer.js b/packages/bruno-tests/src/auth/bearer.js new file mode 100644 index 000000000..d3715aa54 --- /dev/null +++ b/packages/bruno-tests/src/auth/bearer.js @@ -0,0 +1,18 @@ +const express = require('express'); +const router = express.Router(); + +const authenticateToken = (req, res, next) => { + const token = req.header('Authorization'); + + if (!token || token !== `Bearer your_secret_token`) { + return res.status(401).json({ message: 'Unauthorized' }); + } + + next(); +}; + +router.get('/protected', authenticateToken, (req, res) => { + res.status(200).json({ message: 'Authentication successful' }); +}); + +module.exports = router; diff --git a/packages/bruno-tests/src/auth/cookie.js b/packages/bruno-tests/src/auth/cookie.js new file mode 100644 index 000000000..c73943171 --- /dev/null +++ b/packages/bruno-tests/src/auth/cookie.js @@ -0,0 +1,38 @@ +const express = require('express'); +const cookieParser = require('cookie-parser'); +const router = express.Router(); + +// Initialize the cookie-parser middleware +router.use(cookieParser()); + +// Middleware to check if the user is authenticated +function requireAuth(req, res, next) { + const isAuthenticated = req.cookies.isAuthenticated === 'true'; + + if (isAuthenticated) { + next(); // User is authenticated, continue to the next middleware or route handler + } else { + res.status(401).json({ message: 'Unauthorized' }); // User is not authenticated, send a 401 Unauthorized response + } +} + +// Route to set a cookie when a user logs in +router.post('/login', (req, res) => { + // You should perform authentication here, and if successful, set the cookie. + // For demonstration purposes, let's assume the user is authenticated. + res.cookie('isAuthenticated', 'true'); + res.status(200).json({ message: 'Logged in successfully' }); +}); + +// Route to log out and clear the cookie +router.post('/logout', (req, res) => { + res.clearCookie('isAuthenticated'); + res.status(200).json({ message: 'Logged out successfully' }); +}); + +// Protected route that requires authentication +router.get('/protected', requireAuth, (req, res) => { + res.status(200).json({ message: 'Authentication successful' }); +}); + +module.exports = router; diff --git a/packages/bruno-tests/src/auth/index.js b/packages/bruno-tests/src/auth/index.js new file mode 100644 index 000000000..84d93798e --- /dev/null +++ b/packages/bruno-tests/src/auth/index.js @@ -0,0 +1,12 @@ +const express = require('express'); +const router = express.Router(); + +const authBearer = require('./bearer'); +const authBasic = require('./basic'); +const authCookie = require('./cookie'); + +router.use('/bearer', authBearer); +router.use('/basic', authBasic); +router.use('/cookie', authCookie); + +module.exports = router; diff --git a/packages/bruno-tests/src/echo/index.js b/packages/bruno-tests/src/echo/index.js new file mode 100644 index 000000000..36a37102e --- /dev/null +++ b/packages/bruno-tests/src/echo/index.js @@ -0,0 +1,22 @@ +const express = require('express'); +const router = express.Router(); + +router.post('/json', (req, res) => { + return res.json(req.body); +}); + +router.post('/text', (req, res) => { + res.setHeader('Content-Type', 'text/plain'); + return res.send(req.body); +}); + +router.post('/xml-parsed', (req, res) => { + return res.send(req.body); +}); + +router.post('/xml-raw', (req, res) => { + res.setHeader('Content-Type', 'application/xml'); + return res.send(req.rawBody); +}); + +module.exports = router; diff --git a/packages/bruno-tests/src/index.js b/packages/bruno-tests/src/index.js new file mode 100644 index 000000000..286cfdad6 --- /dev/null +++ b/packages/bruno-tests/src/index.js @@ -0,0 +1,45 @@ +const express = require('express'); +const bodyParser = require('body-parser'); +const xmlparser = require('express-xml-bodyparser'); +const cors = require('cors'); +const multer = require('multer'); + +const app = new express(); +const port = process.env.PORT || 80; +const upload = multer(); + +app.use(cors()); +app.use(xmlparser()); +app.use(bodyParser.text()); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); + +const authRouter = require('./auth'); +const echoRouter = require('./echo'); + +app.use('/api/auth', authRouter); +app.use('/api/echo', echoRouter); + +app.get('/ping', function (req, res) { + return res.send('pong'); +}); + +app.get('/headers', function (req, res) { + return res.json(req.headers); +}); + +app.get('/query', function (req, res) { + return res.json(req.query); +}); + +app.post('/echo/multipartForm', upload.none(), function (req, res) { + return res.json(req.body); +}); + +app.get('/redirect-to-ping', function (req, res) { + return res.redirect('/ping'); +}); + +app.listen(port, function () { + console.log(`Testbench started on port: ${port}`); +});