auto-tdd 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.dockerignore +4 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
  3. package/.github/workflows/main.yml +72 -0
  4. package/.nvmrc +1 -0
  5. package/LICENSE +674 -0
  6. package/README.md +24 -0
  7. package/TODO +17 -0
  8. package/adapters/Adapter.js +5 -0
  9. package/adapters/AdapterThing.spec.js +10 -0
  10. package/cucumber.js +3 -0
  11. package/docker-compose.yml +21 -0
  12. package/domain/Thing.port.js +5 -0
  13. package/domain/calculator.js +9 -0
  14. package/domain/domain.spec.js +14 -0
  15. package/domain/javascript-user-interface.js +22 -0
  16. package/domain/test-cases/all.js +5 -0
  17. package/domain/test-cases/sum.js +26 -0
  18. package/domain/test-cases/test-user.js +22 -0
  19. package/features/simple_math.feature +37 -0
  20. package/features/support/steps.js +15 -0
  21. package/features/support/transform.js +16 -0
  22. package/features/support/world.js +22 -0
  23. package/http-api/Dockerfile +21 -0
  24. package/http-api/healthcheck.js +36 -0
  25. package/http-api/start.js +26 -0
  26. package/lambda-function/Dockerfile +16 -0
  27. package/lambda-function/app.js +8 -0
  28. package/package.json +58 -0
  29. package/publish-on-docker-hub.sh +13 -0
  30. package/renovate.json +4 -0
  31. package/stryker.conf.js +13 -0
  32. package/test-doubles/FakeThing.spec.js +3 -0
  33. package/test-http-api/container-test-cases.js +19 -0
  34. package/test-http-api/delay.js +3 -0
  35. package/test-http-api/docker-compose.component.spec.js +33 -0
  36. package/test-http-api/docker.component.spec.js +40 -0
  37. package/test-http-api/http-api-user-interface.js +12 -0
  38. package/test-http-api/runCommand.js +12 -0
  39. package/test-integration/TestingThingDoesStuff.spec.js +3 -0
  40. package/test-lambda-function/delay.js +3 -0
  41. package/test-lambda-function/docker.component.spec.js +55 -0
  42. package/test-lambda-function/runCommand.js +12 -0
  43. package/test-lambda-function/testing-lambda-function-user-interface.js +13 -0
