Skip to content
This repository was archived by the owner on Jun 27, 2019. It is now read-only.

Commit c482ff0

Browse files
Merge pull request #107 from Human-Connection/cucumber-js
Introduce cucumber-js
2 parents 309787d + c0431d6 commit c482ff0

File tree

11 files changed

+533
-11
lines changed

11 files changed

+533
-11
lines changed

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ jobs:
2222
- script:
2323
- yarn install --frozen-lockfile --non-interactive
2424
- yarn add codacy-coverage
25-
- yarn test
25+
- yarn run eslint
26+
- cp config/cucumber.json config/local.json
27+
- yarn run test:coverage
2628
- cat ./coverage/lcov.info | codacy-coverage
2729

2830
after_success:

config/cucumber.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"host": "localhost",
3+
"port": 3030,
4+
"baseURL": "http://localhost:3030",
5+
"frontURL": "http://localhost:3000",
6+
"smtpConfig": {
7+
"host": "0.0.0.0",
8+
"port": 1025,
9+
"ignoreTLS": true
10+
},
11+
"thumbor": {
12+
"url": "",
13+
"key": ""
14+
},
15+
"seeder": {
16+
"runOnInit": false,
17+
"dropDatabase": false
18+
},
19+
"defaultEmail": "[email protected]"
20+
}

features/api/post.feature

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Feature: Import a post from an organization and publish it in Human Connection
2+
As a user of human connection
3+
You would like to publish a post programmatically
4+
In order to automate things
5+
6+
7+
Background:
8+
Given the Human Connection API is up and running
9+
And there is a user in Human Connection with these credentials:
10+
| email | password |
11+
| user@example.com | 1234 |
12+
13+
Scenario: Get a JWT token
14+
When you send a POST request to "/authentication" with:
15+
"""
16+
{
17+
"email": "[email protected]",
18+
"password": "1234",
19+
"strategy": "local"
20+
}
21+
"""
22+
Then there is an access token in the response:
23+
"""
24+
{
25+
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6ImFjY2VzcyIsInR5cGUiOiJhY2Nlc3MifQ..."
26+
}
27+
"""
28+
29+
Scenario: Publish a post
30+
Given you are authenticated
31+
When you send a POST request to "/contributions" with:
32+
"""
33+
{
34+
"title": "Cool title",
35+
"content": "<p>A nice content</p>",
36+
"contentExcerpt": "Nice",
37+
"type": "post",
38+
"language": "de",
39+
"categoryIds": ["5ac7768f8d655d2ee6d48fe4"]
40+
}
41+
"""
42+
Then a new post is created

features/api/usersettings.feature

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Feature: Save current newsfeed filters to usersettings
2+
As a user of human connection
3+
You would like to have my latest newsfeed filter settings saved
4+
In order to see the same selection of content next time I log in
5+
6+
Background:
7+
Given the Human Connection API is up and running
8+
And there is a user in Human Connection with these credentials:
9+
| email | password | isVerified |
10+
| user@example.com | 1234 | true |
11+
12+
Scenario: Save user's language
13+
Given you are authenticated
14+
When you create your user settings via POST request to "/usersettings" with:
15+
"""
16+
{
17+
"uiLanguage": "de"
18+
}
19+
"""
20+
Then your language "de" is stored in your user settings

features/env/database.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* eslint no-console: off */
2+
const { Before, AfterAll, setWorldConstructor } = require('cucumber');
3+
4+
process.env.NODE_ENV = 'test'; // write into the test database
5+
const backendApp = require('../../server/app');
6+
7+
function CustomWorld() {
8+
this.app = backendApp;
9+
}
10+
setWorldConstructor(CustomWorld);
11+
12+
// Asynchronous Promise
13+
Before((_, callback) => {
14+
backendApp.get('mongooseClient').connection.dropDatabase().then(() => {
15+
callback();
16+
});
17+
});
18+
19+
AfterAll((callback) => {
20+
backendApp.get('mongooseClient').disconnect().then(() => {
21+
callback();
22+
});
23+
});

features/env/io.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/* eslint no-console: off */
2+
const { Before } = require('cucumber');
3+
const fs = require('fs-extra');
4+
5+
const tmpDir = './tmp';
6+
7+
Before(() => fs.remove(tmpDir).then(() => fs.ensureDir(tmpDir)));
8+

