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.
- package/.dockerignore +4 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
- package/.github/workflows/main.yml +72 -0
- package/.nvmrc +1 -0
- package/LICENSE +674 -0
- package/README.md +24 -0
- package/TODO +17 -0
- package/adapters/Adapter.js +5 -0
- package/adapters/AdapterThing.spec.js +10 -0
- package/cucumber.js +3 -0
- package/docker-compose.yml +21 -0
- package/domain/Thing.port.js +5 -0
- package/domain/calculator.js +9 -0
- package/domain/domain.spec.js +14 -0
- package/domain/javascript-user-interface.js +22 -0
- package/domain/test-cases/all.js +5 -0
- package/domain/test-cases/sum.js +26 -0
- package/domain/test-cases/test-user.js +22 -0
- package/features/simple_math.feature +37 -0
- package/features/support/steps.js +15 -0
- package/features/support/transform.js +16 -0
- package/features/support/world.js +22 -0
- package/http-api/Dockerfile +21 -0
- package/http-api/healthcheck.js +36 -0
- package/http-api/start.js +26 -0
- package/lambda-function/Dockerfile +16 -0
- package/lambda-function/app.js +8 -0
- package/package.json +58 -0
- package/publish-on-docker-hub.sh +13 -0
- package/renovate.json +4 -0
- package/stryker.conf.js +13 -0
- package/test-doubles/FakeThing.spec.js +3 -0
- package/test-http-api/container-test-cases.js +19 -0
- package/test-http-api/delay.js +3 -0
- package/test-http-api/docker-compose.component.spec.js +33 -0
- package/test-http-api/docker.component.spec.js +40 -0
- package/test-http-api/http-api-user-interface.js +12 -0
- package/test-http-api/runCommand.js +12 -0
- package/test-integration/TestingThingDoesStuff.spec.js +3 -0
- package/test-lambda-function/delay.js +3 -0
- package/test-lambda-function/docker.component.spec.js +55 -0
- package/test-lambda-function/runCommand.js +12 -0
- package/test-lambda-function/testing-lambda-function-user-interface.js +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[](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?
|
package/cucumber.js
ADDED
|
@@ -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,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,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" ]
|
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
package/stryker.conf.js
ADDED
|
@@ -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,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,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 { 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
|
+
}
|