Skip to content

Commit

Permalink
feat(examples): working e2e example
Browse files Browse the repository at this point in the history
  • Loading branch information
mefellows committed Jan 18, 2017
1 parent 274f18f commit 24b9888
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 101 deletions.
6 changes: 3 additions & 3 deletions examples/e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ Given an animal profile, recommends a suitable partner based on similar interest
## Running

1. `npm install`
1. `npm test:consumer`
1. `npm test:publish`
1. `npm test:provider`
1. `npm test:consumer` - Run consumer tests
1. `npm test:publish` - Publish contracts to the broker
1. `npm test:provider` - Run provider tests


## Viewing contracts with the Pact Broker
Expand Down
30 changes: 20 additions & 10 deletions examples/e2e/consumer.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,28 @@ const availableAnimals = () => {
return availableAnimals().then(available => {
const eligible = available.filter(a => !predicates.map(p => p(a, mate)).includes(false));

return eligible.map(candidate => {
const score = weights.reduce((acc, weight) => {
return acc - weight(candidate, mate);
}, 100);
return {
suggestions: eligible.map(candidate => {
const score = weights.reduce((acc, weight) => {
return acc - weight(candidate, mate);
}, 100);

return {
'score': score,
'animal': candidate
};
});
return {
score,
'animal': candidate
};
})
};
});
};

const getAnimalById = (id) => {
return request
.get(`${API_HOST}/animals/${id}`)
.then(res => res.body,
err => null);
};