package/README.md ADDED
@@ -0,0 +1,24 @@
1
+ [![Build Status](https://travis-ci.org/unsegnor/new-app.svg?branch=master)](https://travis-ci.org/unsegnor/new-app)
2
+
3
+ # new-app
4
+ New application schema with:
5
+ - Cucumber tests
6
+ - Integration tests
7
+ - Unit tests
8
+ - Mutation testing
9
+ - Ports and adapters templates
10
+ - Github actions for CI
11
+ - Component tests using docker containers
12
+
13
+ ## Getting started
14
+ 1. Rename the product name on package.json
15
+ 2. Set the repository, bugs and homepage urls
16
+ 3. Set the keywords, description and author
17
+ 4. Set the dockerHubUsername property if you want to automatically publish your docker images
18
+ 4. Set repository secrets in GitHub:
19
+ 4.1 One named NPM_TOKEN with an automation token to publish the package to NPM
20
+ 4.2 One named DOCKERHUB_TOKEN with a token from DockerHub to publish the images
21
+
22
+ ## Run all tests
23
+
24
+ npm test
package/TODO ADDED
@@ -0,0 +1,17 @@
1
+ Add property based testing
2
+ Make a UI to create tests (read and write on a local file)
3
+ Deploy docker container as a lambda function (follow this: https://docs.aws.amazon.com/lambda/latest/dg/images-create.html#images-upload)
4
+ Show the version of the application in a /version endpoint
5
+ Testing with external dependencies
6
+ Testing with internal state
7
+ Testing updates
8
+ deploying lambda function (with state)
9
+ updating a container image? we should take care of transferring the state or reusing or whatever, always through the api of that state?
10
+ Test deploying the application to kubernetes
11
+ Use node version from nvmrc file (I think it is not needed as renovate will update the FROM version in the Dockerfile)
12
+ Ensure we use the same commands to build the container for test and manually to debug
13
+ Create a github action to share among all the repos
14
+ Should we use docker-bench-security? seems like it is evaluating my host instead of the Dockerfile: https://github.com/docker/docker-bench-security
15
+ Measure coverage from component tests
16
+ Use docker containers also for dev environment
17
+ Add tests for published docker images, is it needed?
@@ -0,0 +1,5 @@
1
+ module.exports = function(){
2
+ return Object.freeze({
3
+
4
+ })
5
+ }
@@ -0,0 +1,10 @@
1
+ const Adapter = require('./Adapter')
2
+ const Port = require('../domain/Thing.port')
3
+
4
+ describe('Thing adapter', function(){
5
+ beforeEach(function(){
6
+ this.adapter = Adapter()
7
+ })
8
+
9
+ Port()
10
+ })
package/cucumber.js ADDED
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ default: `--format progress --publish-quiet`,
3
+ };
@@ -0,0 +1,21 @@
1
+ version: '3.8'
2
+
3
+ services:
4
+ http-api:
5
+ container_name: "${CONTAINER_NAME:-api}"
6
+ image: http-api
7
+ build:
8
+ context: .
9
+ dockerfile: ./http-api/Dockerfile
10
+ ports:
11
+ - "3000:3000"
12
+ # I had to duplicate the healthcheck here and inside the Dockerfile
13
+ # because without defininfg the healthcheck here, when running compose up it was taking more than 30 seconds to be healthy
14
+ # while when running docker run directly the container was ready in 2 seconds
15
+ # also when running compose up with this healthcheck defined it takes only 2 seconds
16
+ healthcheck:
17
+ test: ["CMD", "node", "./http-api/healthcheck.js"]
18
+ interval: 1s
19
+ timeout: 20s
20
+ retries: 5
21
+ start_period: 1s
@@ -0,0 +1,5 @@
1
+ module.exports = function(){
2
+ describe('Thing port', function(){
3
+ it('must check adapter stuff')
4
+ })
5
+ }
@@ -0,0 +1,9 @@
1
+ module.exports = function(){
2
+ return Object.freeze({
3
+ sum
4
+ })
5
+
6
+ function sum(){
7
+ return 3
8
+ }
9
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ This file is the entry point for the domain tests.
3
+ It mainly defines what is the user interface that we are going to use to test the domain.
4
+
5
+ In this case it is the javascript-user-interface.
6
+ It will run all the tests that we have defined.
7
+ **/
8
+
9
+ const test_all = require('./test-cases/all')
10
+ const domain_user_interface = require('./javascript-user-interface')()
11
+
12
+ describe('Domain tests', function(){
13
+ test_all(domain_user_interface)
14
+ })
@@ -0,0 +1,22 @@
1
+ /**
2
+ This is one of the multiple user interfaces that the application could have.
3
+ User interfaces translate user actions into operations over the system through the specific interface.
4
+
5
+ The user wants to sum two numbers and we translate that into the instantiation and usage of the calculator.
6
+ An http-api user interface would translate the same action into an http call.
7
+ **/
8
+
9
+ //TODO: Actually we could replace this one by a package-user-interface and require the index.js file instead of the calculator directly.
10
+ const Calculator = require("./calculator")
11
+
12
+ module.exports = function(){
13
+
14
+ const calculator = Calculator()
15
+ return Object.freeze({
16
+ sum
17
+ })
18
+
19
+ function sum(a, b){
20
+ return calculator.sum(a,b)
21
+ }
22
+ }
@@ -0,0 +1,5 @@
1
+ module.exports = function(user_interface){
2
+ describe('Domain tests', function(){
3
+ require('./sum.js')(user_interface)
4
+ })
5
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ In this file we describe the tests in terms of user actions and expectations.
3
+ We could also talk about situations in the the environment that can't be affected by the user like "today is Monday".
4
+ **/
5
+
6
+
7
+ const {expect} = require('chai');
8
+ const User = require('./test-user.js');
9
+
10
+ module.exports = function(user_interface){
11
+ describe('sum', function(){
12
+ let user
13
+
14
+ this.beforeEach(async function(){
15
+ user = User(user_interface)
16
+ })
17
+
18
+ it('basic sum', async () => {
19
+ let result = await user.sum(1,2)
20
+ expect(result).to.equal(3);
21
+ });
22
+
23
+
24
+ it('sum property based'); //https://github.com/dubzzz/fast-check/blob/main/packages/fast-check/documentation/Arbitraries.md#combinators
25
+ })
26
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ This is the user that performs the test.
3
+ It receives a user interface which is the one it will use for testing.
4
+ It doesn't know what interface it is using, that specificities will go in the user interface.
5
+ It is aware of:
6
+ the operations that are needed to be performed on the interface
7
+ the time it takes to get the results
8
+ the errors generated
9
+ all the information that is only known by the user that could be relevant for the testing, like (credentials, name, age ... )
10
+
11
+ We can add specific user expectations here regarding the error messages or the time it takes to get the results
12
+ **/
13
+
14
+ module.exports = function(user_interface){
15
+ return Object.freeze({
16
+ sum
17
+ })
18
+
19
+ async function sum(a, b){
20
+ return await user_interface.sum(a, b)
21
+ }
22
+ }
@@ -0,0 +1,37 @@
1
+ # features/simple_math.feature
2
+ Feature: Simple maths
3
+ In order to do maths
4
+ As a developer
5
+ I want to increment variables
6
+
7
+ Scenario: increment
8
+ Given a variable set to 1
9
+ When I increment the variable by 1
10
+ Then the variable should contain 2
11
+
12
+ Scenario Outline: much more complex increment stuff
13
+ Given a variable set to <var>
14
+ When I increment the variable by <increment>
15
+ Then the variable should contain <result>
16
+
17
+ Examples:
18
+ | var | increment | result |
19
+ | 100 | 5 | 105 |
20
+ | 99 | 1234 | 1333 |
21
+ | 12 | 5 | 17 |
22
+
23
+ Scenario: decrement
24
+ Given a variable set to 1
25
+ When I decrement the variable by 1
26
+ Then the variable should contain 0
27
+
28
+ Scenario Outline: much more complex decrement stuff
29
+ Given a variable set to <var>
30
+ When I decrement the variable by <decrement>
31
+ Then the variable should contain <result>
32
+
33
+ Examples:
34
+ | var | decrement | result |
35
+ | 100 | 5 | 95 |
36
+ | 99 | 1234 | -1135 |
37
+ | 12 | 5 | 7 |
@@ -0,0 +1,15 @@
1
+ // features/support/steps.js
2
+ const { Given, When, Then } = require('@cucumber/cucumber')
3
+ const { expect } = require('chai')
4
+
5
+ Given('a variable set to {int}', function (number) {
6
+ this.setTo(number)
7
+ })
8
+
9
+ When('I {operation} the variable by {int}', function (operation, number) {
10
+ operation.call(this, number)
11
+ })
12
+
13
+ Then('the variable should contain {int}', function (number) {
14
+ expect(this.variable).to.eql(number)
15
+ })
@@ -0,0 +1,16 @@
1
+ const {defineParameterType} = require('@cucumber/cucumber')
2
+
3
+ defineParameterType({
4
+ regexp: /increment|decrement/,
5
+ transformer: function (operationId) {
6
+ switch (operationId) {
7
+ case 'increment':
8
+ return this.incrementBy
9
+ case 'decrement':
10
+ return this.decrementBy
11
+ default:
12
+ throw new Error(`Operation ${operationId} not supported`)
13
+ }
14
+ },
15
+ name: 'operation'
16
+ })
@@ -0,0 +1,22 @@
1
+ // features/support/world.js
2
+ const { setWorldConstructor } = require('@cucumber/cucumber')
3
+
4
+ class CustomWorld {
5
+ constructor () {
6
+ this.variable = 0
7
+ }
8
+
9
+ setTo (number) {
10
+ this.variable = number
11
+ }
12
+
13
+ incrementBy (number) {
14
+ this.variable += number
15
+ }
16
+
17
+ decrementBy (number) {
18
+ this.variable -= number
19
+ }
20
+ }
21
+
22
+ setWorldConstructor(CustomWorld)
@@ -0,0 +1,21 @@
1
+ FROM node:20.8.0
2
+
3
+ # Update npm
4
+ RUN npm i -g npm@9.6.5
5
+
6
+ # Copy logic and http-api files
7
+ COPY ./http-api ./http-api
8
+ COPY ./domain ./domain
9
+ COPY ./package.json ./package.json
10
+ COPY ./package-lock.json ./package-lock.json
11
+
12
+ # Install dependencies
13
+ RUN npm i
14
+
15
+ # Change to a non root user
16
+ USER node
17
+
18
+ # Start api on run
19
+ CMD [ "node", "./http-api/start.js" ]
20
+
21
+ HEALTHCHECK --interval=1s --timeout=1s --retries=5 CMD [ "node", "healthcheck.js" ]
@@ -0,0 +1,36 @@
1
+ const http = require('http');
2
+
3
+ const options = {
4
+ hostname: 'localhost',
5
+ port: 3000,
6
+ path: '/health',
7
+ method: 'GET',
8
+ timeout: 500,
9
+ };
10
+
11
+ console.log("healthcheck")
12
+
13
+ const request = http.request(options, (res) => {
14
+ console.log('response')
15
+ if (res.statusCode === 200) {
16
+ console.log('OK')
17
+ process.exit(0);
18
+ } else {
19
+ console.log('not OK', res.statusCode)
20
+ process.exit(1);
21
+ }
22
+ });
23
+
24
+ request.on('error', () => {
25
+ console.log('error')
26
+ process.exit(1);
27
+ });
28
+
29
+ request.on('timeout', () => {
30
+ console.log('timeout')
31
+ request.destroy();
32
+ process.exit(1);
33
+ });
34
+
35
+ console.log("requesting...")
36
+ request.end();
@@ -0,0 +1,26 @@
1
+ const calculator = require('../domain/calculator')();
2
+
3
+ const express = require('express');
4
+ const PORT = process.env.PORT || 3000;
5
+
6
+ const app = express();
7
+ app.disable("x-powered-by"); //Disabled for security reasons. See: https://sonarcloud.io/organizations/unsegnor/rules?open=javascript%3AS5689&rule_key=javascript%3AS5689
8
+
9
+ app.get('/helloworld', (req, res) => {
10
+ res.send('Hello World!');
11
+ });
12
+
13
+ app.get('/sum', (req, res) => {
14
+ const a = parseInt(req.query.a);
15
+ const b = parseInt(req.query.b);
16
+ const result = calculator.sum(a, b);
17
+ res.status(200).send(result.toString());
18
+ });
19
+
20
+ app.get('/health', (req, res) => {
21
+ res.status(200).send('OK');
22
+ });
23
+
24
+ app.listen(PORT, () => {
25
+ console.log(`Server running on port ${PORT}`);
26
+ });
@@ -0,0 +1,16 @@
1
+ FROM public.ecr.aws/lambda/nodejs:18
2
+
3
+ # Update npm
4
+ RUN npm i -g npm@9.6.5
5
+
6
+ # Copy your function's source code and package.json into the container following indications from the AWS Lambda documentation
7
+ # https://docs.aws.amazon.com/lambda/latest/dg/images-create.html#images-create-1
8
+ #TODO: could we use a command to reference the files when testing and copying them when running in production?
9
+ COPY ./domain ${LAMBDA_TASK_ROOT}/domain
10
+ COPY ./lambda-function/app.js package.json ${LAMBDA_TASK_ROOT}/
11
+
12
+ # Install NPM dependencies
13
+ RUN npm install
14
+
15
+ # Set the Lambda function handler as the entry point
16
+ CMD [ "app.handler" ]
@@ -0,0 +1,8 @@
1
+ const AWS = require('aws-sdk');
2
+ const Calculator = require('./domain/calculator');
3
+
4
+ exports.handler = async (event) => {
5
+ const calculator = Calculator();
6
+ let result = await calculator.sum(event.a, event.b);
7
+ return result
8
+ };
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "auto-tdd",
3
+ "version": "0.1.3",
4
+ "description": "Automated development with TDD",
5
+ "main": "index.js",
6
+ "dockerHubUsername": "vcalatayud",
7
+ "devDependencies": {
8
+ "@cucumber/cucumber": "^10.0.0",
9
+ "@stryker-mutator/core": "6.4.2",
10
+ "@stryker-mutator/mocha-runner": "7.0.0",
11
+ "chai": "4.3.10",
12
+ "mocha": "10.2.0",
13
+ "uuid": "^9.0.0"
14
+ },
15
+ "scripts": {
16
+ "test": "npm run test-mocha && npm run test-cucumber && npm run test-api && npm run test-lambda",
17
+ "test-mocha": "npm run test-doubles && npm run test-domain && npm run test-adapters && npm run test-integration && npm run test-mutation",
18
+ "test-domain": "mocha domain --recursive",
19
+ "test-doubles": "mocha test-doubles --recursive",
20
+ "test-adapters": "mocha adapters --recursive",
21
+ "test-integration": "mocha test-integration --recursive",
22
+ "test-api": "npm run build-api-image && CONTAINER_NAME=api-auto-test-container && mocha test-http-api --recursive",
23
+ "test-lambda": "npm run build-lambda-image && CONTAINER_NAME=lambda-auto-test-container && mocha test-lambda-function --recursive",
24
+ "build-lambda-image": "docker build -t lambda-test-image -f ./lambda-function/Dockerfile .",
25
+ "test-mutation": "npx stryker run",
26
+ "test-cucumber": "cucumber-js",
27
+ "local-api": "node ./http-api/start.js",
28
+ "build-api-image": "docker build -t api-test-image -f ./http-api/Dockerfile .",
29
+ "api-container": "npm run build-api-image && docker run -d -p 3000:3000 --name api-test-container api-test-image",
30
+ "api-container-logs": "docker logs api-test-container",
31
+ "container-app": "CONTAINER_NAME=dev-api && docker-compose up -d --wait",
32
+ "remove-api-container": "docker rm -f api-test-container"
33
+ },
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/unsegnor/auto-tdd.git"
37
+ },
38
+ "keywords": [
39
+ "New",
40
+ "app",
41
+ "test",
42
+ "BDD",
43
+ "gherkins",
44
+ "cucumber",
45
+ "CI"
46
+ ],
47
+ "author": "Víctor Calatayud Asensio",
48
+ "license": "GPL-3.0-or-later",
49
+ "bugs": {
50
+ "url": "https://github.com/unsegnor/auto-tdd/issues"
51
+ },
52
+ "homepage": "https://github.com/unsegnor/auto-tdd#readme",
53
+ "dependencies": {
54
+ "aws-sdk": "^2.1363.0",
55
+ "axios": "^1.3.5",
56
+ "express": "^4.18.2"
57
+ }
58
+ }
@@ -0,0 +1,13 @@
1
+ #!/bin/bash
2
+
3
+ build_and_push_image() {
4
+ FOLDER=$1
5
+ VERSION=$(node -p "require('./package.json').version")
6
+ APP_NAME=$(node -p "require('./package.json').name")
7
+ DOCKERHUB_USERNAME=$(node -p "require('./package.json').dockerHubUsername")
8
+ IMAGE_NAME="$DOCKERHUB_USERNAME/$APP_NAME-$FOLDER:$VERSION"
9
+ docker build -t $IMAGE_NAME -f ./$FOLDER/Dockerfile .
10
+ docker push $IMAGE_NAME
11
+ }
12
+
13
+ build_and_push_image "$1"
package/renovate.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "automerge": true,
3
+ "nvm": true
4
+ }
@@ -0,0 +1,13 @@
1
+ module.exports = {
2
+ packageManager: "npm",
3
+ reporters: ["clear-text", "progress"],
4
+ testRunner: "mocha",
5
+ coverageAnalysis: "perTest",
6
+ mochaOptions:{
7
+ spec: ['domain/*.spec.js']
8
+ },
9
+ mutate: ['domain/*.js',
10
+ '!domain/*.spec.js',
11
+ '!domain/*.port.js',
12
+ '!domain/*.factory.js']
13
+ }
@@ -0,0 +1,3 @@
1
+ describe('Fake Thing', function(){
2
+ it('must behave as a thing')
3
+ })
@@ -0,0 +1,19 @@
1
+ const runCommand = require('./runCommand');
2
+ const delay = require('./delay');
3
+
4
+ module.exports = function({baseUrl}){
5
+ describe('container tests', function(){
6
+ it('should build and run the container', () => {});
7
+
8
+ it('should run containers in parallel')
9
+
10
+ xit('play with the container before removing it', async () => {
11
+ console.log("container deployed")
12
+ await delay(60000)
13
+ });
14
+
15
+ it('container is up and running', async () => {
16
+ await runCommand(`curl ${baseUrl}/health`, 'check api health')
17
+ });
18
+ })
19
+ }
@@ -0,0 +1,3 @@
1
+ module.exports = function delay(ms) {
2
+ return new Promise((resolve) => setTimeout(resolve, ms));
3
+ }
@@ -0,0 +1,33 @@
1
+ const uuid = require('uuid');
2
+ const runCommand = require('./runCommand');
3
+ const container_test_cases = require('./container-test-cases');
4
+ const domain_tests = require('../domain/test-cases/all.js');
5
+ const baseUrl = "http://localhost:3000"
6
+ const http_user_interface = require('./http-api-user-interface')({baseUrl})
7
+
8
+ describe('Docker compose container test', function () {
9
+ this.timeout(300000);
10
+
11
+ async function startApp(containerId){
12
+ await runCommand(`export CONTAINER_NAME=${containerId} && docker-compose up -d --build --wait`, `composed application ${containerId}`)
13
+ }
14
+
15
+ async function removeApp(containerId){
16
+ await runCommand(`export CONTAINER_NAME=${containerId} && docker-compose down`, `application removed ${containerId}`)
17
+ }
18
+
19
+ before(async () => { //beforeAll
20
+ this.containerId = uuid.v4()
21
+ await startApp(this.containerId)
22
+ });
23
+
24
+ after(async () => { //afterAll
25
+ await removeApp(this.containerId)
26
+ });
27
+
28
+ container_test_cases({baseUrl});
29
+
30
+ //TODO: pass a testscenario with preArrange, postArrange, preAct, postAct, preAssert, postAssert methods
31
+ //also user interface and later other options to mock dependencies
32
+ domain_tests(http_user_interface);
33
+ });
@@ -0,0 +1,40 @@
1
+ const uuid = require('uuid');
2
+ const container_test_cases = require('./container-test-cases');
3
+ const runCommand = require('./runCommand');
4
+ const delay = require('./delay');
5
+ const domain_tests = require('../domain/test-cases/all.js');
6
+ const baseUrl = "http://localhost:3000"
7
+ const http_user_interface = require('./http-api-user-interface')({baseUrl})
8
+
9
+ describe('Docker container test', function () {
10
+ this.timeout(300000);
11
+
12
+ async function buildImage(){
13
+ await runCommand('docker build -t auto-test-image -f ./http-api/Dockerfile .', 'built image auto-test-image')
14
+ }
15
+
16
+ async function runContainer(containerId){
17
+ await runCommand(`docker run -d -p 3000:3000 --name ${containerId} auto-test-image`, `created container ${containerId}`)
18
+ await delay(1000) //TODO add this wait to the create command
19
+ // await runCommand(`docker logs ${containerId}`, `logs for container ${containerId}: \n`) //TODO: show the logs and fail in case there are errors
20
+ }
21
+
22
+ async function removeContainer(containerId){
23
+ await runCommand(`docker rm -f ${containerId}`, `removed container ${containerId}`)
24
+ }
25
+
26
+ before(async () => { //beforeAll
27
+ this.containerId = uuid.v4()
28
+ await buildImage()
29
+ await runContainer(this.containerId)
30
+ });
31
+
32
+ after(async () => { //afterAll
33
+ await removeContainer(this.containerId)
34
+ });
35
+
36
+ container_test_cases({baseUrl});
37
+
38
+ //TODO: pass a testscenario with preArrange, postArrange, preAct, postAct, preAssert, postAssert methods
39
+ domain_tests(http_user_interface);
40
+ });
@@ -0,0 +1,12 @@
1
+ const axios = require('axios');
2
+
3
+ module.exports = function({baseUrl}){
4
+ return Object.freeze({
5
+ sum
6
+ })
7
+
8
+ async function sum(a, b){
9
+ const response = await axios.get(`${baseUrl}/sum?a=${a}&b=${b}`);
10
+ return response.data
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ const { exec } = require('child_process');
2
+
3
+ module.exports = async function runCommand(command, reason){
4
+ return new Promise((resolve, reject) => {
5
+ exec(command, (error, stdout) => {
6
+ if (error) return reject(error)
7
+ //console.log(reason)
8
+ //console.log(stdout)
9
+ resolve();
10
+ });
11
+ })
12
+ }
@@ -0,0 +1,3 @@
1
+ describe('Thing does stuff', function(){
2
+ it('must do integration stuff')
3
+ })
@@ -0,0 +1,3 @@
1
+ module.exports = function delay(ms) {
2
+ return new Promise((resolve) => setTimeout(resolve, ms));
3
+ }