features/env/timeout.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const { setDefaultTimeout } = require('cucumber');
2+
3+
setDefaultTimeout(60 * 1000);

features/step_definitions/steps.js

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/* eslint no-unused-expressions: off */
2+
/* eslint func-names: off */
3+
/* eslint no-underscore-dangle: off */
4+
const { Given, When, Then } = require('cucumber');
5+
const fetch = require('node-fetch');
6+
const { expect } = require('chai');
7+
const waitOn = require('wait-on');
8+
9+
const hcBackendUrl = 'http://localhost:3030';
10+
11+
let currentUser;
12+
let currentUserPassword;
13+
let httpResponse;
14+
let currentUserAccessToken;
15+
16+
function authenticate(email, plainTextPassword) {
17+
const formData = {
18+
email,
19+
password: plainTextPassword,
20+
strategy: 'local',
21+
};
22+
return fetch(`${hcBackendUrl}/authentication`, {
23+
method: 'post',
24+
body: JSON.stringify(formData),
25+
headers: { 'Content-Type': 'application/json' },
26+
}).then(response => response.json())
27+
.catch((err) => {
28+
throw (err);
29+
})
30+
.then(json => json.accessToken);
31+
}
32+
33+
function postRequest(route, body, callback) {
34+
const params = {
35+
method: 'post',
36+
body,
37+
headers: { 'Content-Type': 'application/json' },
38+
};
39+
if (currentUserAccessToken) {
40+
params.headers.Authorization = `Bearer ${currentUserAccessToken}`;
41+
}
42+
fetch(`${hcBackendUrl}${route}`, params)
43+
.then(response => response.json())
44+
.catch((err) => {
45+
throw (err);
46+
})
47+
.then((json) => {
48+
httpResponse = json;
49+
callback();
50+
});
51+
}
52+
53+
Given(/^the Human Connection API is up and running(?: on "http:\/\/localhost:3030")?/, (callback) => {
54+
waitOn({ resources: ['tcp:3030'], timeout: 30000 }, (err) => {
55+
if (err) throw (err);
56+
return callback();
57+
});
58+
});
59+
60+
Given('there is a 3rd party application running, e.g. \'Democracy\'', () => {
61+
// Just documentation
62+
});
63+
64+
Given('there is a user in Human Connection with these credentials:', function (dataTable) {
65+
const params = dataTable.hashes()[0];
66+
currentUserPassword = params.password;
67+
return this.app.service('users').create(params).then((user) => {
68+
currentUser = user;
69+
});
70+
});
71+
72+
Given('you are authenticated', () => authenticate(currentUser.email, currentUserPassword).then((accessToken) => {
73+
currentUserAccessToken = accessToken;
74+
}));
75+
76+
When('you send a POST request to {string} with:', (route, body, callback) => postRequest(route, body, callback));
77+
78+
Then('there is an access token in the response:', (jsonResponse) => {
79+
expect(httpResponse.accessToken).to.be.a('string');
80+
expect(httpResponse.accessToken.length).to.eq(342);
81+
const expectedAccessToken = JSON.parse(jsonResponse).accessToken;
82+
const expectedFirstPartOfJwt = expectedAccessToken.split('.')[0];
83+
expect(httpResponse.accessToken.split('.')[0]).to.eq(expectedFirstPartOfJwt);
84+
});
85+
86+
Then('a new post is created', function () {
87+
return this.app.service('contributions').find({}).then((contributions) => {
88+
expect(contributions.total).to.eq(1);
89+
expect(contributions.data[0].type).to.eq('post');
90+
});
91+
});
92+
93+
94+
Then('your language {string} is stored in your user settings', function (lang) {
95+
return this.app.service('usersettings').find({userId: currentUser._id.toString()}).then((settings) => {
96+
expect(settings.total).to.eq(1);
97+
expect(settings.data[0].uiLanguage).to.eq(lang);
98+
});
99+
});
100+
101+
Then('debug', function() {
102+
// eslint-disable-next-line no-debugger
103+
debugger;
104+
});
105+
106+
When('you create your user settings via POST request to {string} with:', function (route, body, callback) {
107+
let jsonBody = JSON.parse(body);
108+
jsonBody.userId = currentUser._id.toString();
109+
postRequest(route, JSON.stringify(jsonBody), callback);
110+
});
111+

