Signed-off-by: Zoey <zoey@z0ey.de>
This commit is contained in:
Zoey
2022-12-16 09:05:58 +01:00
parent fd30cfe98b
commit 19a304d9ce
169 changed files with 2074 additions and 27536 deletions

View File

@@ -1 +0,0 @@
node_modules

View File

@@ -1,76 +0,0 @@
{
"env": {
"browser": true,
"es6": true,
"cypress/globals": true
},
"extends": [
"eslint:recommended",
"plugin:cypress/recommended"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": [
"cypress",
"chai-friendly",
"align-assignments"
],
"rules": {
"indent": [
"error",
"tab"
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"key-spacing": [
"error",
{
"align": "value"
}
],
"comma-spacing": [
"error",
{
"before": false,
"after": true
}
],
"func-call-spacing": [
"error",
"never"
],
"keyword-spacing": [
"error",
{
"before": true
}
],
"no-irregular-whitespace": "error",
"cypress/no-assigning-return-values": "error",
"cypress/no-unnecessary-waiting": "warn",
"no-unused-expressions": 0,
"chai-friendly/no-unused-expressions": 2,
"align-assignments/align-assignments": [
2,
{
"requiresOnly": false
}
]
}
}

4
test/.gitignore vendored
View File

@@ -1,4 +0,0 @@
.vscode
node_modules
results
cypress/videos

View File

@@ -1,11 +0,0 @@
{
"printWidth": 160,
"tabWidth": 4,
"useTabs": true,
"semi": true,
"singleQuote": true,
"bracketSpacing": true,
"jsxBracketSameLine": true,
"trailingComma": "all",
"proseWrap": "always"
}

View File

@@ -1,46 +0,0 @@
# Cypress Test Suite
## Running Locally
```
cd nginxproxymanager/test
yarn install
yarn run cypress
```
## VS Code
Editor settings are not committed to the repository, typically because each developer has their own settings. Below is a list of common setting that may help,
so feel free to try them or ignore them, you are a strong independent developer. You can add settings to either "user" or "workspace" but we recommend using
"workspace" as each project is different.
### ESLint
The ESLint extension only works on JavaScript files by default, so add the following to your workspace settings and reload VSCode.
```
"eslint.autoFixOnSave": true,
"eslint.validate": [
{ "language": "javascript", "autoFix": true },
"html"
]
```
> NOTE: If you've also set the editor.formatOnSave option to true in your settings.json, you'll need to add the following config to prevent running 2 formatting
> commands on save for JavaScript and TypeScript files:
```
"editor.formatOnSave": true,
"[javascript]": {
"editor.formatOnSave": false,
},
"[javascriptreact]": {
"editor.formatOnSave": false,
},
"[typescript]": {
"editor.formatOnSave": false,
},
"[typescriptreact]": {
"editor.formatOnSave": false,
},
```

View File

@@ -1,13 +0,0 @@
FROM cypress/included:5.6.0
COPY --chown=1000 ./ /test
# mkcert
ENV MKCERT=1.4.2
RUN wget -O /usr/bin/mkcert "https://github.com/FiloSottile/mkcert/releases/download/v${MKCERT}/mkcert-v${MKCERT}-linux-amd64" \
&& chmod +x /usr/bin/mkcert
WORKDIR /test
RUN yarn install
ENTRYPOINT []
CMD ["cypress", "run"]

View File

@@ -1,14 +0,0 @@
{
"requestTimeout": 30000,
"defaultCommandTimeout": 20000,
"reporter": "cypress-multi-reporters",
"reporterOptions": {
"configFile": "multi-reporter.json"
},
"videosFolder": "results/videos",
"screenshotsFolder": "results/screenshots",
"env": {
"swaggerBase": "{{baseUrl}}/api/schema",
"RETRIES": 4
}
}

View File

@@ -1,14 +0,0 @@
{
"requestTimeout": 30000,
"defaultCommandTimeout": 20000,
"reporter": "cypress-multi-reporters",
"reporterOptions": {
"configFile": "multi-reporter.json"
},
"videos": false,
"screenshotsFolder": "results/screenshots",
"env": {
"swaggerBase": "{{baseUrl}}/api/schema",
"RETRIES": 0
}
}

View File

@@ -1,5 +0,0 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@@ -1,20 +0,0 @@
/// <reference types="Cypress" />
describe('Basic API checks', () => {
it('Should return a valid health payload', function () {
cy.task('backendApiGet', {
path: '/api/',
}).then((data) => {
// Check the swagger schema:
cy.validateSwaggerSchema('get', 200, '/', data);
});
});
it('Should return a valid schema payload', function () {
cy.task('backendApiGet', {
path: '/api/schema',
}).then((data) => {
expect(data.openapi).to.be.equal('3.0.0');
});
});
});

View File

@@ -1,48 +0,0 @@
/// <reference types="Cypress" />
describe('Users endpoints', () => {
let token;
before(() => {
cy.getToken().then((tok) => {
token = tok;
});
});
it('Should be able to get yourself', function() {
cy.task('backendApiGet', {
token: token,
path: '/api/users/me'
}).then((data) => {
cy.validateSwaggerSchema('get', 200, '/users/{userID}', data);
expect(data).to.have.property('id');
expect(data.id).to.be.greaterThan(0);
});
});
it('Should be able to get all users', function() {
cy.task('backendApiGet', {
token: token,
path: '/api/users'
}).then((data) => {
cy.validateSwaggerSchema('get', 200, '/users', data);
expect(data.length).to.be.greaterThan(0);
});
});
it('Should be able to update yourself', function() {
cy.task('backendApiPut', {
token: token,
path: '/api/users/me',
data: {
name: 'changed name'
}
}).then((data) => {
cy.validateSwaggerSchema('put', 200, '/users/{userID}', data);
expect(data).to.have.property('id');
expect(data.id).to.be.greaterThan(0);
expect(data.name).to.be.equal('changed name');
});
});
});

View File

@@ -1,142 +0,0 @@
const logger = require('./logger');
const restler = require('@jc21/restler');
const BackendApi = function(config, token) {
this.config = config;
this.token = token;
};
/**
* @param {string} token
*/
BackendApi.prototype.setToken = function(token) {
this.token = token;
};
/**
* @param {string} path
* @param {bool} [returnOnError]
* @returns {Promise<object>}
*/
BackendApi.prototype.get = function(path, returnOnError) {
return new Promise((resolve, reject) => {
let headers = {
Accept: 'application/json'
};
if (this.token) {
headers.Authorization = 'Bearer ' + this.token;
}
logger('GET ', this.config.baseUrl + path);
restler
.get(this.config.baseUrl + path, {
headers: headers,
})
.on('complete', function(data, response) {
logger('Response data:', data);
if (!returnOnError && data instanceof Error) {
reject(data);
} else if (!returnOnError && response.statusCode != 200) {
if (typeof data === 'object' && typeof data.error === 'object' && typeof data.error.message !== 'undefined') {
reject(new Error(data.error.code + ': ' + data.error.message));
} else {
reject(new Error('Error ' + response.statusCode));
}
} else {
resolve(data);
}
});
});
};
/**
* @param {string} path
* @param {bool} [returnOnError]
* @returns {Promise<object>}
*/
BackendApi.prototype.delete = function(path, returnOnError) {
return new Promise((resolve, reject) => {
let headers = {
Accept: 'application/json'
};
if (this.token) {
headers.Authorization = 'Bearer ' + this.token;
}
logger('DELETE ', this.config.baseUrl + path);
restler
.del(this.config.baseUrl + path, {
headers: headers,
})
.on('complete', function(data, response) {
logger('Response data:', data);
if (!returnOnError && data instanceof Error) {
reject(data);
} else if (!returnOnError && response.statusCode != 200) {
if (typeof data === 'object' && typeof data.error === 'object' && typeof data.error.message !== 'undefined') {
reject(new Error(data.error.code + ': ' + data.error.message));
} else {
reject(new Error('Error ' + response.statusCode));
}
} else {
resolve(data);
}
});
});
};
/**
* @param {string} path
* @param {object} data
* @param {bool} [returnOnError]
* @returns {Promise<object>}
*/
BackendApi.prototype.postJson = function(path, data, returnOnError) {
logger('POST ', this.config.baseUrl + path);
return this._putPostJson('postJson', path, data, returnOnError);
};
/**
* @param {string} path
* @param {object} data
* @param {bool} [returnOnError]
* @returns {Promise<object>}
*/
BackendApi.prototype.putJson = function(path, data, returnOnError) {
logger('PUT ', this.config.baseUrl + path);
return this._putPostJson('putJson', path, data, returnOnError);
};
/**
* @param {string} path
* @param {object} data
* @param {bool} [returnOnError]
* @returns {Promise<object>}
*/
BackendApi.prototype._putPostJson = function(fn, path, data, returnOnError) {
return new Promise((resolve, reject) => {
restler[fn](this.config.baseUrl + path, data, {
headers: {
Accept: 'application/json',
Authorization: 'Bearer ' + this.token,
},
}).on('complete', function(data, response) {
logger('Response data:', data);
if (!returnOnError && data instanceof Error) {
reject(data);
} else if (!returnOnError && response.statusCode != 200) {
if (typeof data === 'object' && typeof data.error === 'object' && typeof data.error.message !== 'undefined') {
reject(new Error(data.error.code + ': ' + data.error.message));
} else {
reject(new Error('Error ' + response.statusCode));
}
} else {
resolve(data);
}
});
});
};
module.exports = BackendApi;

View File

@@ -1,8 +0,0 @@
const _ = require('lodash');
const chalk = require('chalk');
module.exports = function () {
var arr = _.values(arguments);
arr.unshift(chalk.blue.bold('[') + chalk.yellow.bold('Backend API') + chalk.blue.bold(']'));
console.log.apply(null, arr);
};

View File

@@ -1,64 +0,0 @@
const logger = require('./logger');
const Client = require('./client');
module.exports = function (config) {
logger('Client Ready using', config.baseUrl);
return {
/**
* @param {object} options
* @param {string} options.path API path
* @param {string} [options.token] JWT
* @param {bool} [options.returnOnError] If true, will return instead of throwing errors
* @returns {string}
*/
backendApiGet: (options) => {
const api = new Client(config);
api.setToken(options.token);
return api.get(options.path, options.returnOnError || false);
},
/**
* @param {object} options
* @param {string} options.token JWT
* @param {string} options.path API path
* @param {object} options.data
* @param {bool} [options.returnOnError] If true, will return instead of throwing errors
* @returns {string}
*/
backendApiPost: (options) => {
const api = new Client(config);
api.setToken(options.token);
return api.postJson(options.path, options.data, options.returnOnError || false);
},
/**
* @param {object} options
* @param {string} options.token JWT
* @param {string} options.path API path
* @param {object} options.data
* @param {bool} [options.returnOnError] If true, will return instead of throwing errors
* @returns {string}
*/
backendApiPut: (options) => {
const api = new Client(config);
api.setToken(options.token);
return api.putJson(options.path, options.data, options.returnOnError || false);
},
/**
* @param {object} options
* @param {string} options.token JWT
* @param {string} options.path API path
* @param {bool} [options.returnOnError] If true, will return instead of throwing errors
* @returns {string}
*/
backendApiDelete: (options) => {
const api = new Client(config);
api.setToken(options.token);
return api.delete(options.path, options.returnOnError || false);
}
};
};

View File

@@ -1,20 +0,0 @@
const {SwaggerValidation} = require('@jc21/cypress-swagger-validation');
module.exports = (on, config) => {
// Replace swaggerBase config var wildcard
if (typeof config.env.swaggerBase !== 'undefined') {
config.env.swaggerBase = config.env.swaggerBase.replace('{{baseUrl}}', config.baseUrl);
}
// Plugin Events
on('task', SwaggerValidation(config));
on('task', require('./backendApi/task')(config));
on('task', {
log(message) {
console.log(message);
return null;
}
});
return config;
};

View File

@@ -1,42 +0,0 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
/**
* Check the swagger schema:
*
* @param {string} method API Method in swagger doc, "get", "put", "post", "delete"
* @param {number} statusCode API status code in swagger doc
* @param {string} path Swagger doc endpoint path, exactly as defined in swagger doc
* @param {*} data The API response data to check against the swagger schema
*/
Cypress.Commands.add('validateSwaggerSchema', (method, statusCode, path, data) => {
cy.task('validateSwaggerSchema', {
file: Cypress.env('swaggerBase'),
endpoint: path,
method: method,
statusCode: statusCode,
responseSchema: data,
verbose: true
}).should('equal', null);
});
Cypress.Commands.add('getToken', () => {
// login with existing user
cy.task('backendApiPost', {
path: '/api/tokens',
data: {
identity: 'admin@example.com',
secret: 'changeme'
}
}).then(res => {
cy.wrap(res.token);
});
});

View File

@@ -1,9 +0,0 @@
require('cypress-plugin-retries');
import './commands';
Cypress.on('uncaught:exception', (/*err, runnable*/) => {
// returning false here prevents Cypress from
// failing the test
return false;
});

View File

@@ -1,6 +0,0 @@
{
"include": [
"./node_modules/cypress",
"cypress/**/*.js"
]
}

View File

@@ -1,9 +0,0 @@
{
"reporterEnabled": "spec, mocha-junit-reporter",
"mochaJunitReporterReporterOptions": {
"jenkinsMode": true,
"rootSuiteTitle": "Cypress.npm",
"jenkinsClassnamePrefix": "Cypress.npm.",
"mochaFile": "results/junit/cypress.npm.[hash].xml"
}
}

View File

@@ -1,27 +0,0 @@
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"@jc21/cypress-swagger-validation": "^0.0.9",
"@jc21/restler": "^3.4.0",
"chalk": "^4.1.0",
"cypress": "^5.6.0",
"cypress-multi-reporters": "^1.4.0",
"cypress-plugin-retries": "^1.5.2",
"eslint": "^7.6.0",
"eslint-plugin-align-assignments": "^1.1.2",
"eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-cypress": "^2.11.1",
"lodash": "^4.17.19",
"mocha": "^8.1.1",
"mocha-junit-reporter": "^2.0.0"
},
"scripts": {
"cypress": "cypress open --config-file=cypress/config/dev.json --config baseUrl=${BASE_URL:-http://127.0.0.1:3081}",
"cypress:headless": "cypress run --config-file=cypress/config/dev.json --config baseUrl=${BASE_URL:-http://127.0.0.1:3081}"
},
"author": "",
"license": "ISC"
}

File diff suppressed because it is too large Load Diff