├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── package-lock.json ├── package.json ├── templates ├── function-template.ejs └── test-template.ejs ├── test ├── integration-options10.x.js ├── integration10.x-babel.js ├── integration10.x.js ├── integration12.x.js ├── integration8.10.js ├── mochaPlugin.js ├── test-service-node10.x-babel │ ├── .npmignore │ ├── .serverless_plugins │ │ └── serverless-mocha-plugin │ │ │ └── index.js │ ├── handler.js │ ├── package.json │ ├── serverless.yml │ └── templates │ │ ├── function-template.ejs │ │ └── test-template.ejs ├── test-service-node10.x │ ├── .npmignore │ ├── .serverless_plugins │ │ └── serverless-mocha-plugin │ │ │ └── index.js │ ├── handler.js │ └── serverless.yml ├── test-service-node12.x │ ├── .npmignore │ ├── .serverless_plugins │ │ └── serverless-mocha-plugin │ │ │ └── index.js │ ├── handler.js │ └── serverless.yml ├── test-service-node8.10 │ ├── .npmignore │ ├── .serverless_plugins │ │ └── serverless-mocha-plugin │ │ │ └── index.js │ ├── handler.js │ └── serverless.yml ├── test-service-options │ ├── .env │ ├── .npmignore │ ├── .serverless_plugins │ │ └── serverless-mocha-plugin │ │ │ └── index.js │ ├── handler.js │ ├── serverless.yml │ └── testBuild │ │ ├── goodbye │ │ └── index.js │ │ └── handler.js ├── testUtils.js └── utils.js └── utils.js /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | tmp 3 | testBuild -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": "airbnb", 3 | "plugins": [], 4 | "rules": { 5 | "func-names": "off", 6 | 7 | // doesn't work in node v4 :( 8 | "strict": "off", 9 | "prefer-rest-params": "off", 10 | "react/require-extension" : "off", 11 | "import/no-extraneous-dependencies" : "off" 12 | }, 13 | "env": { 14 | "mocha": true 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "Code scanning - action" 2 | 3 | on: 4 | push: 5 | branches: [master, ] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [master] 9 | schedule: 10 | - cron: '0 13 * * 0' 11 | 12 | jobs: 13 | CodeQL-Build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v2 20 | with: 21 | # We must fetch at least the immediate parents so that if this is 22 | # a pull request then we can checkout the head. 23 | fetch-depth: 2 24 | 25 | # If this run was triggered by a pull request event, then checkout 26 | # the head of the pull request instead of the merge commit. 27 | - run: git checkout HEAD^2 28 | if: ${{ github.event_name == 'pull_request' }} 29 | 30 | # Initializes the CodeQL tools for scanning. 31 | - name: Initialize CodeQL 32 | uses: github/codeql-action/init@v1 33 | # Override language selection by uncommenting this and choosing your languages 34 | # with: 35 | # languages: go, javascript, csharp, python, cpp, java 36 | 37 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 38 | # If this step fails, then you should remove it and run the build manually (see below) 39 | - name: Autobuild 40 | uses: github/codeql-action/autobuild@v1 41 | 42 | # ℹ️ Command-line programs to run using the OS shell. 43 | # 📚 https://git.io/JvXDl 44 | 45 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 46 | # and modify them (or add more) to build your code if your project 47 | # uses a compiled language 48 | 49 | #- run: | 50 | # make bootstrap 51 | # make release 52 | 53 | - name: Perform CodeQL Analysis 54 | uses: github/codeql-action/analyze@v1 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | 35 | # IDE 36 | .idea 37 | 38 | # NYC 39 | .nyc_output 40 | 41 | # Mac 42 | .DS_Store 43 | 44 | tmp 45 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | matrix: 3 | include: 4 | - name: "Node v8" 5 | os: linux 6 | node_js: '8' 7 | env: TEST_SUITE=8.10 8 | - name: "Node v10" 9 | os: linux 10 | node_js: '10' 11 | env: TEST_SUITE=10.x 12 | - name: "Node v12" 13 | os: linux 14 | node_js: '12' 15 | env: TEST_SUITE=12.x 16 | script: 17 | - npm run lint 18 | - npx nyc mocha -t 30000 ./test/*$TEST_SUITE*.js 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 SC5 Online Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Serverless Mocha Plugin 2 | 3 | [![Build Status](https://travis-ci.org/nordcloud/serverless-mocha-plugin.svg?branch=master)](https://travis-ci.org/nordcloud/serverless-mocha-plugin) 4 | 5 | A Serverless Plugin for the [Serverless Framework](http://www.serverless.com), which 6 | adds support for test driven development using [mocha](https://mochajs.org/) 7 | 8 | **THIS PLUGIN REQUIRES SERVERLESS V1!** 9 | 10 | More familiar with Jest? Use [serverless-jest-plugin](https://github.com/sc5/serverless-jest-plugin). 11 | 12 | ## Introduction 13 | 14 | This plugin does the following: 15 | 16 | * It provides commands to create and run tests manually 17 | * It provides a command to create a function, which automatically also creates a test 18 | 19 | ## Installation 20 | 21 | In your service root, run: 22 | 23 | ```bash 24 | npm install --save-dev serverless-mocha-plugin 25 | ``` 26 | 27 | Add the plugin to `serverless.yml`: 28 | 29 | ```yml 30 | plugins: 31 | - serverless-mocha-plugin 32 | ``` 33 | 34 | ## Usage 35 | 36 | ### Creating functions 37 | 38 | Functions (and associated tests) can be created using the command 39 | 40 | ``` 41 | sls create function -f functionName --handler handler 42 | ``` 43 | 44 | e.g. 45 | 46 | ``` 47 | sls create function -f myFunction --handler functions/myFunction/index.handler 48 | ``` 49 | 50 | creates a new function `myFunction` into `serverless.yml` with a code template for 51 | the handler in `functions/myFunction/index.js` and a Javascript function `module.exports.handler` as the entrypoint for the Lambda function. A test template is also created into `test/myFunction.js`. Optionally tests can be created to specific folder using `--path` or `-p` switch, e.g. 52 | 53 | ``` 54 | sls create function -f myFunction --handler functions/myFunction/index.handler --path tests 55 | ``` 56 | 57 | To create an http event for the lambda, add the --httpEvent parameter, i.e. 58 | 59 | ``` 60 | sls create function -f myFunction --handler functions/myFunction/index.handler --httpEvent "[httpVerb] [relativePath]" 61 | ``` 62 | 63 | e.g. 64 | 65 | ``` 66 | sls create function -f myFunction --handler functions/myFunction/index.handler --httpEvent "post myResource" --httpEvent "get myResource" 67 | ``` 68 | 69 | ### Creating tests 70 | 71 | Functions can also be added manually using the mocha-create command 72 | 73 | ``` 74 | sls create test -f functionName 75 | ``` 76 | 77 | If you want to run the tests against the real Lambda functions, you can `initLiveModule()` instead of `getWrapper()`. You can also use `--live` flag and then you don't need to change your tests. 78 | 79 | ``` 80 | let wrapped = mochaPlugin.initLiveModule('myLambdaFunctionName'); 81 | ``` 82 | 83 | `initLiveModule()` and `getWrapper()` are helper methods to initialize [lambda-wrapper](https://github.com/nordcloud/lambda-wrapper), which is used under the hood. Both methods return wrapped function, which can be invoked with `.run({})` method and takes event object as an argument. 84 | 85 | ### Running tests 86 | 87 | Tests can be run directly using the "invoke test" command. This also initializes the environment variables based on your serverless.yml file and the SERVERLESS_TEST_ROOT variable that defines the root for the code to be tested. If you're running the tests locally (rather than on live Lambdas, as described below), it will also set the `IS_LOCAL` to `'true'` to match the behavior of [`sls invoke local`](https://serverless.com/framework/docs/providers/aws/cli-reference/invoke-local#environment). 88 | 89 | ``` 90 | sls invoke test [--stage stage] [--region region] [-t timeout] [-f function1] [-f function2] [...] 91 | ``` 92 | 93 | To use a mocha reporter (e.g. json), use the -R switch. Reporter options can be passed with the -O switch. 94 | 95 | If no function names are passed to "invoke test", all tests are run from the test/ directory and subdirectories. 96 | 97 | The default timeout for tests is 6 seconds. In case you need to apply a different timeout, that can be done in the test file 98 | using using .timeout(milliseconds) with the define, after, before or it -blocks. e.g. 99 | ``` 100 | it('implement tests here', () => { 101 | ... 102 | }).timeout(xxx); 103 | ``` 104 | 105 | To run test in specific folder use `--path` or `-p` switch. 106 | 107 | To run tests live against the actual deployed Lambdas, use the '--live' or '-l' switch. Please note that this will work only for tests created with module version 1.4 or higher. 108 | 109 | To run tests e.g. against built artefacts that reside in some other directory, use the '--root' or '-r' switch. e.g. 110 | ``` 111 | sls webpack -o testBuild 112 | sls invoke test --root testBuild 113 | rm -rf testBuild 114 | ``` 115 | 116 | 117 | ### Using own template for a test file 118 | 119 | The templates to use for new function Files can be determined with the custom `testTemplate` configuration in `serverless.yml` 120 | 121 | ```yaml 122 | custom: 123 | serverless-mocha-plugin: 124 | testTemplate: templates/myTest.js 125 | ``` 126 | 127 | Currently, there are three variables available for use in the template: 128 | 129 | - functionName - name of the function 130 | - functionPath - path to the function 131 | - handlerName - the name of the handler function 132 | 133 | If you'd like to get more information on the template engine, you check documentation of the [EJS project](http://ejs.co/). 134 | 135 | ### Using own template for function file 136 | 137 | The templates to use for new function Files can be determined with the custom `functionTemplate` configuration in `serverless.yml` 138 | 139 | ```yaml 140 | custom: 141 | serverless-mocha-plugin: 142 | functionTemplate: templates/myFunction.js 143 | ``` 144 | 145 | ### Running commands before / after tests 146 | 147 | The plugin can be configured to run commands before / after the tests. This is done by setting preTestCommands and postTestCommands in the plugin configuration. 148 | 149 | For example, start serverless-offline before tests and stop it after tests using the following configuration: 150 | 151 | ```yaml 152 | custom: 153 | serverless-mocha-plugin: 154 | preTestCommands: 155 | - bash startOffline.sh 156 | postTestCommands: 157 | - bash stopOffline.sh 158 | ``` 159 | 160 | Sample startOffline.sh: 161 | ``` 162 | TMPFILE=/var/tmp/offline$$.log 163 | if [ -f .offline.pid ]; then 164 | echo "Found file .offline.pid. Not starting." 165 | exit 1 166 | fi 167 | 168 | serverless offline 2>1 > $TMPFILE & 169 | PID=$! 170 | echo $PID > .offline.pid 171 | 172 | while ! grep "server ready" $TMPFILE 173 | do sleep 1; done 174 | 175 | rm $TMPFILE 176 | ``` 177 | 178 | **Note:** The example relies on the output of the `serverless offline` command. If the start script is not working for you, replace `"server ready"` with the string `serverless offline` prints as soon as the server is ready and listening. 179 | 180 | Sample stopOffline.sh 181 | ``` 182 | kill `cat .offline.pid` 183 | rm .offline.pid 184 | ``` 185 | 186 | ### Usage with [babel register](https://babeljs.io/docs/en/babel-register) 187 | 188 | If you use mocha with [babel compiler](https://github.com/mochajs/mocha/wiki/compilers-deprecation) e.g. `sls invoke test --compilers js:@babel/register` \ 189 | Babel configuration can be determined with the custom `babelOptions` configuration in serverless.yml 190 | 191 | ``` 192 | custom: 193 | serverless-mocha-plugin: 194 | babelOptions: 195 | presets: [["@babel/env", { "targets": { "node": "8.10" }, "shippedProposals": true, "useBuiltIns": "usage" }]] 196 | plugins: 197 | - ["@babel/plugin-transform-runtime"] 198 | ``` 199 | ## Release History (1.x) 200 | 201 | * 2019/11/xx - v1.12.0 - support for node12 202 | fix --compiler option parsing 203 | * 2019/07/25 - v1.11.0 - support for node10 204 | deprecated node6 205 | * 2019/04/02 - v1.10.0 - add timeout parameter 206 | add babel options 207 | * 2018/12/15 - v1.9.1 - fix to work with serverless 1.33 and later 208 | * 2018/09/16 - v1.9.0 - add support for --exit option 209 | * 2018/04/03 - v1.8.0 - add support for Node 8 210 | * 2017/09/10 - v1.7.0 - ability to run scripts before / after tests 211 | * 2017/09/09 - v1.6.0 - also run tests from subfolders of test 212 | * 2017/07/11 - v1.4.1 - Add option --root for running tests on e.g. webpack build results residing in other directories, 213 | add option --httpEvent to create http events when creating functions 214 | * 2017/07/09 - v1.4.0 - Add --live switch, 215 | add --grep switch, 216 | verify that the test runtime matches the service runtime, 217 | upgrade lambda-wrapper (returns exceptions as errors) 218 | * 2016/12/21 - v1.3.2 - Fix population of environment variables 219 | * 2016/11/28 - v1.3.1 - Added support for environment variables in Serverless 1.2 220 | * 2016/11/09 - v1.2.0 - Added ability to add function / test templates 221 | * 2016/11/09 - v1.1.0 - Added function create command. 222 | * 2016/09/23 - v1.0.2 - Bugfixes, configurable test timeouts 223 | * 2016/08/15 - v1.0.0 - Preliminary version for Serverless 1.0 224 | 225 | ## License 226 | 227 | Copyright (c) 2017 [Nordcloud](https://nordcloud.com/), licensed for users and contributors under MIT license. 228 | https://github.com/nordcloud/serverless-mocha-plugin/blob/master/LICENSE 229 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * serverless-mocha-plugin 5 | * - a plugin for TDD with Serverless Framework 6 | */ 7 | 8 | const path = require('path'); 9 | const lambdaWrapper = require('lambda-wrapper'); 10 | const Mocha = require('mocha'); 11 | const chai = require('chai'); 12 | const ejs = require('ejs'); 13 | const fse = require('fs-extra'); 14 | const fs = require('fs'); 15 | const BbPromise = require('bluebird'); 16 | const yamlEdit = require('yaml-edit'); 17 | const { execSync } = require('child_process'); 18 | const utils = require('./utils'); 19 | 20 | const testTemplateFile = path.join('templates', 'test-template.ejs'); 21 | const functionTemplateFile = path.join('templates', 'function-template.ejs'); 22 | 23 | const validFunctionRuntimes = [ 24 | 'aws-nodejs8.10', 25 | 'aws-nodejs10.x', 26 | 'aws-nodejs12.x', 27 | ]; 28 | 29 | const humanReadableFunctionRuntimes = `${validFunctionRuntimes 30 | .map(template => `"${template}"`).join(', ')}`; 31 | 32 | class mochaPlugin { 33 | constructor(serverless, options) { 34 | this.serverless = serverless; 35 | this.options = options; 36 | 37 | this.commands = { 38 | create: { 39 | commands: { 40 | test: { 41 | usage: 'Create mocha tests for service / function', 42 | lifecycleEvents: [ 43 | 'test', 44 | ], 45 | options: { 46 | function: { 47 | usage: 'Name of the function', 48 | shortcut: 'f', 49 | required: true, 50 | }, 51 | path: { 52 | usage: 'Path for the tests', 53 | shortcut: 'p', 54 | }, 55 | }, 56 | }, 57 | function: { 58 | usage: 'Create a function into the service', 59 | lifecycleEvents: [ 60 | 'function', 61 | 'test', 62 | ], 63 | options: { 64 | function: { 65 | usage: 'Name of the function', 66 | shortcut: 'f', 67 | required: true, 68 | }, 69 | handler: { 70 | usage: 'Handler for the function (e.g. --handler my-function/index.handler)', 71 | required: true, 72 | }, 73 | path: { 74 | usage: 'Path for the tests (e.g. --path tests)', 75 | shortcut: 'p', 76 | }, 77 | httpEvent: { 78 | usage: 'Add an http endpoint (e.g. --httpEvent "verb relative-path")', 79 | }, 80 | }, 81 | }, 82 | }, 83 | }, 84 | invoke: { 85 | usage: 'Invoke mocha tests for service / function', 86 | commands: { 87 | test: { 88 | usage: 'Invoke test(s)', 89 | lifecycleEvents: [ 90 | 'invoke', 91 | ], 92 | options: { 93 | function: { 94 | usage: 'Name of the function', 95 | shortcut: 'f', 96 | }, 97 | reporter: { 98 | usage: 'Mocha reporter to use', 99 | shortcut: 'R', 100 | }, 101 | 'reporter-options': { 102 | usage: 'Options for mocha reporter', 103 | shortcut: 'O', 104 | }, 105 | grep: { 106 | usage: 'Run only matching tests', 107 | shortcut: 'G', 108 | }, 109 | live: { 110 | usage: 'Run the Lambda function in AWS', 111 | shortcut: 'l', 112 | }, 113 | root: { 114 | usage: 'Service root for running tests', 115 | }, 116 | path: { 117 | usage: 'Path for the tests for running tests in other than default "test" folder', 118 | }, 119 | compilers: { 120 | usage: 'Compiler to use on Mocha', 121 | }, 122 | timeout: { 123 | usage: 'Timeout to wait for Mocha', 124 | shortcut: 't', 125 | }, 126 | exit: { 127 | usage: 'force shutdown of the event loop after test run', 128 | }, 129 | }, 130 | }, 131 | }, 132 | }, 133 | }; 134 | 135 | this.hooks = { 136 | 'create:test:test': this.createTest.bind(this), 137 | 'invoke:test:invoke': this.runTests.bind(this), 138 | 'create:function:function': this.createFunction.bind(this), 139 | 'create:function:test': this.createTest.bind(this), 140 | // 'create:function:create' 141 | }; 142 | } 143 | 144 | // Run pre/postTest scriprs 145 | runScripts(testStage) { 146 | const myModule = this; 147 | return new Promise((succeed) => { 148 | const cmds = myModule.config[testStage] || []; 149 | cmds.forEach((cmd) => { 150 | this.serverless.cli.log(`Run command: ${cmd}`); 151 | const cmdOut = execSync(cmd); 152 | if (process.env.SLS_DEBUG) { 153 | const output = cmdOut.toString(); 154 | this.serverless.cli.log(output); 155 | } 156 | }); 157 | succeed(); 158 | }); 159 | } 160 | 161 | runTests() { 162 | return new Promise((resolve) => { 163 | const myModule = this; 164 | const funcOption = this.options.f || this.options.function || []; 165 | const testsPath = this.options.p || this.options.path || utils.getTestsFolder(); 166 | const testFileMap = {}; 167 | const mocha = new Mocha({ 168 | timeout: this.options.t || this.options.timeout || 6000, 169 | }); 170 | 171 | const { stage } = this.options; 172 | const { region } = this.options; 173 | 174 | let funcNames = []; 175 | if (typeof funcOption === 'string') { 176 | funcNames = [funcOption]; 177 | } else if (funcOption.length > 0) { 178 | funcNames = funcOption; 179 | } 180 | 181 | const inited = this.serverless.service; 182 | myModule.config = (inited.custom || {})['serverless-mocha-plugin'] || {}; 183 | // Verify that the service runtime matches with the current runtime 184 | let { runtime } = inited.provider; 185 | // Fix the real version for node10 186 | if (runtime) { 187 | runtime = runtime.replace('.x', ''); 188 | } 189 | 190 | let nodeVersion; 191 | if (typeof process.versions === 'object') { 192 | nodeVersion = process.versions.node; 193 | } else { 194 | nodeVersion = process.versions; 195 | } 196 | nodeVersion = nodeVersion.replace(/\.[^.]*$/, ''); 197 | 198 | const versionValidator = (providerRuntime, currentNodeVersion) => { 199 | if (providerRuntime === 'nodejs10.x') { 200 | return currentNodeVersion.match(/^v?(\d+)\.\d+/)[1] !== '10'; 201 | } 202 | return `nodejs${currentNodeVersion}` !== providerRuntime; 203 | }; 204 | 205 | if (versionValidator(inited.provider.runtime, nodeVersion)) { 206 | let errorMsg = `Tests being run with nodejs${nodeVersion}, `; 207 | errorMsg = `${errorMsg} service is using ${runtime}.`; 208 | errorMsg = `${errorMsg} Tests may not be reliable.`; 209 | 210 | this.serverless.cli.log(errorMsg); 211 | } 212 | 213 | myModule.serverless.environment = inited.environment; 214 | 215 | myModule.runScripts('preTestCommands') 216 | .then(() => { 217 | const svcFuncs = myModule.getFunctions(funcNames); 218 | const funcs = utils.getTestFiles(svcFuncs, testsPath, funcNames); 219 | 220 | // Run the tests that were actually found 221 | funcNames = Object.keys(funcs); 222 | if (funcNames.length === 0) { 223 | return myModule.serverless.cli.log('No tests to run'); 224 | } 225 | 226 | funcNames.forEach((func) => { 227 | if (funcs[func].mochaPlugin) { 228 | if (funcs[func].handler) { 229 | // Map only functions 230 | testFileMap[func] = funcs[func]; 231 | utils.setEnv(this.serverless, func); 232 | } else { 233 | utils.setEnv(this.serverless); 234 | } 235 | 236 | const { testPath } = funcs[func].mochaPlugin; 237 | 238 | if (fs.existsSync(testPath)) { 239 | mocha.addFile(testPath); 240 | } 241 | } 242 | 243 | const { reporter } = myModule.options; 244 | 245 | if (reporter !== undefined) { 246 | const reporterOptions = {}; 247 | if (myModule.options['reporter-options'] !== undefined) { 248 | myModule.options['reporter-options'].split(',').forEach((opt) => { 249 | const L = opt.split('='); 250 | if (L.length > 2 || L.length === 0) { 251 | throw new Error(`invalid reporter option "${opt}"`); 252 | } else if (L.length === 2) { 253 | const [name, value] = L; 254 | reporterOptions[name] = value; 255 | } else { 256 | reporterOptions[L[0]] = true; 257 | } 258 | }); 259 | } 260 | mocha.reporter(reporter, reporterOptions); 261 | } 262 | 263 | if (myModule.options.grep) { 264 | mocha.grep(myModule.options.grep); 265 | } 266 | 267 | // set the SERVERLESS_TEST_ROOT variable to define root for tests 268 | let rootFolder = this.serverless.config.servicePath; 269 | 270 | if (myModule.options.root) { 271 | rootFolder = myModule.options.root; 272 | myModule.serverless.cli.log(`Run tests against code under '${rootFolder}'`); 273 | } 274 | 275 | // Use full paths to ensure that the code is correctly required in tests 276 | if (!path.isAbsolute(rootFolder)) { 277 | const currDir = process.cwd(); 278 | rootFolder = path.join(currDir, rootFolder); 279 | } 280 | 281 | /* eslint-disable dot-notation */ 282 | process.env['SERVERLESS_TEST_ROOT'] = rootFolder; 283 | 284 | if (myModule.options.live) { 285 | process.env['SERVERLESS_MOCHA_PLUGIN_LIVE'] = true; 286 | process.env['SERVERLESS_MOCHA_PLUGIN_REGION'] = region || inited.provider.region; 287 | process.env['SERVERLESS_MOCHA_PLUGIN_SERVICE'] = inited.service; 288 | process.env['SERVERLESS_MOCHA_PLUGIN_STAGE'] = stage || inited.provider.stage; 289 | } else { 290 | // Set the `IS_LOCAL` env variable to match the `sls invoke local` environment. 291 | process.env['IS_LOCAL'] = true; 292 | } 293 | /* eslint-enable dot-notation */ 294 | 295 | const { compilers } = myModule.options; 296 | if (typeof compilers !== 'undefined') { 297 | myModule.options.compilers.split(',').filter(e => e !== '').forEach((c) => { 298 | // Splitting only to preserve backwards 299 | // compatibility. 300 | const split = c.split(/:(.+)/); 301 | const ext = split[0]; 302 | let mod = split[1] || ext; 303 | 304 | if (mod[0] === '.') { 305 | mod = path.join(process.cwd(), mod); 306 | } 307 | 308 | const babelModules = ['babel-register', '@babel/register']; 309 | const babelConf = ((this.serverless.service.custom || {})['serverless-mocha-plugin'] || {}).babelOptions; // eslint-disable-line max-len 310 | if (babelModules.includes(mod) && babelConf) { 311 | /* eslint-disable import/no-dynamic-require */ 312 | require(mod)(babelConf); // eslint-disable-line global-require 313 | /* eslint-enable import/no-dynamic-require */ 314 | } else { 315 | /* eslint-disable import/no-dynamic-require */ 316 | require(mod); // eslint-disable-line global-require 317 | /* eslint-enable import/no-dynamic-require */ 318 | } 319 | }); 320 | } 321 | return null; 322 | }, error => myModule.serverless.cli.log(error)); 323 | let runnerFailures = 0; 324 | mocha.run((failures) => { 325 | process.on('exit', () => { 326 | myModule.runScripts('postTestCommands') 327 | // exit with non-zero status if there were failures 328 | .then(() => process.exit(failures)); 329 | }); 330 | if (myModule.options.exit) { 331 | process.exit(failures); 332 | } 333 | }).on('test', (suite) => { 334 | const testFuncName = utils.funcNameFromPath(suite.file); 335 | // set env only for functions 336 | if (testFileMap[testFuncName]) { 337 | utils.setEnv(myModule.serverless, testFuncName); 338 | } else { 339 | utils.setEnv(myModule.serverless); 340 | } 341 | }).on('fail', () => { 342 | runnerFailures += 1; 343 | }).on('end', () => { 344 | resolve(); 345 | if (myModule.options.exit) { 346 | process.exit(runnerFailures > 0 ? 1 : 0); 347 | } 348 | }); 349 | return null; 350 | }); 351 | }); 352 | } 353 | 354 | createTest() { 355 | const funcName = this.options.f || this.options.function; 356 | const testsRootFolder = this.options.p || this.options.path || 'test'; 357 | const myModule = this; 358 | 359 | const testsFolder = utils.createTestFolder(testsRootFolder); 360 | 361 | const testFilePath = utils.getTestFilePath(funcName, testsFolder); 362 | if (fs.existsSync(testFilePath)) { 363 | myModule.serverless.cli.log(`Test file ${testFilePath} already exists`); 364 | return (new Error(`File ${testFilePath} already exists`)); 365 | } 366 | const func = myModule.serverless.service.functions[funcName]; 367 | const handlerParts = func.handler.split('.'); 368 | const funcPath = (`${handlerParts[0]}.js`).replace(/\\/g, '/'); 369 | const handler = handlerParts[handlerParts.length - 1]; 370 | 371 | let templateFilenamePath = ''; 372 | 373 | if (this.serverless.service.custom 374 | && this.serverless.service.custom['serverless-mocha-plugin'] 375 | && this.serverless.service.custom['serverless-mocha-plugin'].testTemplate) { 376 | templateFilenamePath = path.join(this.serverless.config.servicePath, 377 | this.serverless.service.custom['serverless-mocha-plugin'].testTemplate); 378 | } 379 | if ((!templateFilenamePath) || (!fs.existsSync(templateFilenamePath))) { 380 | templateFilenamePath = path.join(__dirname, testTemplateFile); 381 | } 382 | 383 | const templateString = utils.getTemplateFromFile(templateFilenamePath); 384 | 385 | const content = ejs.render(templateString, { 386 | functionName: funcName, 387 | functionPath: funcPath, 388 | handlerName: handler, 389 | }); 390 | 391 | const err = fs.writeFileSync(testFilePath, content); 392 | if (err) { 393 | myModule.serverless.cli.log(`Creating file ${testFilePath} failed: ${err}`); 394 | return new Error(`Creating file ${testFilePath} failed: ${err}`); 395 | } 396 | return myModule.serverless.cli.log(`serverless-mocha-plugin: created ${testFilePath}`); 397 | } 398 | 399 | // Helper functions 400 | 401 | getFunctions(funcList) { 402 | const myModule = this; 403 | const funcObjs = {}; 404 | const allFuncs = myModule.serverless.service.functions; 405 | 406 | if (funcList.length === 0) { 407 | return allFuncs; 408 | } 409 | 410 | let func; 411 | funcList.forEach((funcName) => { 412 | func = allFuncs[funcName]; 413 | if (func) { 414 | funcObjs[funcName] = func; 415 | } else { 416 | myModule.serverless.cli.log(`Warning: Could not find function '${funcName}'.`); 417 | } 418 | }); 419 | return (funcObjs); 420 | } 421 | 422 | createAWSNodeJSFuncFile(handlerPath) { 423 | const handlerInfo = path.parse(handlerPath); 424 | const handlerDir = path.join(this.serverless.config.servicePath, handlerInfo.dir); 425 | const handlerFile = `${handlerInfo.name}.js`; 426 | const handlerFunction = handlerInfo.ext.replace(/^\./, ''); 427 | let templateFile = path.join(__dirname, functionTemplateFile); 428 | 429 | if (this.serverless.service.custom 430 | && this.serverless.service.custom['serverless-mocha-plugin'] 431 | && this.serverless.service.custom['serverless-mocha-plugin'].functionTemplate) { 432 | templateFile = path.join(this.serverless.config.servicePath, 433 | this.serverless.service.custom['serverless-mocha-plugin'].functionTemplate); 434 | } 435 | 436 | const templateText = fse.readFileSync(templateFile).toString(); 437 | const jsFile = ejs.render(templateText, { 438 | handlerFunction, 439 | }); 440 | 441 | const filePath = path.join(handlerDir, handlerFile); 442 | 443 | this.serverless.utils.writeFileDir(filePath); 444 | if (this.serverless.utils.fileExistsSync(filePath)) { 445 | const errorMessage = [ 446 | `File "${filePath}" already exists. Cannot create function.`, 447 | ].join(''); 448 | throw new this.serverless.classes.Error(errorMessage); 449 | } 450 | if (fs.writeFileSync(path.join(handlerDir, handlerFile), jsFile)) { 451 | this.serverless.cli.log(`Creating file ${handlerFile} failed`); 452 | return new Error(`Creating file ${handlerFile} failed`); 453 | } 454 | this.serverless.cli.log(`Created function file "${path.join(handlerDir, handlerFile)}"`); 455 | return BbPromise.resolve(); 456 | } 457 | 458 | createFunctionTest() { 459 | const plugin = this; 460 | return plugin.createFunction() 461 | .then(plugin.createTest); 462 | } 463 | 464 | createFunction() { 465 | this.serverless.cli.log('Generating function...'); 466 | const functionName = this.options.function; 467 | const { handler } = this.options; 468 | 469 | const serverlessYmlFilePath = path 470 | .join(this.serverless.config.servicePath, 'serverless.yml'); 471 | 472 | const serverlessYmlFileContent = fse 473 | .readFileSync(serverlessYmlFilePath).toString(); 474 | 475 | return this.serverless.yamlParser.parse(serverlessYmlFilePath) 476 | .then((config) => { 477 | const runtime = [config.provider.name, config.provider.runtime].join('-'); 478 | 479 | if (validFunctionRuntimes.indexOf(runtime) < 0) { 480 | const errorMessage = [ 481 | `Provider / Runtime "${runtime}" is not supported.`, 482 | ` Supported runtimes are: ${humanReadableFunctionRuntimes}.`, 483 | ].join(''); 484 | throw new this.serverless.classes.Error(errorMessage); 485 | } 486 | 487 | const ymlEditor = yamlEdit(serverlessYmlFileContent); 488 | 489 | if (ymlEditor.hasKey(`functions.${functionName}`)) { 490 | const errorMessage = [ 491 | `Function "${functionName}" already exists. Cannot create function.`, 492 | ].join(''); 493 | throw new this.serverless.classes.Error(errorMessage); 494 | } 495 | 496 | const funcDoc = {}; 497 | const funcData = { handler }; 498 | if (this.options.httpEvent) { 499 | let events = []; 500 | if (typeof this.options.httpEvent === 'string') { 501 | events = [ 502 | this.options.httpEvent, 503 | ]; 504 | } else { 505 | events = this.options.httpEvent; 506 | } 507 | funcData.events = []; 508 | 509 | events.forEach((val) => { 510 | this.serverless.cli.log(`Add http event '${val}'`); 511 | 512 | funcData.events.push({ 513 | http: val, 514 | }); 515 | }); 516 | } 517 | this.serverless.service.functions[functionName] = funcData; 518 | funcDoc[functionName] = funcData; 519 | 520 | if (ymlEditor.insertChild('functions', funcDoc)) { 521 | const errorMessage = [ 522 | `Could not find functions in ${serverlessYmlFilePath}`, 523 | ].join(''); 524 | throw new this.serverless.classes.Error(errorMessage); 525 | } 526 | 527 | fse.writeFileSync(serverlessYmlFilePath, ymlEditor.dump()); 528 | if (validFunctionRuntimes.includes(runtime)) { 529 | return this.createAWSNodeJSFuncFile(handler); 530 | } 531 | 532 | throw new this.serverless.classes.Error(`Unknown runtime ${runtime}`); 533 | }); 534 | } 535 | } 536 | 537 | module.exports = mochaPlugin; 538 | module.exports.lambdaWrapper = lambdaWrapper; 539 | module.exports.chai = chai; 540 | module.exports.initLiveModule = (modName) => { 541 | const functionName = [ 542 | process.env.SERVERLESS_MOCHA_PLUGIN_SERVICE, 543 | process.env.SERVERLESS_MOCHA_PLUGIN_STAGE, 544 | modName, 545 | ].join('-'); 546 | 547 | return { 548 | region: process.env.SERVERLESS_MOCHA_PLUGIN_REGION, 549 | lambdaFunction: functionName, 550 | }; 551 | }; 552 | const { initLiveModule } = module.exports; 553 | 554 | module.exports.getWrapper = (modName, modPath, handler) => { 555 | let wrapped; 556 | // TODO: make this fetch the data from serverless.yml 557 | 558 | if (process.env.SERVERLESS_MOCHA_PLUGIN_LIVE) { 559 | const mod = initLiveModule(modName); 560 | wrapped = lambdaWrapper.wrap(mod); 561 | } else { 562 | /* eslint-disable import/no-dynamic-require */ 563 | /* eslint-disable global-require */ 564 | const mod = require(process.env.SERVERLESS_TEST_ROOT + modPath); 565 | /* eslint-enable global-require */ 566 | /* eslint-enable import/no-dynamic-require */ 567 | wrapped = lambdaWrapper.wrap(mod, { 568 | handler, 569 | }); 570 | } 571 | return wrapped; 572 | }; 573 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-mocha-plugin", 3 | "version": "1.12.0", 4 | "engines": { 5 | "node": ">= 8.10.0", 6 | "npm": ">= 5.6.0" 7 | }, 8 | "description": "Serverless plugin for test driven development using mocha", 9 | "author": "Mikael Puittinen (https://nordcloud.com)", 10 | "contributors": [ 11 | "Anssi Herranen", 12 | "Rafał Janicki", 13 | "Eetu Tuomala" 14 | ], 15 | "license": "MIT", 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/nordcloud/serverless-mocha-plugin" 19 | }, 20 | "keywords": [ 21 | "serverless framework plugin", 22 | "serverless applications", 23 | "serverless plugins", 24 | "api gateway", 25 | "lambda", 26 | "aws", 27 | "aws lambda", 28 | "mocha", 29 | "amazon", 30 | "amazon web services", 31 | "serverless.com" 32 | ], 33 | "main": "index.js", 34 | "bin": {}, 35 | "scripts": { 36 | "test": "nyc mocha -t 30000", 37 | "lint": "eslint ." 38 | }, 39 | "devDependencies": { 40 | "babel-register": "6.26.0", 41 | "copy-webpack-plugin": "^5.0.3", 42 | "eslint": "^5.16.0", 43 | "eslint-config-airbnb": "^17.1.1", 44 | "eslint-config-airbnb-base": "^13.2.0", 45 | "eslint-plugin-import": "^2.18.0", 46 | "eslint-plugin-jsx-a11y": "^6.2.3", 47 | "eslint-plugin-react": "^7.14.2", 48 | "nyc": "^14.1.1", 49 | "serverless": "^1.47.0", 50 | "serverless-webpack": "^5.3.1", 51 | "webpack": "^4.35.3", 52 | "webpack-node-externals": "^1.7.2" 53 | }, 54 | "dependencies": { 55 | "aws-sdk": "^2.491.0", 56 | "bluebird": "^3.5.5", 57 | "chai": "^4.2.0", 58 | "delayed-stream": "^1.0.0", 59 | "ejs": "^2.6.2", 60 | "fs-extra": "^8.1.0", 61 | "lambda-wrapper": "^0.3.0", 62 | "mocha": "^6.1.4", 63 | "yaml-edit": "^0.1.3" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /templates/function-template.ejs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports.<%= handlerFunction %> = async (event, context) => { 4 | const response = { 5 | statusCode: 200, 6 | body: JSON.stringify({ 7 | message: 'Go Serverless v1.0! Your function executed successfully!', 8 | input: event, 9 | }), 10 | }; 11 | 12 | return response; 13 | // Use this code if you don't use the http event with the LAMBDA-PROXY integration 14 | // return { message: 'Go Serverless v1.0! Your function executed successfully!', event }; 15 | }; 16 | -------------------------------------------------------------------------------- /templates/test-template.ejs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // tests for <%= functionName %> 4 | // Generated by serverless-mocha-plugin 5 | 6 | const mochaPlugin = require('serverless-mocha-plugin'); 7 | const expect = mochaPlugin.chai.expect; 8 | let wrapped = mochaPlugin.getWrapper('<%= functionName %>', '/<%= functionPath %>', '<%= handlerName %>'); 9 | 10 | describe('<%= functionName %>', () => { 11 | before((done) => { 12 | done(); 13 | }); 14 | 15 | it('implement tests here', async () => { 16 | const response = await wrapped.run({}); 17 | expect(response).to.not.be.empty; 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /test/integration-options10.x.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Serverless = require('serverless'); 4 | const { execSync } = require('child_process'); 5 | const path = require('path'); 6 | const fse = require('fs-extra'); 7 | const { expect } = require('chai'); 8 | const testUtils = require('./testUtils'); 9 | 10 | const serverless = new Serverless(); 11 | serverless.init(); 12 | const serverlessExec = path.join(serverless.config.serverlessPath, '..', 'bin', 'serverless'); 13 | 14 | describe('integration with options in stage prod', () => { 15 | before(() => { 16 | // create temporary directory and copy test service there 17 | process.env.MOCHA_PLUGIN_TEST_DIR = path.join(__dirname); 18 | const tmpDir = testUtils.getTmpDirPath(); 19 | fse.mkdirsSync(tmpDir); 20 | fse.copySync(path.join(process.env.MOCHA_PLUGIN_TEST_DIR, 'test-service-options'), tmpDir); 21 | process.chdir(tmpDir); 22 | execSync(`ln -s ${path.join(process.env.MOCHA_PLUGIN_TEST_DIR, '/../node_modules')} ${tmpDir}/`); 23 | }); 24 | 25 | it('should contain test params in cli info', () => { 26 | const test = execSync(`${serverlessExec} -h`); 27 | const result = test.toString(); 28 | expect(result).to.have.string( 29 | 'create test ................... Create mocha tests for service / function', 30 | ); 31 | expect(result).to.have.string( 32 | 'create function ............... Create a function into the service', 33 | ); 34 | expect(result).to.have.string( 35 | 'invoke test ................... Invoke test(s)', 36 | ); 37 | }); 38 | 39 | it('should create test for hello function', () => { 40 | const test = execSync(`${serverlessExec} create test --function hello --stage prod`); 41 | const result = test.toString(); 42 | expect(result).to.have.string( 43 | 'serverless-mocha-plugin: created test/hello.js', 44 | ); 45 | }); 46 | 47 | it('should create function goodbye with 2 http endpoints', () => { 48 | const test = execSync( 49 | `${serverlessExec}` 50 | + ' create function --function goodbye --handler goodbye/index.handler ' 51 | + '--httpEvent "post event" --httpEvent "get event" --stage prod', 52 | ); 53 | const result = test.toString(); 54 | expect(result).to.have.string( 55 | 'Add http event \'post event\'', 56 | ); 57 | expect(result).to.have.string( 58 | 'Add http event \'get event\'', 59 | ); 60 | expect(result).to.have.string( 61 | 'serverless-mocha-plugin: created test/goodbye.js', 62 | ); 63 | }); 64 | 65 | it('should run tests successfully in stage prod', () => { 66 | // change test files to use local proxy version of mocha plugin 67 | testUtils.replaceTextInFile( 68 | path.join('test', 'hello.js'), 69 | 'require(\'serverless-mocha-plugin\')', 70 | 'require(\'../.serverless_plugins/serverless-mocha-plugin/index.js\')', 71 | ); 72 | testUtils.replaceTextInFile( 73 | path.join('test', 'goodbye.js'), 74 | 'require(\'serverless-mocha-plugin\')', 75 | 'require(\'../.serverless_plugins/serverless-mocha-plugin/index.js\')', 76 | ); 77 | const test = execSync(`${serverlessExec} invoke test --stage prod`); 78 | const result = test.toString(); 79 | expect(result).to.have.string( 80 | 'goodbye\n ✓ implement tests here', 81 | ); 82 | 83 | expect(result).to.have.string( 84 | 'hello\n ✓ implement tests here', 85 | ); 86 | 87 | expect(result).to.have.string( 88 | '2 passing', 89 | ); 90 | }); 91 | 92 | it('should run tests successfully against built package', () => { 93 | // change test files to use local proxy version of mocha plugin 94 | // These have been done earlier 95 | 96 | const test = execSync(`${serverlessExec} invoke test --stage prod --root testBuild`); 97 | const result = test.toString(); 98 | 99 | expect(result).to.have.string( 100 | 'Run tests against code under \'testBuild\'', 101 | ); 102 | 103 | expect(result).to.have.string( 104 | 'goodbye\n ✓ implement tests here', 105 | ); 106 | 107 | expect(result).to.have.string( 108 | 'hello\n ✓ implement tests here', 109 | ); 110 | 111 | expect(result).to.have.string( 112 | '2 passing', 113 | ); 114 | }); 115 | 116 | it('should limit tests to run with --grep option', () => { 117 | const test = execSync(`${serverlessExec} invoke test --grep goodbye --stage prod`); 118 | const result = test.toString(); 119 | expect(result).to.have.string( 120 | 'goodbye\n ✓ implement tests here', 121 | ); 122 | 123 | expect(result).to.have.string( 124 | '1 passing', 125 | ); 126 | }); 127 | }); 128 | -------------------------------------------------------------------------------- /test/integration10.x-babel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Serverless = require('serverless'); 4 | const { execSync } = require('child_process'); 5 | const path = require('path'); 6 | const fse = require('fs-extra'); 7 | const { expect } = require('chai'); 8 | const testUtils = require('./testUtils'); 9 | 10 | const serverless = new Serverless(); 11 | serverless.init(); 12 | const serverlessExec = path.join(serverless.config.serverlessPath, '..', 'bin', 'serverless'); 13 | 14 | describe('integration (node v10.x template with babel)', () => { 15 | before(function () { 16 | // increase timeout because of the npm install, with node 4 and npm 2 it's taking some time 17 | this.timeout(120000); 18 | // create temporary directory and copy test service there 19 | process.env.MOCHA_PLUGIN_TEST_DIR = path.join(__dirname); 20 | const tmpDir = testUtils.getTmpDirPath(); 21 | fse.mkdirsSync(tmpDir); 22 | fse.copySync( 23 | path.join(process.env.MOCHA_PLUGIN_TEST_DIR, 'test-service-node10.x-babel'), 24 | tmpDir, 25 | ); 26 | process.chdir(tmpDir); 27 | execSync('npm install -s'); 28 | }); 29 | 30 | it('should contain test params in cli info', () => { 31 | const test = execSync(`${serverlessExec}`); 32 | const result = test.toString(); 33 | expect(result).to.have.string( 34 | 'create test ................... Create mocha tests for service / function', 35 | ); 36 | expect(result).to.have.string( 37 | 'create function ............... Create a function into the service', 38 | ); 39 | expect(result).to.have.string( 40 | 'invoke test ................... Invoke test(s)', 41 | ); 42 | }); 43 | 44 | it('should create test for hello function', () => { 45 | const test = execSync(`${serverlessExec} create test --function hello`); 46 | const result = test.toString(); 47 | expect(result).to.have.string( 48 | 'serverless-mocha-plugin: created test/hello.js', 49 | ); 50 | }); 51 | 52 | it('should create function goodbye', () => { 53 | const test = execSync( 54 | `${serverlessExec}` 55 | + ' create function --function goodbye --handler goodbye/index.handler', 56 | ); 57 | const result = test.toString(); 58 | expect(result).to.have.string( 59 | 'serverless-mocha-plugin: created test/goodbye.js', 60 | ); 61 | }); 62 | 63 | it('should run tests successfully', () => { 64 | // change test files to use local proxy version of mocha plugin 65 | testUtils.replaceTextInFile( 66 | path.join('test', 'hello.js'), 67 | 'require(\'serverless-mocha-plugin\')', 68 | 'require(\'../.serverless_plugins/serverless-mocha-plugin/index.js\')', 69 | ); 70 | testUtils.replaceTextInFile( 71 | path.join('test', 'goodbye.js'), 72 | 'require(\'serverless-mocha-plugin\')', 73 | 'require(\'../.serverless_plugins/serverless-mocha-plugin/index.js\')', 74 | ); 75 | const test = execSync(`${serverlessExec} invoke test --compilers js:babel-register`); 76 | const result = test.toString(); 77 | expect(result).to.have.string( 78 | 'goodbye\n ✓ implement tests here', 79 | ); 80 | 81 | expect(result).to.have.string( 82 | 'hello\n ✓ implement tests here', 83 | ); 84 | 85 | expect(result).to.have.string( 86 | '2 passing', 87 | ); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /test/integration10.x.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Serverless = require('serverless'); 4 | const { execSync } = require('child_process'); 5 | const path = require('path'); 6 | const fse = require('fs-extra'); 7 | const { expect } = require('chai'); 8 | const testUtils = require('./testUtils'); 9 | 10 | const serverless = new Serverless(); 11 | serverless.init(); 12 | const serverlessExec = path.join(serverless.config.serverlessPath, '..', 'bin', 'serverless'); 13 | 14 | describe('integration (node v10.x template)', () => { 15 | before(() => { 16 | // create temporary directory and copy test service there 17 | process.env.MOCHA_PLUGIN_TEST_DIR = path.join(__dirname); 18 | const tmpDir = testUtils.getTmpDirPath(); 19 | fse.mkdirsSync(tmpDir); 20 | fse.copySync(path.join(process.env.MOCHA_PLUGIN_TEST_DIR, 'test-service-node10.x'), tmpDir); 21 | process.chdir(tmpDir); 22 | }); 23 | 24 | it('should contain test params in cli info', () => { 25 | const test = execSync(`${serverlessExec}`); 26 | const result = test.toString(); 27 | expect(result).to.have.string( 28 | 'create test ................... Create mocha tests for service / function', 29 | ); 30 | expect(result).to.have.string( 31 | 'create function ............... Create a function into the service', 32 | ); 33 | expect(result).to.have.string( 34 | 'invoke test ................... Invoke test(s)', 35 | ); 36 | }); 37 | 38 | it('should create test for hello function', () => { 39 | const test = execSync(`${serverlessExec} create test --function hello`); 40 | const result = test.toString(); 41 | expect(result).to.have.string( 42 | 'serverless-mocha-plugin: created test/hello.js', 43 | ); 44 | }); 45 | 46 | it('should create function goodbye', () => { 47 | const test = execSync(`${serverlessExec} create function --function goodbye --handler goodbye/index.handler`); 48 | const result = test.toString(); 49 | expect(result).to.have.string( 50 | 'serverless-mocha-plugin: created test/goodbye.js', 51 | ); 52 | }); 53 | 54 | it('should run tests successfully', () => { 55 | // change test files to use local proxy version of mocha plugin 56 | testUtils.replaceTextInFile( 57 | path.join(process.cwd(), 'test', 'hello.js'), 58 | 'require(\'serverless-mocha-plugin\')', 59 | 'require(\'../.serverless_plugins/serverless-mocha-plugin/index.js\')', 60 | ); 61 | testUtils.replaceTextInFile( 62 | path.join(process.cwd(), 'test', 'goodbye.js'), 63 | 'require(\'serverless-mocha-plugin\')', 64 | 'require(\'../.serverless_plugins/serverless-mocha-plugin/index.js\')', 65 | ); 66 | 67 | const test = execSync(`${serverlessExec} invoke test`); 68 | const result = test.toString(); 69 | 70 | expect(result).to.have.string( 71 | 'goodbye\n ✓ implement tests here', 72 | ); 73 | 74 | expect(result).to.have.string( 75 | 'hello\n ✓ implement tests here', 76 | ); 77 | 78 | expect(result).to.have.string( 79 | '2 passing', 80 | ); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /test/integration12.x.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Serverless = require('serverless'); 4 | const { execSync } = require('child_process'); 5 | const path = require('path'); 6 | const fse = require('fs-extra'); 7 | const { expect } = require('chai'); 8 | const testUtils = require('./testUtils'); 9 | 10 | const serverless = new Serverless(); 11 | serverless.init(); 12 | const serverlessExec = path.join(serverless.config.serverlessPath, '..', 'bin', 'serverless'); 13 | 14 | describe('integration (node v12.x template)', () => { 15 | before(() => { 16 | // create temporary directory and copy test service there 17 | process.env.MOCHA_PLUGIN_TEST_DIR = path.join(__dirname); 18 | const tmpDir = testUtils.getTmpDirPath(); 19 | fse.mkdirsSync(tmpDir); 20 | fse.copySync(path.join(process.env.MOCHA_PLUGIN_TEST_DIR, 'test-service-node12.x'), tmpDir); 21 | process.chdir(tmpDir); 22 | }); 23 | 24 | it('should contain test params in cli info', () => { 25 | const test = execSync(`${serverlessExec}`); 26 | const result = test.toString(); 27 | expect(result).to.have.string( 28 | 'create test ................... Create mocha tests for service / function', 29 | ); 30 | expect(result).to.have.string( 31 | 'create function ............... Create a function into the service', 32 | ); 33 | expect(result).to.have.string( 34 | 'invoke test ................... Invoke test(s)', 35 | ); 36 | }); 37 | 38 | it('should create test for hello function', () => { 39 | const test = execSync(`${serverlessExec} create test --function hello`); 40 | const result = test.toString(); 41 | expect(result).to.have.string( 42 | 'serverless-mocha-plugin: created test/hello.js', 43 | ); 44 | }); 45 | 46 | it('should create function goodbye', () => { 47 | const test = execSync(`${serverlessExec} create function --function goodbye --handler goodbye/index.handler`); 48 | const result = test.toString(); 49 | expect(result).to.have.string( 50 | 'serverless-mocha-plugin: created test/goodbye.js', 51 | ); 52 | }); 53 | 54 | it('should run tests successfully', () => { 55 | // change test files to use local proxy version of mocha plugin 56 | testUtils.replaceTextInFile( 57 | path.join(process.cwd(), 'test', 'hello.js'), 58 | 'require(\'serverless-mocha-plugin\')', 59 | 'require(\'../.serverless_plugins/serverless-mocha-plugin/index.js\')', 60 | ); 61 | testUtils.replaceTextInFile( 62 | path.join(process.cwd(), 'test', 'goodbye.js'), 63 | 'require(\'serverless-mocha-plugin\')', 64 | 'require(\'../.serverless_plugins/serverless-mocha-plugin/index.js\')', 65 | ); 66 | 67 | const test = execSync(`${serverlessExec} invoke test`); 68 | const result = test.toString(); 69 | 70 | expect(result).to.have.string( 71 | 'goodbye\n ✓ implement tests here', 72 | ); 73 | 74 | expect(result).to.have.string( 75 | 'hello\n ✓ implement tests here', 76 | ); 77 | 78 | expect(result).to.have.string( 79 | '2 passing', 80 | ); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /test/integration8.10.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Serverless = require('serverless'); 4 | const { execSync } = require('child_process'); 5 | const path = require('path'); 6 | const fse = require('fs-extra'); 7 | const { expect } = require('chai'); 8 | const testUtils = require('./testUtils'); 9 | 10 | const serverless = new Serverless(); 11 | serverless.init(); 12 | const serverlessExec = path.join(serverless.config.serverlessPath, '..', 'bin', 'serverless'); 13 | 14 | describe('integration (node v8.10 template)', () => { 15 | before(() => { 16 | // create temporary directory and copy test service there 17 | process.env.MOCHA_PLUGIN_TEST_DIR = path.join(__dirname); 18 | const tmpDir = testUtils.getTmpDirPath(); 19 | fse.mkdirsSync(tmpDir); 20 | fse.copySync(path.join(process.env.MOCHA_PLUGIN_TEST_DIR, 'test-service-node8.10'), tmpDir); 21 | process.chdir(tmpDir); 22 | }); 23 | 24 | it('should contain test params in cli info', () => { 25 | const test = execSync(`${serverlessExec}`); 26 | const result = test.toString(); 27 | expect(result).to.have.string( 28 | 'create test ................... Create mocha tests for service / function', 29 | ); 30 | expect(result).to.have.string( 31 | 'create function ............... Create a function into the service', 32 | ); 33 | expect(result).to.have.string( 34 | 'invoke test ................... Invoke test(s)', 35 | ); 36 | }); 37 | 38 | it('should create test for hello function', () => { 39 | const test = execSync(`${serverlessExec} create test --function hello`); 40 | const result = test.toString(); 41 | expect(result).to.have.string( 42 | 'serverless-mocha-plugin: created test/hello.js', 43 | ); 44 | }); 45 | 46 | it('should create function goodbye', () => { 47 | const test = execSync( 48 | `${serverlessExec}` 49 | + ' create function --function goodbye --handler goodbye/index.handler', 50 | ); 51 | const result = test.toString(); 52 | expect(result).to.have.string( 53 | 'serverless-mocha-plugin: created test/goodbye.js', 54 | ); 55 | }); 56 | 57 | it('should run tests successfully', () => { 58 | // change test files to use local proxy version of mocha plugin 59 | testUtils.replaceTextInFile( 60 | path.join('test', 'hello.js'), 61 | 'require(\'serverless-mocha-plugin\')', 62 | 'require(\'../.serverless_plugins/serverless-mocha-plugin/index.js\')', 63 | ); 64 | testUtils.replaceTextInFile( 65 | path.join('test', 'goodbye.js'), 66 | 'require(\'serverless-mocha-plugin\')', 67 | 'require(\'../.serverless_plugins/serverless-mocha-plugin/index.js\')', 68 | ); 69 | 70 | const test = execSync(`${serverlessExec} invoke test`); 71 | const result = test.toString(); 72 | 73 | expect(result).to.have.string( 74 | 'goodbye\n ✓ implement tests here', 75 | ); 76 | 77 | expect(result).to.have.string( 78 | 'hello\n ✓ implement tests here', 79 | ); 80 | 81 | expect(result).to.have.string( 82 | '2 passing', 83 | ); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /test/mochaPlugin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { expect } = require('chai'); 4 | const path = require('path'); 5 | const fse = require('fs-extra'); 6 | const MochaPlugin = require('../index'); 7 | 8 | describe('mochaPlugin', () => { 9 | before(() => { 10 | const tmp = path.join(__dirname, '../', 'tmp'); 11 | fse.mkdirsSync(tmp); 12 | process.chdir(tmp); 13 | }); 14 | 15 | it('checks that commands exists', () => { 16 | const mochaPlugin = new MochaPlugin({}, {}); 17 | const commands = Object.keys(mochaPlugin.commands); 18 | expect(commands).to.eql(['create', 'invoke']); 19 | }); 20 | 21 | it('checks hooks exists', () => { 22 | const mochaPlugin = new MochaPlugin({}, {}); 23 | const hooks = Object.keys(mochaPlugin.hooks); 24 | expect(hooks).to.eql([ 25 | 'create:test:test', 26 | 'invoke:test:invoke', 27 | 'create:function:function', 28 | 'create:function:test', 29 | ]); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/test-service-node10.x-babel/.npmignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /test/test-service-node10.x-babel/.serverless_plugins/serverless-mocha-plugin/index.js: -------------------------------------------------------------------------------- 1 | // Proxy 2 | const path = require('path'); 3 | const mochaDir = path.join(process.env.MOCHA_PLUGIN_TEST_DIR, '../', 'index.js'); 4 | module.exports = require(mochaDir); -------------------------------------------------------------------------------- /test/test-service-node10.x-babel/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports.hello = (event, context, callback) => { 4 | const response = { 5 | statusCode: 200, 6 | body: JSON.stringify({ 7 | message: 'Go Serverless v1.0! Your function executed successfully!', 8 | input: event, 9 | }), 10 | }; 11 | 12 | callback(null, response); 13 | 14 | // Use this code if you don't use the http event with the LAMBDA-PROXY integration 15 | // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event }); 16 | }; 17 | -------------------------------------------------------------------------------- /test/test-service-node10.x-babel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-service-node10.x-babel", 3 | "version": "0.0.1", 4 | "description": "test-service-node10.x-babel", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/nordcloud/serverless-mocha-plugin" 8 | }, 9 | "scripts": { 10 | "preinstall": "npm config set package-lock false", 11 | "postinstall": "npm config set package-lock true" 12 | }, 13 | "license": "MIT", 14 | "devDependencies": { 15 | "babel-preset-env": "^1.7.0" 16 | }, 17 | "babel": { 18 | "presets": [ 19 | ["env", { 20 | "targets": { 21 | "node": "6.10" 22 | } 23 | }] 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/test-service-node10.x-babel/serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: mocha-test-suite 15 | 16 | # You can pin your service to only deploy with a specific Serverless version 17 | # Check out our docs for more details 18 | # frameworkVersion: "=X.X.X" 19 | 20 | provider: 21 | name: aws 22 | runtime: nodejs10.x 23 | 24 | # you can overwrite defaults here 25 | # stage: dev 26 | # region: us-east-1 27 | 28 | # you can add statements to the Lambda function's IAM Role here 29 | # iamRoleStatements: 30 | # - Effect: "Allow" 31 | # Action: 32 | # - "s3:ListBucket" 33 | # Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] } 34 | # - Effect: "Allow" 35 | # Action: 36 | # - "s3:PutObject" 37 | # Resource: 38 | # Fn::Join: 39 | # - "" 40 | # - - "arn:aws:s3:::" 41 | # - "Ref" : "ServerlessDeploymentBucket" 42 | 43 | # you can define service wide environment variables here 44 | # environment: 45 | # variable1: value1 46 | 47 | # you can add packaging information here 48 | #package: 49 | # include: 50 | # - include-me.js 51 | # - include-me-dir/** 52 | # exclude: 53 | # - exclude-me.js 54 | # - exclude-me-dir/** 55 | 56 | functions: 57 | hello: 58 | handler: handler.hello 59 | 60 | # The following are a few example events you can configure 61 | # NOTE: Please make sure to change your handler code to work with those events 62 | # Check the event documentation for details 63 | # events: 64 | # - http: 65 | # path: users/create 66 | # method: get 67 | # - s3: ${env:BUCKET} 68 | # - schedule: rate(10 minutes) 69 | # - sns: greeter-topic 70 | # - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000 71 | 72 | # Define function environment variables here 73 | # environment: 74 | # variable2: value2 75 | 76 | # you can add CloudFormation resource templates here 77 | #resources: 78 | # Resources: 79 | # NewResource: 80 | # Type: AWS::S3::Bucket 81 | # Properties: 82 | # BucketName: my-new-bucket 83 | # Outputs: 84 | # NewOutput: 85 | # Description: "Description for the output" 86 | # Value: "Some output value" 87 | 88 | plugins: 89 | - serverless-mocha-plugin 90 | 91 | custom: 92 | serverless-mocha-plugin: 93 | testTemplate: templates/test-template.js 94 | functionTemplate: templates/function-template.ejs 95 | -------------------------------------------------------------------------------- /test/test-service-node10.x-babel/templates/function-template.ejs: -------------------------------------------------------------------------------- 1 | export function <%= handlerFunction %>(event, context, callback) { 2 | const response = { 3 | statusCode: 200, 4 | body: JSON.stringify({ 5 | message: 'Go Serverless v1.0! Your function executed successfully!', 6 | input: event, 7 | }), 8 | }; 9 | 10 | callback(null, response); 11 | 12 | // Use this code if you don't use the http event with the LAMBDA-PROXY integration 13 | // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event }); 14 | } -------------------------------------------------------------------------------- /test/test-service-node10.x-babel/templates/test-template.ejs: -------------------------------------------------------------------------------- 1 | // tests for <%= functionName %> 2 | // Generated by serverless-mocha-plugin 3 | 4 | import mod from '../<%= functionPath %>'; 5 | 6 | import { lambdaWrapper, chai } from 'serverless-mocha-plugin'; 7 | 8 | const { expect } = chai; 9 | const wrapped = lambdaWrapper.wrap(mod, { handler: '<%= handlerName %>' }); 10 | 11 | describe('<%= functionName %>', () => { 12 | before((done) => { 13 | // lambdaWrapper.init(liveFunction); // Run the deployed lambda 14 | 15 | done(); 16 | }); 17 | 18 | it('implement tests here', () => { 19 | return wrapped.run({}).then((response) => { 20 | expect(response).to.not.be.empty; 21 | }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/test-service-node10.x/.npmignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /test/test-service-node10.x/.serverless_plugins/serverless-mocha-plugin/index.js: -------------------------------------------------------------------------------- 1 | // Proxy 2 | const path = require('path'); 3 | const mochaDir = path.join(process.env.MOCHA_PLUGIN_TEST_DIR, '../', 'index.js'); 4 | module.exports = require(mochaDir); -------------------------------------------------------------------------------- /test/test-service-node10.x/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports.hello = (event, context, callback) => { 4 | const response = { 5 | statusCode: 200, 6 | body: JSON.stringify({ 7 | message: 'Go Serverless v1.0! Your function executed successfully!', 8 | input: event, 9 | }), 10 | }; 11 | 12 | callback(null, response); 13 | 14 | // Use this code if you don't use the http event with the LAMBDA-PROXY integration 15 | // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event }); 16 | }; 17 | -------------------------------------------------------------------------------- /test/test-service-node10.x/serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: mocha-test-suite 15 | 16 | # You can pin your service to only deploy with a specific Serverless version 17 | # Check out our docs for more details 18 | # frameworkVersion: "=X.X.X" 19 | 20 | provider: 21 | name: aws 22 | runtime: nodejs10.x 23 | 24 | # you can overwrite defaults here 25 | # stage: dev 26 | # region: us-east-1 27 | 28 | # you can add statements to the Lambda function's IAM Role here 29 | # iamRoleStatements: 30 | # - Effect: "Allow" 31 | # Action: 32 | # - "s3:ListBucket" 33 | # Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] } 34 | # - Effect: "Allow" 35 | # Action: 36 | # - "s3:PutObject" 37 | # Resource: 38 | # Fn::Join: 39 | # - "" 40 | # - - "arn:aws:s3:::" 41 | # - "Ref" : "ServerlessDeploymentBucket" 42 | 43 | # you can define service wide environment variables here 44 | # environment: 45 | # variable1: value1 46 | 47 | # you can add packaging information here 48 | #package: 49 | # include: 50 | # - include-me.js 51 | # - include-me-dir/** 52 | # exclude: 53 | # - exclude-me.js 54 | # - exclude-me-dir/** 55 | 56 | functions: 57 | hello: 58 | handler: handler.hello 59 | 60 | # The following are a few example events you can configure 61 | # NOTE: Please make sure to change your handler code to work with those events 62 | # Check the event documentation for details 63 | # events: 64 | # - http: 65 | # path: users/create 66 | # method: get 67 | # - s3: ${env:BUCKET} 68 | # - schedule: rate(10 minutes) 69 | # - sns: greeter-topic 70 | # - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000 71 | 72 | # Define function environment variables here 73 | # environment: 74 | # variable2: value2 75 | 76 | # you can add CloudFormation resource templates here 77 | #resources: 78 | # Resources: 79 | # NewResource: 80 | # Type: AWS::S3::Bucket 81 | # Properties: 82 | # BucketName: my-new-bucket 83 | # Outputs: 84 | # NewOutput: 85 | # Description: "Description for the output" 86 | # Value: "Some output value" 87 | 88 | plugins: 89 | - serverless-mocha-plugin 90 | -------------------------------------------------------------------------------- /test/test-service-node12.x/.npmignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /test/test-service-node12.x/.serverless_plugins/serverless-mocha-plugin/index.js: -------------------------------------------------------------------------------- 1 | // Proxy 2 | const path = require('path'); 3 | const mochaDir = path.join(process.env.MOCHA_PLUGIN_TEST_DIR, '../', 'index.js'); 4 | module.exports = require(mochaDir); -------------------------------------------------------------------------------- /test/test-service-node12.x/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports.hello = async (event) => { 4 | const response = { 5 | statusCode: 200, 6 | body: JSON.stringify({ 7 | message: 'Go Serverless v1.0! Your function executed successfully!', 8 | input: event, 9 | }), 10 | }; 11 | 12 | return response; 13 | 14 | // Use this code if you don't use the http event with the LAMBDA-PROXY integration 15 | // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event }); 16 | }; 17 | -------------------------------------------------------------------------------- /test/test-service-node12.x/serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: mocha-test-suite 15 | 16 | # You can pin your service to only deploy with a specific Serverless version 17 | # Check out our docs for more details 18 | # frameworkVersion: "=X.X.X" 19 | 20 | provider: 21 | name: aws 22 | runtime: nodejs12.x 23 | 24 | # you can overwrite defaults here 25 | # stage: dev 26 | # region: us-east-1 27 | 28 | # you can add statements to the Lambda function's IAM Role here 29 | # iamRoleStatements: 30 | # - Effect: "Allow" 31 | # Action: 32 | # - "s3:ListBucket" 33 | # Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] } 34 | # - Effect: "Allow" 35 | # Action: 36 | # - "s3:PutObject" 37 | # Resource: 38 | # Fn::Join: 39 | # - "" 40 | # - - "arn:aws:s3:::" 41 | # - "Ref" : "ServerlessDeploymentBucket" 42 | 43 | # you can define service wide environment variables here 44 | # environment: 45 | # variable1: value1 46 | 47 | # you can add packaging information here 48 | #package: 49 | # include: 50 | # - include-me.js 51 | # - include-me-dir/** 52 | # exclude: 53 | # - exclude-me.js 54 | # - exclude-me-dir/** 55 | 56 | functions: 57 | hello: 58 | handler: handler.hello 59 | 60 | # The following are a few example events you can configure 61 | # NOTE: Please make sure to change your handler code to work with those events 62 | # Check the event documentation for details 63 | # events: 64 | # - http: 65 | # path: users/create 66 | # method: get 67 | # - s3: ${env:BUCKET} 68 | # - schedule: rate(10 minutes) 69 | # - sns: greeter-topic 70 | # - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000 71 | 72 | # Define function environment variables here 73 | # environment: 74 | # variable2: value2 75 | 76 | # you can add CloudFormation resource templates here 77 | #resources: 78 | # Resources: 79 | # NewResource: 80 | # Type: AWS::S3::Bucket 81 | # Properties: 82 | # BucketName: my-new-bucket 83 | # Outputs: 84 | # NewOutput: 85 | # Description: "Description for the output" 86 | # Value: "Some output value" 87 | 88 | plugins: 89 | - serverless-mocha-plugin 90 | -------------------------------------------------------------------------------- /test/test-service-node8.10/.npmignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /test/test-service-node8.10/.serverless_plugins/serverless-mocha-plugin/index.js: -------------------------------------------------------------------------------- 1 | // Proxy 2 | const path = require('path'); 3 | const mochaDir = path.join(process.env.MOCHA_PLUGIN_TEST_DIR, '../', 'index.js'); 4 | module.exports = require(mochaDir); -------------------------------------------------------------------------------- /test/test-service-node8.10/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports.hello = (event, context, callback) => { 4 | const response = { 5 | statusCode: 200, 6 | body: JSON.stringify({ 7 | message: 'Go Serverless v1.0! Your function executed successfully!', 8 | input: event, 9 | }), 10 | }; 11 | 12 | callback(null, response); 13 | 14 | // Use this code if you don't use the http event with the LAMBDA-PROXY integration 15 | // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event }); 16 | }; 17 | -------------------------------------------------------------------------------- /test/test-service-node8.10/serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: mocha-test-suite 15 | 16 | # You can pin your service to only deploy with a specific Serverless version 17 | # Check out our docs for more details 18 | # frameworkVersion: "=X.X.X" 19 | 20 | provider: 21 | name: aws 22 | runtime: nodejs8.10 23 | 24 | # you can overwrite defaults here 25 | # stage: dev 26 | # region: us-east-1 27 | 28 | # you can add statements to the Lambda function's IAM Role here 29 | # iamRoleStatements: 30 | # - Effect: "Allow" 31 | # Action: 32 | # - "s3:ListBucket" 33 | # Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] } 34 | # - Effect: "Allow" 35 | # Action: 36 | # - "s3:PutObject" 37 | # Resource: 38 | # Fn::Join: 39 | # - "" 40 | # - - "arn:aws:s3:::" 41 | # - "Ref" : "ServerlessDeploymentBucket" 42 | 43 | # you can define service wide environment variables here 44 | # environment: 45 | # variable1: value1 46 | 47 | # you can add packaging information here 48 | #package: 49 | # include: 50 | # - include-me.js 51 | # - include-me-dir/** 52 | # exclude: 53 | # - exclude-me.js 54 | # - exclude-me-dir/** 55 | 56 | functions: 57 | hello: 58 | handler: handler.hello 59 | 60 | # The following are a few example events you can configure 61 | # NOTE: Please make sure to change your handler code to work with those events 62 | # Check the event documentation for details 63 | # events: 64 | # - http: 65 | # path: users/create 66 | # method: get 67 | # - s3: ${env:BUCKET} 68 | # - schedule: rate(10 minutes) 69 | # - sns: greeter-topic 70 | # - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000 71 | 72 | # Define function environment variables here 73 | # environment: 74 | # variable2: value2 75 | 76 | # you can add CloudFormation resource templates here 77 | #resources: 78 | # Resources: 79 | # NewResource: 80 | # Type: AWS::S3::Bucket 81 | # Properties: 82 | # BucketName: my-new-bucket 83 | # Outputs: 84 | # NewOutput: 85 | # Description: "Description for the output" 86 | # Value: "Some output value" 87 | 88 | plugins: 89 | - serverless-mocha-plugin 90 | -------------------------------------------------------------------------------- /test/test-service-options/.env: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nordcloud/serverless-mocha-plugin/7aace4054ea2007f9d0d321b119bfa446eb7f500/test/test-service-options/.env -------------------------------------------------------------------------------- /test/test-service-options/.npmignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /test/test-service-options/.serverless_plugins/serverless-mocha-plugin/index.js: -------------------------------------------------------------------------------- 1 | // Proxy 2 | const path = require('path'); 3 | const mochaDir = path.join(process.env.MOCHA_PLUGIN_TEST_DIR, '../', 'index.js'); 4 | module.exports = require(mochaDir); -------------------------------------------------------------------------------- /test/test-service-options/handler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (process.env.STAGE !== 'prod-stage-test') { 4 | throw new Error('Environmental variable STAGE is not defined'); 5 | } 6 | 7 | module.exports.hello = (event, context, callback) => { 8 | const response = { 9 | statusCode: 200, 10 | body: JSON.stringify({ 11 | message: 'Go Serverless v1.0! Your function executed successfully!', 12 | input: event, 13 | }), 14 | }; 15 | 16 | if (process.env.STAGE !== 'prod-stage-test') { 17 | return callback('Environmental variable STAGE is incorrect'); 18 | } 19 | 20 | return callback(null, response); 21 | 22 | // Use this code if you don't use the http event with the LAMBDA-PROXY integration 23 | // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event }); 24 | }; 25 | -------------------------------------------------------------------------------- /test/test-service-options/serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: mocha-test-suite 15 | 16 | # You can pin your service to only deploy with a specific Serverless version 17 | # Check out our docs for more details 18 | # frameworkVersion: "=X.X.X" 19 | 20 | provider: 21 | name: aws 22 | runtime: nodejs10.x 23 | environment: 24 | STAGE: ${opt:stage}-stage-test 25 | 26 | # you can overwrite defaults here 27 | # stage: dev 28 | # region: us-east-1 29 | 30 | # you can add statements to the Lambda function's IAM Role here 31 | # iamRoleStatements: 32 | # - Effect: "Allow" 33 | # Action: 34 | # - "s3:ListBucket" 35 | # Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] } 36 | # - Effect: "Allow" 37 | # Action: 38 | # - "s3:PutObject" 39 | # Resource: 40 | # Fn::Join: 41 | # - "" 42 | # - - "arn:aws:s3:::" 43 | # - "Ref" : "ServerlessDeploymentBucket" 44 | 45 | # you can define service wide environment variables here 46 | # environment: 47 | # variable1: value1 48 | 49 | # you can add packaging information here 50 | #package: 51 | # include: 52 | # - include-me.js 53 | # - include-me-dir/** 54 | # exclude: 55 | # - exclude-me.js 56 | # - exclude-me-dir/** 57 | 58 | functions: 59 | hello: 60 | handler: handler.hello 61 | 62 | # The following are a few example events you can configure 63 | # NOTE: Please make sure to change your handler code to work with those events 64 | # Check the event documentation for details 65 | # events: 66 | # - http: 67 | # path: users/create 68 | # method: get 69 | # - s3: ${env:BUCKET} 70 | # - schedule: rate(10 minutes) 71 | # - sns: greeter-topic 72 | # - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000 73 | 74 | # Define function environment variables here 75 | # environment: 76 | # variable2: value2 77 | 78 | # you can add CloudFormation resource templates here 79 | #resources: 80 | # Resources: 81 | # NewResource: 82 | # Type: AWS::S3::Bucket 83 | # Properties: 84 | # BucketName: my-new-bucket 85 | # Outputs: 86 | # NewOutput: 87 | # Description: "Description for the output" 88 | # Value: "Some output value" 89 | 90 | plugins: 91 | - serverless-mocha-plugin 92 | -------------------------------------------------------------------------------- /test/test-service-options/testBuild/goodbye/index.js: -------------------------------------------------------------------------------- 1 | (function (e, a) { for (const i in a) e[i] = a[i]; }(exports, /** *** */ (function (modules) { // webpackBootstrap 2 | /** *** */ // The module cache 3 | /** *** */ const installedModules = {}; 4 | 5 | /** *** */ // The require function 6 | /** *** */ function __webpack_require__(moduleId) { 7 | /** *** */ // Check if module is in cache 8 | /** *** */ if (installedModules[moduleId]) 9 | /** *** */ { return installedModules[moduleId].exports; } 10 | 11 | /** *** */ // Create a new module (and put it into the cache) 12 | /** *** */ const module = installedModules[moduleId] = { 13 | /** *** */ exports: {}, 14 | /** *** */ id: moduleId, 15 | /** *** */ loaded: false, 16 | /** *** */ }; 17 | 18 | /** *** */ // Execute the module function 19 | /** *** */ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 20 | 21 | /** *** */ // Flag the module as loaded 22 | /** *** */ module.loaded = true; 23 | 24 | /** *** */ // Return the exports of the module 25 | /** *** */ return module.exports; 26 | /** *** */ } 27 | 28 | 29 | /** *** */ // expose the modules object (__webpack_modules__) 30 | /** *** */ __webpack_require__.m = modules; 31 | 32 | /** *** */ // expose the module cache 33 | /** *** */ __webpack_require__.c = installedModules; 34 | 35 | /** *** */ // __webpack_public_path__ 36 | /** *** */ __webpack_require__.p = ''; 37 | 38 | /** *** */ // Load entry module and return exports 39 | /** *** */ return __webpack_require__(0); 40 | /** *** */ }([ 41 | /* 0 */ 42 | /** */ (function (module, exports, __webpack_require__) { 43 | module.exports = __webpack_require__(1); 44 | /** */ }), 45 | /* 1 */ 46 | /** */ (function (module, exports) { 47 | 'use strict'; 48 | 49 | module.exports.handler = (event, context, callback) => { 50 | const response = { 51 | statusCode: 200, 52 | body: JSON.stringify({ 53 | message: 'Go Serverless v1.0! Your function executed successfully!', 54 | input: event, 55 | }), 56 | }; 57 | 58 | callback(null, response); 59 | 60 | // Use this code if you don't use the http event with the LAMBDA-PROXY integration 61 | // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event }); 62 | }; 63 | /** */ }), 64 | /** *** */ ])))); 65 | -------------------------------------------------------------------------------- /test/test-service-options/testBuild/handler.js: -------------------------------------------------------------------------------- 1 | (function (e, a) { for (const i in a) e[i] = a[i]; }(exports, /** *** */ (function (modules) { // webpackBootstrap 2 | /** *** */ // The module cache 3 | /** *** */ const installedModules = {}; 4 | 5 | /** *** */ // The require function 6 | /** *** */ function __webpack_require__(moduleId) { 7 | /** *** */ // Check if module is in cache 8 | /** *** */ if (installedModules[moduleId]) 9 | /** *** */ { return installedModules[moduleId].exports; } 10 | 11 | /** *** */ // Create a new module (and put it into the cache) 12 | /** *** */ const module = installedModules[moduleId] = { 13 | /** *** */ exports: {}, 14 | /** *** */ id: moduleId, 15 | /** *** */ loaded: false, 16 | /** *** */ }; 17 | 18 | /** *** */ // Execute the module function 19 | /** *** */ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 20 | 21 | /** *** */ // Flag the module as loaded 22 | /** *** */ module.loaded = true; 23 | 24 | /** *** */ // Return the exports of the module 25 | /** *** */ return module.exports; 26 | /** *** */ } 27 | 28 | 29 | /** *** */ // expose the modules object (__webpack_modules__) 30 | /** *** */ __webpack_require__.m = modules; 31 | 32 | /** *** */ // expose the module cache 33 | /** *** */ __webpack_require__.c = installedModules; 34 | 35 | /** *** */ // __webpack_public_path__ 36 | /** *** */ __webpack_require__.p = ''; 37 | 38 | /** *** */ // Load entry module and return exports 39 | /** *** */ return __webpack_require__(0); 40 | /** *** */ }([ 41 | /* 0 */ 42 | /** */ (function (module, exports, __webpack_require__) { 43 | module.exports = __webpack_require__(2); 44 | /** */ }), 45 | /* 1 */, 46 | /* 2 */ 47 | /** */ (function (module, exports) { 48 | 'use strict'; 49 | 50 | if (process.env.STAGE !== 'prod-stage-test') { 51 | throw new Error('Environmental variable STAGE is not defined'); 52 | } 53 | 54 | module.exports.hello = (event, context, callback) => { 55 | const response = { 56 | statusCode: 200, 57 | body: JSON.stringify({ 58 | message: 'Go Serverless v1.0! Your function executed successfully!', 59 | input: event, 60 | }), 61 | }; 62 | 63 | if (process.env.STAGE !== 'prod-stage-test') { 64 | return callback('Environmental variable STAGE is incorrect'); 65 | } 66 | 67 | return callback(null, response); 68 | 69 | // Use this code if you don't use the http event with the LAMBDA-PROXY integration 70 | // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event }); 71 | }; 72 | /** */ }), 73 | /** *** */ ])))); 74 | -------------------------------------------------------------------------------- /test/testUtils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fse = require('fs-extra'); 4 | const os = require('os'); 5 | const crypto = require('crypto'); 6 | const path = require('path'); 7 | 8 | const replaceTextInFile = (filePath, subString, newSubString) => { 9 | const fileContent = fse.readFileSync(filePath).toString(); 10 | fse.writeFileSync(filePath, fileContent.replace(subString, newSubString)); 11 | }; 12 | 13 | const getTmpDirPath = () => path.join(os.tmpdir(), 14 | 'tmpdirs-serverless-mocha-plugin', 15 | 'serverless-mocha-plugin', 16 | crypto.randomBytes(8).toString('hex')); 17 | 18 | module.exports = { 19 | replaceTextInFile, 20 | getTmpDirPath, 21 | }; 22 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { expect } = require('chai'); 4 | const path = require('path'); 5 | const fse = require('fs-extra'); 6 | const utils = require('../utils.js'); 7 | const testUtils = require('./testUtils'); 8 | 9 | describe('utils', () => { 10 | before(() => { 11 | process.env.MOCHA_PLUGIN_TEST_DIR = path.join(__dirname); 12 | const tmp = testUtils.getTmpDirPath(); 13 | fse.mkdirsSync(tmp); 14 | process.chdir(tmp); 15 | }); 16 | 17 | it('tests getTestFilePath for handler', () => { 18 | const testFilePath = utils.getTestFilePath('handler'); 19 | expect(testFilePath).to.be.equal('test/handler.js'); 20 | }); 21 | 22 | it('tests getTestFilePath for folder/handler', () => { 23 | const testFilePath = utils.getTestFilePath('folder/handler'); 24 | expect(testFilePath).to.be.equal('test/handler.js'); 25 | }); 26 | 27 | it('tests getTestFilePath for handler in custom folder', () => { 28 | const testFilePath = utils.getTestFilePath('handler', 'custom'); 29 | expect(testFilePath).to.be.equal('custom/handler.js'); 30 | }); 31 | 32 | it('tests getTestFilePath for folder/handler in custom folder', () => { 33 | const testFilePath = utils.getTestFilePath('folder/handler', 'custom'); 34 | expect(testFilePath).to.be.equal('custom/handler.js'); 35 | }); 36 | 37 | it('gets template from a file', () => { 38 | const templatePath = path.join( 39 | process.env.MOCHA_PLUGIN_TEST_DIR, 40 | '../', 41 | 'templates/test-template.ejs', 42 | ); 43 | const expectedTemplate = fse.readFileSync(templatePath, 'utf-8'); 44 | const template = utils.getTemplateFromFile(templatePath); 45 | expect(template).to.be.equal(expectedTemplate); 46 | }); 47 | 48 | it('tests default createTestFolder', () => { 49 | const folder = utils.createTestFolder(); 50 | expect(folder).to.be.equal('test'); 51 | }); 52 | 53 | it('tests custom createTestFolder', () => { 54 | const folder = utils.createTestFolder('custom'); 55 | expect(folder).to.be.equal('custom'); 56 | }); 57 | 58 | it('tests funcNameFromPath', () => { 59 | const functionName = utils.funcNameFromPath('path/to/functionName.js'); 60 | expect(functionName).to.be.equal('functionName'); 61 | }); 62 | 63 | it('tests setEnv with testFunction1 (env vars)', () => { 64 | const serverless = { 65 | service: { 66 | provider: { 67 | }, 68 | functions: { 69 | testFunction1: { 70 | }, 71 | }, 72 | }, 73 | }; 74 | utils.setEnv(serverless, 'testFunction1'); 75 | expect(process.env.TEST_VALUE_PROVIDER).to.be.equal(undefined); 76 | expect(process.env.TEST_VALUE_FUNCTION).to.be.equal(undefined); 77 | }); 78 | 79 | it('tests setEnv with testFunction1', () => { 80 | const serverless = { 81 | service: { 82 | provider: { 83 | environment: { 84 | TEST_VALUE_PROVIDER: 'test value provider', 85 | }, 86 | }, 87 | functions: { 88 | testFunction1: { 89 | environment: { 90 | TEST_VALUE_FUNCTION: 'test value function 1', 91 | }, 92 | }, 93 | }, 94 | }, 95 | }; 96 | utils.setEnv(serverless, 'testFunction1'); 97 | expect(process.env.TEST_VALUE_PROVIDER).to.be.equal('test value provider'); 98 | expect(process.env.TEST_VALUE_FUNCTION).to.be.equal('test value function 1'); 99 | }); 100 | 101 | it('tests setEnv with testFunction2', () => { 102 | const serverless = { 103 | service: { 104 | provider: { 105 | environment: { 106 | TEST_VALUE_PROVIDER: 'test value provider', 107 | }, 108 | }, 109 | functions: { 110 | testFunction2: { 111 | environment: { 112 | TEST_VALUE_FUNCTION: 'test value function 2', 113 | }, 114 | }, 115 | }, 116 | }, 117 | }; 118 | utils.setEnv(serverless, 'testFunction2'); 119 | expect(process.env.TEST_VALUE_PROVIDER).to.be.equal('test value provider'); 120 | expect(process.env.TEST_VALUE_FUNCTION).to.be.equal('test value function 2'); 121 | }); 122 | }); 123 | -------------------------------------------------------------------------------- /utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | 6 | const defaultTestsRootFolder = 'test'; // default test folder used for tests 7 | 8 | function getTestsFolder(testsRootFolder) { 9 | return testsRootFolder || defaultTestsRootFolder; 10 | } 11 | 12 | function getTestFilePath(funcName, testsRootFolder) { 13 | return path.join(getTestsFolder(testsRootFolder), `${funcName.replace(/.*\//g, '')}.js`); 14 | } 15 | 16 | function traverseTestFolder(testFolder, prefix) { 17 | const funcFiles = []; 18 | const dirContents = fs.readdirSync(testFolder); 19 | 20 | dirContents.forEach((val) => { 21 | const stats = fs.statSync(path.join(testFolder, val)); 22 | if (stats.isFile()) { 23 | funcFiles.push(prefix ? path.join(prefix, val) : val); 24 | } else { 25 | const subContents = traverseTestFolder( 26 | path.join(testFolder, val), prefix ? path.join(prefix, val) : val, 27 | ); 28 | subContents.forEach((subval) => { 29 | funcFiles.push(subval); 30 | }); 31 | } 32 | }); 33 | return funcFiles; 34 | } 35 | 36 | // getTestFiles. Returns all test files, attaches to functions 37 | function getTestFiles(funcs, testFolder, funcList) { 38 | const funcFiles = traverseTestFolder(testFolder); 39 | const resFuncs = {}; 40 | if (funcFiles.length > 0) { 41 | funcFiles.forEach((val) => { 42 | if (['.js', '.ts'].includes(path.extname(val))) { 43 | const base = path.basename(val).replace(/(\.test)?.[tj]s$/, ''); 44 | // Create test for non-functions only if no funcList 45 | if (funcs[base] || funcList.length === 0) { 46 | resFuncs[base] = funcs[base] || {}; 47 | 48 | resFuncs[base].mochaPlugin = { 49 | testPath: path.join(getTestsFolder(testFolder), val), 50 | }; 51 | } 52 | } 53 | }); 54 | } 55 | return resFuncs; 56 | } 57 | 58 | // Create the test folder 59 | function createTestFolder(testsRootFolder) { 60 | const testsFolder = getTestsFolder(testsRootFolder); 61 | const exists = fs.existsSync(testsFolder); 62 | if (exists) { 63 | return testsFolder; 64 | } 65 | fs.mkdirSync(testsFolder); 66 | return testsFolder; 67 | } 68 | 69 | function getTemplateFromFile(templateFilenamePath) { 70 | return fs.readFileSync(templateFilenamePath, 'utf-8'); 71 | } 72 | 73 | function funcNameFromPath(filePath) { 74 | const data = path.parse(filePath); 75 | 76 | return data.name; 77 | } 78 | 79 | function setEnv(serverless, funcName) { 80 | const serviceVars = serverless.service.provider.environment || {}; 81 | let functionVars = {}; 82 | if (funcName && serverless.service.functions[funcName]) { 83 | functionVars = serverless.service.functions[funcName].environment || {}; 84 | } 85 | return Object.assign( 86 | process.env, 87 | serviceVars, 88 | functionVars, 89 | ); 90 | } 91 | 92 | module.exports = { 93 | getTestsFolder, 94 | getTestFilePath, 95 | getTestFiles, 96 | createTestFolder, 97 | getTemplateFromFile, 98 | funcNameFromPath, 99 | setEnv, 100 | }; 101 | --------------------------------------------------------------------------------