// API
server.get('/suggestions/:animalId', (req, res) => {
if (!req.params.animalId) {
Expand All @@ -64,5 +73,6 @@ const availableAnimals = () => {
module.exports = {
server,
availableAnimals,
suggestion
suggestion,
getAnimalById
};
4 changes: 3 additions & 1 deletion examples/e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"version": "1.0.0",
"description": "Pact JS E2E Example",
"scripts": {
"test": "./node_modules/.bin/mocha test/consumer.spec.js",
"test:consumer": "./node_modules/.bin/mocha test/consumer.spec.js",
"test:publish": "node test/publish.js",
"test:provider": "node test/provider.spec.js",
"consumer": "node ./consumerService.js",
"provider": "node ./providerService.js"
},
Expand Down
27 changes: 18 additions & 9 deletions examples/e2e/provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@ const Repository = require('./repository');
const server = express();
server.use(cors());
server.use(bodyParser.json());
server.use(bodyParser.urlencoded({extended: true}));
server.use(bodyParser.urlencoded({ extended: true }));
server.use((req, res, next) => {
res.header('Content-Type', 'application/json; charset=utf-8');
next();
});

// Load data into a repository
const animalRepository = new Repository();
const data = require('./data/animalData.json');
data.reduce( (a, v) => {
v.id = a + 1;
animalRepository.insert(v);
return a + 1;
}, 0);
const importData = () => {
const data = require('./data/animalData.json');
data.reduce( (a, v) => {
v.id = a + 1;
animalRepository.insert(v);
return a + 1;
}, 0);
}

// Suggestions function:
// Given availability and sex, find available suitors...
Expand All @@ -39,7 +45,6 @@ server.get('/animals/available', (req, res) => {
server.get('/animals/:id', (req, res) => {
const response = animalRepository.getById(req.params.id);
if (response) {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(response));
} else {
res.writeHead(404);
Expand All @@ -66,4 +71,8 @@ server.post('/animals', (req, res) => {
res.end();
});

module.exports = server;
module.exports = {
server,
importData,
animalRepository
};
3 changes: 2 additions & 1 deletion examples/e2e/providerService.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
let server = require('./provider.js');
let { server, importData } = require('./provider.js');
importData();

server = server.listen(8081, () => {
const host = server.address().address;
Expand Down
185 changes: 119 additions & 66 deletions examples/e2e/test/consumer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const path = require('path');
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const expect = chai.expect;
const Pact = require('pact');
const pact = require('pact');
const mockservice = require('@pact-foundation/pact-node');
const MOCK_SERVER_PORT = 1234;
const LOG_LEVEL = process.env.LOG_LEVEL || 'WARN';
Expand All @@ -11,15 +11,15 @@ chai.use(chaiAsPromised);

// Configure and import consumer API
process.env.API_HOST = `http://localhost:${MOCK_SERVER_PORT}`;
const { suggestion } = require('../consumer');
const { suggestion, getAnimalById } = require('../consumer');

describe('Pact', () => {
let provider;

// Alias flexible matchers for simplicity
const term = Pact.Matchers.term;
const like = Pact.Matchers.somethingLike;
const eachLike = Pact.Matchers.eachLike;
const term = pact.Matchers.term;
const like = pact.Matchers.somethingLike;
const eachLike = pact.Matchers.eachLike;

// Configure mock server
const mockServer = mockservice.createServer({
Expand All @@ -32,88 +32,141 @@ describe('Pact', () => {
});
mockservice.logLevel(LOG_LEVEL);

// Animal we want to match :)
const suitor = {
"id": 2,
"first_name": "Nanny",
"animal": "goat",
"last_name": "Doe",
"age": 27,
"gender": "F",
"location": {
"description": "Werribee Zoo",
"country": "Australia",
"post_code": 3000
'id': 2,
'first_name': 'Nanny',
'animal': 'goat',
'last_name': 'Doe',
'age': 27,
'gender': 'F',
'location': {
'description': 'Werribee Zoo',
'country': 'Australia',
'post_code': 3000
},
"eligibility": {
"available": true,
"previously_married": true
'eligibility': {
'available': true,
'previously_married': true
},
"interests": [
"walks in the garden/meadow",
"parkour"
'interests': [
'walks in the garden/meadow',
'parkour'
]
};

const MIN_ANIMALS = 2;

// Define animal list payload, with flexible matchers
const animalListExpectation = eachLike({
"id": like(1),
"first_name": like("Billy"),
"last_name": like("Goat"),
"animal": like("goat"),
"age": like(21),
"gender": term({matcher: "F|M", generate: "M"}),
"location": {
"description": like("Melbourne Zoo"),
"country": like("Australia"),
"post_code": like(3000)
const animalBodyExpectation = {
'id': like(1),
'first_name': like('Billy'),
'last_name': like('Goat'),
'animal': like('goat'),
'age': like(21),
'gender': term({ matcher: 'F|M', generate: 'M' }),
'location': {
'description': like('Melbourne Zoo'),
'country': like('Australia'),
'post_code': like(3000)
},
"eligibility": {
"available": like(true),
"previously_married": like(false)
'eligibility': {
'available': like(true),
'previously_married': like(false)
},
"interests": eachLike("walks in the garden/meadow")
}, {min: 2});

before((done) => {
'interests': eachLike('walks in the garden/meadow')
};
const animalListExpectation = eachLike(animalBodyExpectation, { min: MIN_ANIMALS });

// Start mock server
// Start mock server before unit tests
before(done => {
mockServer.start()
.then(() => {
provider = Pact({consumer: 'Matching Service', provider: 'Animal Profile Service', port: MOCK_SERVER_PORT});
.then(() => {
provider = pact({ consumer: 'Matching Service', provider: 'Animal Profile Service', port: MOCK_SERVER_PORT });

// Add interactions
provider.addInteraction({
state: 'Has some animals',
uponReceiving: 'a request for all animals',
withRequest: {
method: 'GET',
path: '/animals/available',
},
willRespondWith: {
status: 200,
headers: {'Content-Type': 'application/json'},
body: animalListExpectation
}
}).then(() => done());
})
.catch(e => {
console.log("ERROR: ", e);
done();
});
// Add interactions
return provider.addInteraction({
state: 'Has some animals',
uponReceiving: 'a request for all animals',
withRequest: {
method: 'GET',
path: '/animals/available'
},
willRespondWith: {
status: 200,
headers: { 'Content-Type': 'application/json; charset=utf-8' },
body: animalListExpectation
}
});
})
.then(() => {
return provider.addInteraction({
state: 'Has no animals',
uponReceiving: 'a request for an animal with ID 100',
withRequest: {
method: 'GET',
path: '/animals/100'
},
willRespondWith: {
status: 404
}
});
})
.then(() => {
return provider.addInteraction({
state: 'Has an animal with ID 1',
uponReceiving: 'a request for an animal with ID 1',
withRequest: {
method: 'GET',
path: '/animals/1'
},
willRespondWith: {
status: 200,
headers: { 'Content-Type': 'application/json; charset=utf-8' },
body: animalBodyExpectation
}
});
})
.then(() => done())
.catch(e => {
console.log('ERROR: ', e);
done();
});
});

// Verify service client works as expected
it('returns a list of animals', (done) => {
const suggestedMates = suggestion(suitor);
describe('when a call to list all animals from the Animal Service is made', () => {
describe('and there are animals in the database', () => {
it('returns a list of animals', done => {
const suggestedMates = suggestion(suitor);

expect(suggestedMates).to.eventually.have.deep.property('suggestions[0].score', 94);
expect(suggestedMates).to.eventually.have.property('suggestions').with.lengthOf(MIN_ANIMALS).notify(done);
});
});
});
describe('when a call to the Animal Service is made to retreive a single animal by ID', () => {
describe('and there is an animal in the DB with ID 1', () => {
it('returns the animal', done => {
const suggestedMates = getAnimalById(1);

expect(suggestedMates).to.eventually.have.lengthOf(2);
expect(suggestedMates).to.eventually.be.a('array').notify(done);
expect(suggestedMates).to.eventually.have.deep.property('id', 1).notify(done);
// expect(suggestedMates).to.eventually.have.property('suggestions').with.lengthOf(MIN_ANIMALS).notify(done);
});
});
describe('and there no animals in the database', () => {
it('returns a 404', done => {
const suggestedMates = getAnimalById(100);

expect(suggestedMates).to.eventually.be.a('null').notify(done);
});
});
});

// Write pact files
after(() => {
provider.finalize().then(() => {
mockservice.removeAllServers()
mockservice.removeAllServers();
});
});
});
Loading

0 comments on commit 24b9888

Please sign in to comment.