package.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,20 @@
3434
},
3535
"scripts": {
3636
"clear": "rm -Rf tmp",
37-
"test": "npm run eslint && cross-env NODE_ENV=test && nyc --reporter=lcovonly --reporter=text-summary npm run mocha",
37+
"test": "npm run mocha && npm run cucumber",
38+
"test:coverage": "nyc --reporter=lcovonly --reporter=text-summary npm run test",
3839
"test:mongo": "npm run eslint && cross-env NODE_ENV=test && nyc --reporter=lcovonly --reporter=text-summary npm run mocha:mongo",
39-
"eslint": "eslint server/. test/. --config .eslintrc.json",
40+
"eslint": "eslint server/. test/. features/. --config .eslintrc.json",
4041
"start": "concurrently 'mongod' 'wait-on tcp:27017 && cross-env NODE_ENV=production node server/'",
4142
"dev:debug": "npm run clear && concurrently '$npm_package_config_mongoDev &>/dev/null' 'wait-on tcp:27017 && cross-env DEBUG=feathers && cross-env NODE_ENV=development nodemon --inspect server/'",
4243
"dev": "npm run clear && concurrently '$npm_package_config_mongoDev &>/dev/null' 'wait-on tcp:27017 && cross-env DEBUG=feathers && cross-env NODE_ENV=development nodemon server/'",
4344
"dev:local": "sh scripts/run-local.sh",
4445
"dev:noseed": "concurrently 'mongod --dbpath data' 'wait-on tcp:27017 && NODE_ENV=development DEBUG=feathers nodemon server/'",
4546
"dev:win": "npm run clear && concurrently \"mongod --dbpath /data/db\" \"wait-on tcp:27017&&cross-env NODE_ENV=development&&cross-env DEBUG=feathers&& nodemon --inspect server/\"",
4647
"mocha": "npm run clear && $npm_package_config_mocha",
47-
"mocha:mongo": "$npm_package_config_concurrently '$npm_package_config_mongoDev &>/dev/null' 'wait-on tcp:27017 && npm run mocha'"
48+
"mocha:mongo": "$npm_package_config_concurrently '$npm_package_config_mongoDev &>/dev/null' 'wait-on tcp:27017 && npm run mocha'",
49+
"cucumber": "npm run clear && concurrently --kill-others --success first 'cross-env NODE_ENV=test node server/' 'wait-on tcp:3030 && cross-env NODE_ENV=test cucumber-js'",
50+
"cucumber:mongo": "npm run clear && concurrently --kill-others --success first '$npm_package_config_mongoDev &>/dev/null || sleep infinity' 'wait-on tcp:27017 && cross-env NODE_ENV=test node server/' 'wait-on tcp:3030 && cross-env NODE_ENV=test cucumber-js'"
4851
},
4952
"config": {
5053
"mongoDev": "mongod --dbpath data --quiet",
@@ -106,11 +109,14 @@
106109
},
107110
"devDependencies": {
108111
"babel-eslint": "~8.2.6",
112+
"chai": "^4.1.2",
113+
"cucumber": "^4.2.1",
109114
"concurrently": "~3.6.0",
110115
"cross-env": "^5.2.0",
111116
"eslint": "~4.19.1",
112117
"istanbul": "1.1.0-alpha.1",
113118
"mocha": "~5.2.0",
119+
"node-fetch": "^2.1.2",
114120
"nodemon": "~1.18.1",
115121
"nyc": "^12.0.2",
116122
"wait-on": "~2.1.0"

server/services/usersettings/usersettings.hooks.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
const { restrictToOwner } = require('feathers-authentication-hooks');
22
const mapCreateToUpsert = require('../../hooks/map-create-to-upsert');
3+
const auth = require('@feathersjs/authentication');
34

45
module.exports = {
56
before: {
67
all: [],
78
find: [],
89
get: [],
9-
create: [
10+
create: [
11+
auth.hooks.authenticate('jwt'),
1012
mapCreateToUpsert(context => {
1113
const { data } = context;
1214
return { userId: data.userId };
1315
})
1416
],
1517
update: [
18+
auth.hooks.authenticate('jwt'),
1619
restrictToOwner()
1720
],
1821
patch: [
22+
auth.hooks.authenticate('jwt'),
1923
restrictToOwner()
2024
],
2125
remove: [
26+
auth.hooks.authenticate('jwt'),
2227
restrictToOwner()
2328
]
2429
},

0 commit comments

Comments
 (0)