diff --git a/.gitignore b/.gitignore index 91223703..808df5af 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,6 @@ jspm_packages .DS_Store .idea /public +/test/.nohost/ +test/app/assets/.nohost/properties +test/app/assets/.nohost/.backup/properties diff --git a/package-lock.json b/package-lock.json index e401d605..5c59c57c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -983,6 +983,107 @@ "@babel/helper-plugin-utils": "^7.10.4" } }, + "@babel/plugin-transform-react-display-name": { + "version": "7.12.13", + "resolved": "http://r.tnpm.oa.com/@babel%2fplugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.13.tgz", + "integrity": "sha512-MprESJzI9O5VnJZrL7gg1MpdqmiFcUv41Jc7SahxYsNP2kDkFqClxxTZq+1Qv4AFCamm+GXMRDQINNn+qrxmiA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.12.13", + "resolved": "http://r.tnpm.oa.com/@babel%2fhelper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz", + "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==", + "dev": true + } + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.12.17", + "resolved": "http://r.tnpm.oa.com/@babel%2fplugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.17.tgz", + "integrity": "sha512-mwaVNcXV+l6qJOuRhpdTEj8sT/Z0owAVWf9QujTZ0d2ye9X/K+MTOTSizcgKOj18PGnTc/7g1I4+cIUjsKhBcw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/types": "^7.12.17" + }, + "dependencies": { + "@babel/helper-annotate-as-pure": { + "version": "7.12.13", + "resolved": "http://r.tnpm.oa.com/@babel%2fhelper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz", + "integrity": "sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-module-imports": { + "version": "7.12.13", + "resolved": "http://r.tnpm.oa.com/@babel%2fhelper-module-imports/-/helper-module-imports-7.12.13.tgz", + "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==", + "dev": true, + "requires": { + "@babel/types": "^7.12.13" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.12.13", + "resolved": "http://r.tnpm.oa.com/@babel%2fhelper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz", + "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==", + "dev": true + }, + "@babel/plugin-syntax-jsx": { + "version": "7.12.13", + "resolved": "http://r.tnpm.oa.com/@babel%2fplugin-syntax-jsx/-/plugin-syntax-jsx-7.12.13.tgz", + "integrity": "sha512-d4HM23Q1K7oq/SLNmG6mRt85l2csmQ0cHRaxRXjKW0YFdEXqlZ5kzFQKH5Uc3rDJECgu+yCRgPkG04Mm98R/1g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/types": { + "version": "7.12.17", + "resolved": "http://r.tnpm.oa.com/@babel%2ftypes/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.12.11", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "http://r.tnpm.oa.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@babel/plugin-transform-react-jsx-development": { + "version": "7.12.17", + "resolved": "http://r.tnpm.oa.com/@babel%2fplugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.17.tgz", + "integrity": "sha512-BPjYV86SVuOaudFhsJR1zjgxxOhJDt6JHNoD48DxWEIxUCAMjV1ys6DYw4SDYZh0b1QsS2vfIA9t/ZsQGsDOUQ==", + "dev": true, + "requires": { + "@babel/plugin-transform-react-jsx": "^7.12.17" + } + }, + "@babel/plugin-transform-react-pure-annotations": { + "version": "7.12.1", + "resolved": "http://r.tnpm.oa.com/@babel%2fplugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.12.1.tgz", + "integrity": "sha512-RqeaHiwZtphSIUZ5I85PEH19LOSzxfuEazoY7/pWASCAIBuATQzpSVD+eT6MebeeZT2F4eSL0u4vw6n4Nm0Mjg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, "@babel/plugin-transform-regenerator": { "version": "7.12.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz", @@ -1175,6 +1276,27 @@ "esutils": "^2.0.2" } }, + "@babel/preset-react": { + "version": "7.12.13", + "resolved": "http://r.tnpm.oa.com/@babel%2fpreset-react/-/preset-react-7.12.13.tgz", + "integrity": "sha512-TYM0V9z6Abb6dj1K7i5NrEhA13oS5ujUYQYDfqIBXYHOc2c2VkFgc+q9kyssIyUfy4/hEwqrgSlJ/Qgv8zJLsA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/plugin-transform-react-display-name": "^7.12.13", + "@babel/plugin-transform-react-jsx": "^7.12.13", + "@babel/plugin-transform-react-jsx-development": "^7.12.12", + "@babel/plugin-transform-react-pure-annotations": "^7.12.1" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.12.13", + "resolved": "http://r.tnpm.oa.com/@babel%2fhelper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz", + "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==", + "dev": true + } + } + }, "@babel/runtime": { "version": "7.12.5", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", @@ -3697,48 +3819,10 @@ } }, "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - } - } + "version": "7.0.0-bridge.0", + "resolved": "http://r.tnpm.oa.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "dev": true }, "babel-eslint": { "version": "10.1.0", @@ -3754,22 +3838,6 @@ "resolve": "^1.12.0" } }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "dev": true, - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - } - }, "babel-helper-bindify-decorators": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz", @@ -3931,16 +3999,6 @@ "babel-types": "^6.24.1" } }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, "babel-jest": { "version": "26.6.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", @@ -4762,21 +4820,6 @@ "babel-plugin-transform-object-rest-spread": "^6.22.0" } }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "dev": true, - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - } - }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -7178,15 +7221,6 @@ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", "dev": true }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -9470,16 +9504,6 @@ "react-is": "^16.7.0" } }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -10365,12 +10389,6 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, - "is-finite": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", - "dev": true - }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -12726,12 +12744,6 @@ } } }, - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", - "dev": true - }, "json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", @@ -14445,12 +14457,6 @@ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", "dev": true }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -16750,15 +16756,6 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -17720,15 +17717,6 @@ "urix": "^0.1.0" } }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "^0.5.6" - } - }, "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", @@ -18949,12 +18937,6 @@ "punycode": "^2.1.1" } }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, "tsconfig-paths": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", diff --git a/package.json b/package.json index d2aad564..472b3651 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "start": "node bin/nohost run", "docs:dev": "vuepress dev docs", "docs:build": "vuepress build docs", - "test": "jest --config=./test/jest/jest.config.js --coverage", + "test": "jest --config=./test/jest/jest.config.js --coverage --detectOpenHandles --forceExit", "test:watch": "jest --config=./test/jest/jest.config.js --watchAll --coverage" }, "registry": "https://registry.npmjs.org/@nohost/server", @@ -43,6 +43,7 @@ "antd": "^3.25.3", "babel-core": "^6.25.0", "babel-eslint": "^10.0.3", + "babel-jest": "^26.6.3", "babel-loader": "^7.1.1", "babel-plugin-import": "^1.2.1", "babel-plugin-transform-class-properties": "^6.24.1", diff --git a/test/.nohost/.backup/properties b/test/.nohost/.backup/properties index 2afd1ce0..e6f453da 100644 --- a/test/.nohost/.backup/properties +++ b/test/.nohost/.backup/properties @@ -1 +1 @@ -{"filesOrder":[],"domain":"abc.com","latestVersion":"0.5.34","admin":{"username":"admin","password":"60149a289a3623cd214943af2892e103f4bddafb"}} +{"filesOrder":[],"domain":"","admin":{"username":"admin","password":"7c4a8d09ca3762af61e59520943dc26494f8941b"},"latestVersion":"0.6.5"} diff --git a/test/.nohost/properties b/test/.nohost/properties index 2afd1ce0..e6f453da 100644 --- a/test/.nohost/properties +++ b/test/.nohost/properties @@ -1 +1 @@ -{"filesOrder":[],"domain":"abc.com","latestVersion":"0.5.34","admin":{"username":"admin","password":"60149a289a3623cd214943af2892e103f4bddafb"}} +{"filesOrder":[],"domain":"","admin":{"username":"admin","password":"7c4a8d09ca3762af61e59520943dc26494f8941b"},"latestVersion":"0.6.5"} diff --git a/test/app/assets/.nohost/.backup/properties b/test/app/assets/.nohost/.backup/properties new file mode 100644 index 00000000..96cc0bd4 --- /dev/null +++ b/test/app/assets/.nohost/.backup/properties @@ -0,0 +1 @@ +{"filesOrder":[],"domain":"abc.com","admin":{"username":"admin","password":"60149a289a3623cd214943af2892e103f4bddafb"},"latestVersion":"0.6.5"} diff --git a/test/app/assets/.nohost/properties b/test/app/assets/.nohost/properties new file mode 100644 index 00000000..96cc0bd4 --- /dev/null +++ b/test/app/assets/.nohost/properties @@ -0,0 +1 @@ +{"filesOrder":[],"domain":"abc.com","admin":{"username":"admin","password":"60149a289a3623cd214943af2892e103f4bddafb"},"latestVersion":"0.6.5"} diff --git a/test/index.test.js b/test/index.test.js index 1aedb3c2..3900765f 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -4,11 +4,12 @@ * All Tencent Modifications are Copyright (C) THL A29 Limited. * nohost-环境配置与抓包调试平台 is licensed under the MIT License except for the third-party components listed below. */ - const startServer = require('../index'); +const { httpRequire } = require('./utils'); // debug mode const options = { + port: 9001, debugMode: 'product', }; @@ -16,7 +17,56 @@ const cb = jest.fn(); // Test index.js describe('index', () => { - test('should callback be called', () => { + test('9001 port', () => { expect(startServer(options, cb)).toBeUndefined(); }); + + test('9002 port', () => { + options.port = 9002; + options.mode = 'prod'; + expect(startServer(options, cb)).toBeUndefined(); + }); + + test('option is function', () => { + expect(startServer(cb, '')).toBeUndefined(); + }); + + test('should response be matched index html', done => { + options.port = 3013; + startServer(options, cb); + + httpRequire('http://127.0.0.1:3013').then(str => { + expect(str).toContain('选择环境'); + done(); + }); + }); + + test('should response be matched share html', done => { + options.port = 3003; + startServer(options, cb); + + httpRequire('http://127.0.0.1:3003/account/sda/share/').then(str => { + expect(str).toContain('查看抓包'); + done(); + }); + }); + + test('should response be matched export html', done => { + options.port = 3004; + startServer(options, cb); + + httpRequire('http://127.0.0.1:3004/export_sessions').then(str => { + expect(str).toContain('Method Not Allowed'); + done(); + }); + }); + + test('should response be matched export html', done => { + options.port = 3005; + startServer(options, cb); + httpRequire('http://127.0.0.1:3005/nohost_share/').then(str => { + expect(str).toContain('查看抓包'); + done(); + }); + }); }); diff --git a/test/jest/babel.config.js b/test/jest/babel.config.js deleted file mode 100644 index a0a1ef2c..00000000 --- a/test/jest/babel.config.js +++ /dev/null @@ -1,27 +0,0 @@ -/* Tencent is pleased to support the open source community by making nohost-环境配置与抓包调试平台 available. -* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. The below software in -* this distribution may have been modified by THL A29 Limited ("Tencent Modifications"). -* All Tencent Modifications are Copyright (C) THL A29 Limited. -* nohost-环境配置与抓包调试平台 is licensed under the MIT License except for the third-party components listed below. -*/ - -module.exports = { - presets: [ - [ - '@babel/preset-env', - { - targets: { - node: 'current', - }, - }, - ], - ], - plugins: [ - ['@babel/plugin-proposal-decorators', { legacy: true }], - ['@babel/plugin-proposal-clas s-properties', { loose: true }], - ], - // jest config - test: [ - 'jest', - ], -}; diff --git a/test/jest/jest.config.js b/test/jest/jest.config.js index 1c527253..49670524 100644 --- a/test/jest/jest.config.js +++ b/test/jest/jest.config.js @@ -5,21 +5,22 @@ * nohost-环境配置与抓包调试平台 is licensed under the MIT License except for the third-party components listed below. */ -const path = require('path'); +// const path = require('path'); module.exports = { + // verbose: true, moduleFileExtensions: ['js'], - rootDir: '..', - transform: { - // '^.+\\.(ts|tsx)$': 'ts-jest', - // 加载babel配置, - '^.+\\.(t|j)s?$': ['babel-jest', { configFile: path.resolve(__dirname, 'babel.config.js') }], - }, + transform: {}, testMatch: ['**/test/**/*.test.js'], testEnvironment: 'node', reporters: ['default'], coveragePathIgnorePatterns: [ '/node_modules/', + '/test/', ], + clearMocks: true, coverageReporters: ['json', 'json-summary', 'lcov', 'text', 'clover'], + coverageDirectory: 'test/coverage', + rootDir: '../../', + testTimeout: 30000, }; diff --git a/test/lib/index.test.js b/test/lib/index.test.js index 6f85302c..65ea344b 100644 --- a/test/lib/index.test.js +++ b/test/lib/index.test.js @@ -1,20 +1,159 @@ -const path = require('path'); -const kill = require('kill-port'); +const { setPath } = require('../utils'); -const filePath = path.join(process.cwd(), 'test'); -process.env.WHISTLE_PATH = filePath; +setPath(); + +jest.mock('../../lib/main/util', () => { + return { + passToWhistle: () => true, + passToService: () => true, + }; +}); + +jest.mock('http', () => { + let i = 0; + const reqSock = { + on: type => type, + once: type => type, + pipe: () => reqSock, + setHeader: () => jest.fn(), + end: () => jest.fn(), + }; + + const whistleReq = { + headers: { + 'content-length': 10, + 'x-forwarded-for': 'localhost:9001', + host: 'admin.nohost.pro', + }, + _hasError: false, + dispatch(name) { + this.dispatchList[name](); + }, + dispatchList: [], + on (type, cb) { + this.dispatchList[type] = cb(); + }, + once: (type, cb) => cb(), + socket: { + remoteAddress: 'nohost.com', + end: () => true, + }, + set: () => true, + pipe: client => { + client.on('data', () => {}); + client.on('end', () => { + }); + }, + setHeader: () => jest.fn(), + req: { + on: () => true, + once: () => true, + setHeader: () => jest.fn(), + headers: { + 'x-forwarded-for': 'localhost:9001', + }, + socket: { + remoteAddress: 'nohost.com', + end: () => true, + }, + pipe: client => { + client.on('data', () => {}); + client.on('end', () => { + }); + }, + }, + }; + + const runConfig = ['', '', + () => { + whistleReq.headers.host = ''; + }, + () => { + whistleReq.headers = { + host: null, + 'x-whistle-nohost-env': '$123', + 'x-whistle-nohost-rule': '$123', + 'x-whistle-nohost-value': '$123', + }; + }, + ]; + + function changeReq() { + const fn = runConfig[i]; + if (fn) { fn(); } + i++; + } + return { + request: (opts, cb) => { + const obj = { + on: (type, callback) => { + if (type === 'end') { + callback(); + } + }, + statusCode: 200, + setEncoding: () => '', + }; + cb(obj); + return obj; + }, + createServer: (callback) => { + changeReq(); + callback(whistleReq, reqSock); + return { + on: (type, cb) => cb(whistleReq, reqSock), + listen: (port, host, cb) => cb(), + removeAllListeners: () => true, + close: (cb) => cb(), + }; + }, + }; +}); const createServer = require('../../lib/index'); const options = { - username: '', - password: '', - port: '8081', + username: 'admin', + password: '123456', + port: '3032', + storage: '127.0.0.1:9001~9999', }; + describe('lib index', () => { - test('', () => { - createServer(options); - kill(30017, 'tcp'); + test('createServer', () => { + const cb = jest.fn(); + const server = createServer(options, cb); + expect(server.timeout).toBe(360000); + }); +}); + +describe('lib index with storage is 127.0.0.1:10021', () => { + test('should option return array and port is 10021', () => { + const cb = jest.fn(); + options.port = '10021'; + options.storage = '127.0.0.1:10021'; + createServer(options, cb); + expect(options.storage[0].port).toBe(10021); + }); +}); + +describe('lib index with storage is abc', () => { + test('createServer', () => { + const cb = jest.fn(); + options.port = '10009'; + options.storage = 'abc'; + createServer(options, cb); + expect(options.storage).toBeUndefined(); + }); +}); + +describe('lib index with headers', () => { + test('should whistleReq.header.host', () => { + const cb = jest.fn(); + options.port = '10031'; + options.storage = '127.0.0.1:9001~9999'; + createServer(options, cb); + expect(options.port).toBe(10031); }); }); diff --git a/test/lib/main/cgi/getSetting.test.js b/test/lib/main/cgi/getSetting.test.js index 049ce29d..a5c39818 100644 --- a/test/lib/main/cgi/getSetting.test.js +++ b/test/lib/main/cgi/getSetting.test.js @@ -1,8 +1,6 @@ -const path = require('path'); - -const filePath = path.join(process.cwd(), 'test'); -process.env.WHISTLE_PATH = filePath; +const { setPath } = require('../../../utils'); +setPath(); const getSetting = require('../../../../lib/main/cgi/getSettings'); const storage = { diff --git a/test/lib/main/cgi/removeCert.test.js b/test/lib/main/cgi/removeCert.test.js index 3136df19..2148a76f 100644 --- a/test/lib/main/cgi/removeCert.test.js +++ b/test/lib/main/cgi/removeCert.test.js @@ -1,8 +1,6 @@ -const path = require('path'); - -const filePath = path.join(process.cwd(), 'test'); -process.env.WHISTLE_PATH = filePath; +const { setPath } = require('../../../utils'); +setPath(); const removeCert = require('../../../../lib/main/cgi/removeCert'); const certsMgr = require('../../../../lib/main/certsMgr'); const whistleMgr = require('../../../../lib/main/whistleMgr'); diff --git a/test/lib/main/cgi/restart.test.js b/test/lib/main/cgi/restart.test.js index 51aea9b4..a74e6e77 100644 --- a/test/lib/main/cgi/restart.test.js +++ b/test/lib/main/cgi/restart.test.js @@ -1,7 +1,6 @@ -const path = require('path'); +const { setPath } = require('../../../utils'); -const filePath = path.join(process.cwd(), 'test'); -process.env.WHISTLE_PATH = filePath; +setPath(); const restart = require('../../../../lib/main/cgi/restart'); const whistleMgr = require('../../../../lib/main/whistleMgr'); diff --git a/test/lib/main/cgi/setAdmin.test.js b/test/lib/main/cgi/setAdmin.test.js index 8889cd3b..253e3ab2 100644 --- a/test/lib/main/cgi/setAdmin.test.js +++ b/test/lib/main/cgi/setAdmin.test.js @@ -1,7 +1,6 @@ -const path = require('path'); +const { setPath } = require('../../../utils'); -const filePath = path.join(process.cwd(), 'test'); -process.env.WHISTLE_PATH = filePath; +setPath(); const setAdmin = require('../../../../lib/main/cgi/setAdmin'); const storage = require('../../../../lib/main/storage'); diff --git a/test/lib/main/cgi/setDomain.test.js b/test/lib/main/cgi/setDomain.test.js index ea7589c0..08e6630c 100644 --- a/test/lib/main/cgi/setDomain.test.js +++ b/test/lib/main/cgi/setDomain.test.js @@ -1,8 +1,6 @@ -const path = require('path'); - -const filePath = path.join(process.cwd(), 'test'); -process.env.WHISTLE_PATH = filePath; +const { setPath } = require('../../../utils'); +setPath(); const setDomain = require('../../../../lib/main/cgi/setDomain'); const storage = require('../../../../lib/main/storage'); const whistleMgr = require('../../../../lib/main/whistleMgr'); diff --git a/test/lib/main/cgi/status.test.js b/test/lib/main/cgi/status.test.js new file mode 100644 index 00000000..89ab48c9 --- /dev/null +++ b/test/lib/main/cgi/status.test.js @@ -0,0 +1,81 @@ + +const Koa = require('koa'); +const router = require('koa-router')(); +const serve = require('koa-static'); +const path = require('path'); +const { createServer } = require('http'); +const { httpPost } = require('../../../utils'); +const status = require('../../../../lib/main/cgi/status'); + +const setupRouter = (r) => { + r.get('/status', status); +}; + + +const MAX_AGE = 1000 * 60 * 5; +const app = new Koa(); + +setupRouter(router); +app.use(router.routes()); +app.use(router.allowedMethods()); +app.use(serve(path.join(__dirname, '../../../../../public/'), { maxage: MAX_AGE })); + +const cb = jest.fn(); + +// debug mode +const options = { + port: 10012, + debugMode: 'product', +}; + + +const server = createServer(options, (req, res) => { + app.callback()(req, res); +}); + +server.listen(options.port, '127.0.0.1', cb); +const servers = '111.222.333.444:55555/67,888.999.999.999:00000/123,888.999.999.999:00000/123'; + +describe('test status', () => { + const params = { + host: '127.0.0.1', + port: options.port, + method: 'GET', + path: '/status?space=123&group=456', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'x-nohost-servers': Buffer.from(servers).toString('base64'), + }, + }; + + test('get status', done => { + httpPost(params).then((res) => { + expect(res).toContain('workerNum'); + done(); + }); + }); + + test('get status with empty x-nohost-servers', done => { + params.headers['x-nohost-servers'] = ''; + httpPost(params).then((res) => { + expect(res).toContain('workerNum'); + done(); + }); + }); + + test('get status with wrong x-nohost-servers', done => { + params.headers['x-nohost-servers'] = Buffer.from('123').toString('base64'); + httpPost(params).then((res) => { + expect(res).toContain('workerNum'); + done(); + }); + }); + + test('get status with empty query', done => { + params.path = '/status'; + httpPost(params).then((res) => { + expect(res).toContain('workerNum'); + done(); + }); + }); +}); diff --git a/test/lib/main/cgi/uploadCerts.test.js b/test/lib/main/cgi/uploadCerts.test.js new file mode 100644 index 00000000..fe11b0dd --- /dev/null +++ b/test/lib/main/cgi/uploadCerts.test.js @@ -0,0 +1,66 @@ +const { setPath } = require('../../../utils'); + +setPath(); + +const uploadCerts = require('../../../../lib/main/cgi/uploadCerts'); +const whistleMgr = require('../../../../lib/main/whistleMgr'); +const certsMgr = require('../../../../lib/main/certsMgr'); + +const ctx = { + request: { + body: { + certs: ['aaa', 'bbb'], + }, + }, + whistleMgr, + certsMgr, +}; + +const restart = jest.fn(); +ctx.whistleMgr.restart = restart; +ctx.certsMgr.write = name => name; + +describe('main cgi uploadCerts', () => { + test('restart should be called', async() => { + await uploadCerts(ctx); + expect(restart).toBeCalled(); + }); + + test('ec should be 0', async() => { + ctx.request.body = { + 'a,': ['', ''], + }; + await uploadCerts(ctx); + expect(ctx.body.ec).toBe(0); + }); + + test('ec should be 0', async() => { + ctx.request.body = ''; + await uploadCerts(ctx); + expect(ctx.body.ec).toBe(0); + }); + + test('ec should be 0 while certs is not Array', async() => { + ctx.request.body = { + certs: 123, + }; + await uploadCerts(ctx); + expect(ctx.body.ec).toBe(0); + }); + + test('ec should be 0 while key is empty', async() => { + ctx.request.body = { + certs: ['', '213'], + }; + await uploadCerts(ctx); + expect(ctx.body.ec).toBe(0); + }); + + test('ec should be 0 while key is > max legth', async() => { + ctx.request.body = { + certs: [''.padEnd(1024 * 66 + 2, 0), '213'], + }; + await uploadCerts(ctx); + expect(ctx.body.ec).toBe(0); + }); +}); diff --git a/test/lib/main/router.test.js b/test/lib/main/router.test.js new file mode 100644 index 00000000..2f6e2f30 --- /dev/null +++ b/test/lib/main/router.test.js @@ -0,0 +1,62 @@ +const Koa = require('koa'); +const router = require('koa-router')(); +const serve = require('koa-static'); +const path = require('path'); +const { createServer } = require('http'); +const { httpRequire, setPath } = require('../../utils'); + +setPath(); +const setupRouter = require('../../../lib/main/router'); + + +const MAX_AGE = 1000 * 60 * 5; +const app = new Koa(); + +setupRouter(router); +app.use(router.routes()); +app.use(router.allowedMethods()); +app.use(serve(path.join(__dirname, '../../../../../public/'), { maxage: MAX_AGE })); + +const cb = jest.fn(); + +// debug mode +const options = { + port: 10010, + debugMode: 'product', +}; + +const server = createServer(options, (req, res) => { + app.callback()(req, res); +}); +server.listen(options.port, '127.0.0.1', cb); + +const REQUEST_URL = `http://127.0.0.1:${options.port}`; +describe('lib main router', () => { + test('/user/wonder redirect to /account/wonder', done => { + httpRequire(`${REQUEST_URL}/user/wonder`).then((res) => { + expect(res).toContain('/account/wonder'); + done(); + }); + }); + + test('/p/plugin.share/ab', done => { + httpRequire(`${REQUEST_URL}/p/plugin.share/ab`).then((res) => { + expect(res).not.toBeNull(); + done(); + }); + }); + + test('/p/wonder', done => { + httpRequire(`${REQUEST_URL}/p/wonder`).then((res) => { + expect(res).toContain('/p/wonder/'); + done(); + }); + }); + + test('/account/$123/', done => { + httpRequire(`${REQUEST_URL}/account/$123/`).then((res) => { + expect(res).toContain('Not Found'); + done(); + }); + }); +}); diff --git a/test/lib/main/storage.test.js b/test/lib/main/storage.test.js index a3f5fdee..dad5a615 100644 --- a/test/lib/main/storage.test.js +++ b/test/lib/main/storage.test.js @@ -1,8 +1,6 @@ -const path = require('path'); - -const filePath = path.join(process.cwd(), 'test'); -process.env.WHISTLE_PATH = filePath; +const { setPath } = require('../../utils'); +setPath(); const { checkDomain, isUIRequest } = require('../../../lib/main/storage'); const req = { @@ -37,9 +35,13 @@ describe('lib main strage test', () => { expect(isUIRequest(req)).toBeTruthy(); }); - test('should isUIRequest result be true', () => { + test('should isUIRequest result be true', done => { req.headers['x-whistle-nohost-ui'] = 1; req.url = 'https://qq/.nohost-inner-path./com'; expect(isUIRequest(req)).toBeTruthy(); + // 覆盖回调 + setTimeout(() => { + done(); + }, 3000); }); }); diff --git a/test/lib/main/test/app/assets/.nohost/properties b/test/lib/main/test/app/assets/.nohost/properties new file mode 100644 index 00000000..e69de29b diff --git a/test/lib/main/util.test.js b/test/lib/main/util.test.js index 2e062cf4..a6eb2c5f 100644 --- a/test/lib/main/util.test.js +++ b/test/lib/main/util.test.js @@ -1,80 +1,80 @@ -const path = require('path'); +const url = require('url'); +const { createServer } = require('http'); +const { httpRequire, setPath } = require('../../utils'); -const filePath = path.join(process.cwd(), 'test'); -process.env.WHISTLE_PATH = filePath; +setPath(); +const { + passToWhistle, + passToService, +} = require('../../../lib/main/util'); -// process.on('unhandledRejection', function (err) { +jest.mock('@nohost/connect', () => { + return { + request: () => { + return { + statusCode: 200, + pipe: () => true, + }; + }, + getRawHeaders: () => true, + tunnel: () => true, + upgrade: () => true, + }; +}); -// }); -const { - removeIPV6Prefix, - getClientIp, - destroy, - onClose, -} = require('../../../lib/main/util'); +const cb = jest.fn(); -describe('main util', () => { - test('should removeIPV6Prefix return empty', () => { - expect(removeIPV6Prefix(123)).toBe(''); - }); +// debug mode +const options = { + port: 10011, + debugMode: 'product', +}; - test('should removeIPV6Prefix return empty', () => { - const req = { - headers: { - XFF: '::ffff:192.1.56.10', - }, - socket: { - remoteAddress: '192.168.1.1', - }, - }; - expect(getClientIp(req)).toEqual('192.168.1.1'); - }); +// passToService 使用 +let ctx = null; - test('should destory be called', () => { - const destroyFn = jest.fn(); - const req = { - destroy: destroyFn, - }; +const testUrl = ['/head', '/upgrade', '/tunnel', '/error']; +const server = createServer(options, async (req, res) => { + const { pathname } = url.parse(req.url); + res.writeHead(200, { 'Content-Type': 'text/plain' }); + if (pathname === '/tunnel') { + res.writeHead = ''; + } else if (pathname === '/upgrade') { + res.writeHead = ''; + req.isUpgrade = false; + } else if (pathname === '/service') { + ctx = { req, res }; + } - destroy(req); - expect(destroyFn).toBeCalled(); - }); + await passToWhistle(req, res); + if (testUrl.includes(pathname)) { + res.write('Hello World!'); + res.end(); + } +}); - test('should abort be called', () => { - const abortFn = jest.fn(); - const req = { - abort: abortFn, - }; +server.listen(options.port, '127.0.0.1', cb); - destroy(req); - expect(abortFn).toBeCalled(); +describe('main util', () => { + test('passToWhistle tunnel test', done => { + httpRequire(`http://127.0.0.1:${options.port}/tunnel`).then(res => { + expect(res).toBe('Hello World!'); + done(); + }); }); - test('should onClose return undefined', () => { - const req = { - _hasError: false, - on: (type, cb) => cb(), - once: (type, cb) => cb(), - }; - const res = jest.fn(); - expect(onClose(req, res)).toBe(undefined); + test('passToWhistle upgrade test', done => { + httpRequire(`http://127.0.0.1:${options.port}/upgrade`).then(res => { + expect(res).toBe('Hello World!'); + done(); + }); }); - // test('should getWhistleData return promise ',()=>{ - // const req = { - // headers:{ - // 'content-length': 10, - // }, - // _hasError:false, - // dispatch: name => dispatchList[name](), - // dispatchList: [], - // on: function (type, cb) { - // this.dispatchList[type] = cb() - // }, - // once: (type,cb) => cb(), - // } - // const res = jest.fn() - // expect(getWhistleData(req)).toBeInstanceOf(Promise) - // }) + test('passToService upgrade test', async() => { + httpRequire(`http://127.0.0.1:${options.port}/service`).then(async() => { + await passToService(ctx); + expect(ctx.body).toBe(''); + }); + }); }); diff --git a/test/lib/main/whistleMgr.test.js b/test/lib/main/whistleMgr.test.js index 31319690..0fa84db3 100644 --- a/test/lib/main/whistleMgr.test.js +++ b/test/lib/main/whistleMgr.test.js @@ -3,11 +3,22 @@ const path = require('path'); const filePath = path.join(process.cwd(), 'test'); process.env.WHISTLE_PATH = filePath; -const { fork } = require('../../../lib/main/whistleMgr'); +const { fork, restart } = require('../../../lib/main/whistleMgr'); describe('lib main whistleMgr', () => { - test('should fork return Promise', () => { - const server = fork(); - expect(server).toBeInstanceOf(Promise); + const server = fork(); + test('should fork return Promise', done => { + server.then(port => { + expect(port).toBeGreaterThanOrEqual(3000); + done(); + }); + }); + + test('should _eventsCount be 0 after restart', done => { + server.then(() => { + restart(); + expect(server.whistleProcess._eventsCount).toBe(0); + done(); + }); }); }); diff --git a/test/lib/main/worker.test.js b/test/lib/main/worker.test.js new file mode 100644 index 00000000..da8caeb2 --- /dev/null +++ b/test/lib/main/worker.test.js @@ -0,0 +1,15 @@ +const { kill, fork } = require('../../../lib/main/worker'); + +describe('test main worker', () => { + test('fork, should port return > 0 ', done => { + fork(0).then(port => { + expect(port).toBeGreaterThanOrEqual(0); + done(); + }); + }); + + test('fork, kill port should return undefined', done => { + expect(kill(0)).toBeUndefined(); + done(); + }); +}); diff --git a/test/lib/util/getPort.test.js b/test/lib/util/getPort.test.js index 686f6404..a154c63e 100644 --- a/test/lib/util/getPort.test.js +++ b/test/lib/util/getPort.test.js @@ -1,15 +1,29 @@ -const getPort = require('../../../lib/util/getPort'); -describe('util getPort', () => { - test('should server start', () => { - expect(getPort(() => { - })); - }); +jest.mock('http', () => { + return { + createServer: () => { + return { + listen: (port, host, callback) => { callback(); }, + removeAllListeners: () => true, + on: () => true, + close: (callb) => callb(), + }; + }, + }; +}); - test('should server error', () => { - expect(getPort(() => { +const getPort = require('../../../lib/util/getPort'); + +let mockPort; + +function portCb(port) { + mockPort = port; +} - })); +describe('util getPort', () => { + test('should server start', () => { + getPort(portCb); + expect(mockPort).toBeGreaterThanOrEqual(30013); }); }); diff --git a/test/lib/util/login.test.js b/test/lib/util/login.test.js index 6804ac8a..f8c68384 100644 --- a/test/lib/util/login.test.js +++ b/test/lib/util/login.test.js @@ -16,19 +16,20 @@ const cookies = { set: key => key, }; +const ctx = { + cookies, + req: { + headers: {}, + }, + set: name => name, +}; + describe('util login', () => { test('should login success with username is empty', () => { const authConf = { username: '', password: 'da39a3ee5e6b4b0d3255bfef95601890afd80709', }; - const ctx = { - cookies, - req: { - headers: {}, - }, - set: name => name, - }; expect(checkLogin(ctx, authConf)).toBeTruthy(); }); }); @@ -39,15 +40,7 @@ describe('util login', () => { username: 'admin', password: '7c4a8d09ca3762af61e59520943dc26494f8941b', }; - const ctx = { - cookies, - req: { - headers: { - authorization: 'Basic YWRtaW46MTIzNDU2', - }, - }, - set: name => name, - }; + ctx.req.headers.authorization = 'Basic YWRtaW46MTIzNDU2'; expect(checkLogin(ctx, authConf)).toBeTruthy(); }); }); @@ -58,15 +51,7 @@ describe('util login', () => { username: 'admin2', password: '7c4a8d09ca3762af61e59520943dc26494f8941b', }; - const ctx = { - cookies, - req: { - headers: { - authorization: 'Basic YWRtaW46MTIzNDU2', - }, - }, - set: name => name, - }; + ctx.req.headers.authorization = 'Basic YWRtaW46MTIzNDU2'; expect(checkLogin(ctx, authConf)).toBeFalsy(); }); }); diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 00000000..ad8ac872 --- /dev/null +++ b/test/utils.js @@ -0,0 +1,102 @@ + +const http = require('http'); +const path = require('path'); + +const filePath = path.join(process.cwd(), 'test/app/assets'); + +const socket = { + remotePort: 9001, + on: () => true, + once: () => true, + removeAllListeners: () => true, + destroy: () => true, + write: () => true, + end: () => true, + pipe: () => true, +}; + +const headers = { + 'content-length': 10, + 'x-forwarded-for': 'localhost:9001', +}; + +/** + * @description 设置证书所需的路径,避免文件报错 + */ +const setPath = () => { + process.env.WHISTLE_PATH = filePath; +}; + +/** + * @description 封装通用的 http 请求方法 + * @param {string} rquestPath http://127.0.0.1:3001 + */ +const httpRequire = (rquestPath) => { + return new Promise((resolve) => { + http.get(rquestPath, (data) => { + let str = ''; + data.on('data', (chunk) => { + str += chunk;// 监听数据响应,拼接数据片段 + }); + data.on('end', () => { + resolve(str); + }); + }); + }); +}; + +const httpPost = (options) => { + return new Promise((resolve) => { + const req = http.request(options, (data) => { + let str = ''; + data.on('data', (chunk) => { + str += chunk;// 监听数据响应,拼接数据片段 + }); + data.on('end', () => { + resolve(str); + }); + }); + req.end(); + }); +}; + +/** + * @description 获取mock whistleReq + */ +const getMockWhistleReq = () => { + return { + headers, + _hasError: false, + dispatch(name) { + this.dispatchList[name](); + }, + dispatchList: [], + on (type, cb) { + this.dispatchList[type] = cb(); + }, + once: (type, cb) => cb(), + socket, + set: () => true, + pipe: client => { + client.on('data', () => {}); + client.on('end', () => { + }); + }, + req: { + writeHead: false, + socket, + headers, + ...socket, + }, + }; +}; + +const getMockSocket = () => { + return socket; +}; + +exports.setPath = setPath; +exports.httpRequire = httpRequire; +exports.httpPost = httpPost; +exports.getMockWhistleReq = getMockWhistleReq; +exports.getMockSocket = getMockSocket;