I worked on a project with Spring Boot java framework where guys automated API docs generation. Every time you run BDD/Integration style tests, there was api blue print file created out from mocha tests. Then it ran generate-html-from-api blueprint. I liked this approach as it has two advantages:
1) API docs are always correct and up-to-date
2) saves time, because no need to write another documentation file (like apidoc).
Has anyone tried and has working example for node projects? I found api-doc-test plugin, however its documentation is limited. ? Ideally, I would like just to run:
mocha --recursive
Which would generate api-doc.html and place under test/tmp/.
I have looked at swagger but I really don't want to specify endpoint information twice and it would really be awesome just write once in BDD tests and have double result (tests + docs) at the same time.
https://github.com/stackia/test2doc.js
I'm working on this project, which enables generating documents (currently only API blueprint) from BDD tests, just exactly what you need.
Test code example:
const doc = require('test2doc')
const request = require('supertest') // We use supertest as the HTTP request library
require('should') // and use should as the assertion library
// For Koa, you should exports app.listen() or app.callback() in your app entry
const app = require('./my-express-app.js')
after(function () {
doc.emit('api-documentation.apib')
})
doc.group('Products').is(doc => {
describe('#Products', function () {
doc.action('Get all products').is(doc => {
it('should get all products', function () {
// Write specs towards your API endpoint as you would normally do
// Just decorate with some utility methods
return request(app)
.get(doc.get('/products'))
.query(doc.query({
minPrice: doc.val(10, 'Only products of which price >= this value should be returned')
}))
.expect(200)
.then(res => {
body = doc.resBody(res.body)
body.desc('List of all products')
.should.not.be.empty()
body[0].should.have.properties('id', 'name', 'price')
body[0].price.desc('Price of this product').should.be.a.Number
})
})
})
})
})
Related
I'm walking through the Javascript demos of pg-promise-demo and I have a question about the route /api/users/:name.
Running this locally works, the user is entered into the database, but is there a reason this wouldn't be a POST? Is there some sort of advantage to creating a user in the database using GET?
// index.js
// --------
app.get('/api/users/:name', async (req, res) => {
try {
const data = (req) => {
return db.task('add-user', async (t) => {
const user = await t.users.findByName(req.params.name);
return user || t.users.add(req.params.name);
});
};
} catch (err) {
// do something with error
}
});
For brevity I'll omit the code for t.users.findByName(name) and t.users.add(name) but they use QueryFile to execute a SQL command.
EDIT: Update link to pg-promise-demo.
The reason is explained right at the top of that file:
IMPORTANT:
Do not re-use the HTTP-service part of the code from here!
It is an over-simplified HTTP service with just GET handlers, because:
This demo is to be tested by typing URL-s manually in the browser;
The focus here is on a proper database layer only, not an HTTP service.
I think it is pretty clear that you are not supposed to follow the HTTP implementation of the demo, rather its database layer only. The demo's purpose is to teach you how to organize a database layer in a large application, and not how to develop HTTP services.
I want to test my nodejs code using Jest.
In my code I use stripe.
When requiring stripe you have to use this line
const stripe=require('stripe')("apikey");
in order to be able to access the stripe methods.
Obviously that's the library I want to mock, but if I do
jest.mock('stripe');
I cannot mock the stripe methods I need as it's like doing a require without passing the key in the higher order function.
I could not find any correlation around.
Is there a way to achieve that?
I figure you'll need to build your entire Stripe SDK mock. This is what's working for me atm:
// Stripe SDK mock
jest.mock('stripe', () => {
return jest.fn().mockImplementation(() => {
return {
skus: {
retrieve: (sku, callback) => {
callback({}, {});
}
}
};
});
});
The above mock will return empty sku object when calling stripe.skus.retrieve(req.query.sku, function(err, sku) { ... })
Same should go for the rest. If you want this mock to return different kinds of data depending on input, you'll need to implement that logic in the mock.
Hope this helps,
Im currently working on several NodeJS APIs that do exploit a Neo4J Database. I want to do automated tests on each endpoints and make sure everything works (eg: POST a user should create a node user in my graph with the expected labels and properties)
As a junior developer Im not really sure where to start.
My initial idea is to set up a fixtures Neo4j database (by executing a long cypher query on a void graph that will generate fixtures data)
The issue is that this fixtures database will be affected by the different tests I do.
For Instance if i want to test a DELETE endpoint I will assert that a data will be deleted of my database.
I see two solutions for that :
Before testing an endpoint I generate some needed data. But then I
will have to make sure to delete them after the test to not impair
the fixtures and affect other endpoint tests.
Before testing an endpoint I clean the database, execute the fixtures query, and execute a second query to add some extra data to test my endpoint. Then for each endpoint im sure to have a clean database with eventually some extra data.
The first solution seems effort/time-consuming while the second seems a bit rough. Maybe my conception of automated tests is really wrong.
Here is an example of a test I have done (using mochajs and chai) Where I change the admin of an organisation :
describe('UPDATE organisation', () => {
before((doneBefore) => {
const admin1 = updateOrganisationUtilities.createAdmin('admin#test.com');
const admin2 = updateOrganisationUtilities.createAdmin('admin2#test.com');
Promise.all([admin1, admin2]).then(
(admins) => {
idAdmin = admins[0].id;
idAdmin2 = admins[1].id;
updateOrganisationUtilities.bindAdminToOrganisation(idAdmin, idOrganisation)
.then(() => {
doneBefore();
});
});
});
after((doneAfter) => {
Promise.all([
updateOrganisationUtilities.deleteExtraData(),
]).then(() => {
doneAfter();
});
});
it('Should update an organisation', (doneIt) => {
const req = {
method: 'PUT',
url: `/organisations/${idOrganisation}`,
payload: JSON.stringify({
name: 'organisation-test',
address: 'here',
trainingNumber: '15',
type: 'organisation.types.university',
expirationDate: new Date(),
idAdmin: idAdmin2,
}),
headers: {
authorization: token,
},
};
server.inject(req, (res) => {
assert.equal(res.statusCode, 200);
assert.exists(res.result.id);
assert.equal(res.result.address, 'here');
assert.equal(res.result.trainingNumber, '15');
assert.equal(res.result.type, 'organisation.types.university');
updateOrganisationUtilities.getLinkBetweenAdminAndOrga(res.result.id, idAdmin2)
.then((link) => {
assert.include(link, 'IS_ADMIN');
assert.include(link, 'ROLE');
doneIt();
});
});
});
});
As you can see :
I create some usefull extra data in before()
I delete the extra data in after()
The method updateOrganisationUtilities.getLinkBetweenAdminAndOrga()
check if the changes in Neo4j has been correctly applied.
It seems working but Im afraid that it's going to be a PITA to maintain this kind of structure when I will have hundreds of tests that might alter the database. Moreover I fear consuming too much time with this way of testing my endpoints since I have to write specific functions/queries before and after each endpoint test.
I'm sorry if my question seems wide open but im very curious about how experienced developers deal with endpoints automated tests.
To ensure that unexpected changes from one test do not affect another test, you should completely empty out the DB after each test, and create the appropriate fixture before each test. Not only would this ensure that you are testing with the data you expect, but it will make implementing the tests easier.
Given that there are plenty of libraries for generating mock/fake data starting from a JSON schema or a Mongoose model and so on, how to test the behavior of a sw (let's say a web api) for the wrong data cases.
For example let's say I have a user service with name, email, phone, etc and a deep description of its fields data content. Let's say I have also different error codes that should be thrown for each possible error. I can't understand how to programmatically produce bad mock data (wrong email, bad formed name, etc) to put inside a test.
Moreover are there some test-process specs for these cases?
Thanks!
---- Integration for to answer to TGW: I'm doing standard tests, something like:
const app = require(-myapp-); //express or whatever app
const userModel = require('-myModelDefinition-); //e.g. json schema
const mockingLibrary = require(-mockingLibrary-); //Sinon or any other
//I'll test that the user->create method works properly on good input
const fakeUser = mockingLibrary.mock(userModel);
describe('\'users\' service', () => {
it('create method - good case',()=>{
return app.service('users')
.create(fakeUser)
.should.eventually
.have.property('_id'); //or any other test
});
});
//What if I want to test on bad input?
const fakeUserWithErrorOnEmail = mockingLibrary.mock(userModel,{errorOn:'email'});
describe('\'users\' service', () => {
it('create method - bad email case',done=>{
return app.service('users')
.create(fakeUserWithErrorOnEmail)
should.be.rejectedWith(Error, "email-error-message");
});
});
So what I'm looking for, maybe, is a mocking library able to produce both good and bad mock data given the description/schema of good ones.
I have JSON API built with koa which I am trying to cover with integration tests.
A simple test would look like this:
describe("GET: /users", function() {
it ("should respond", function (done) {
request(server)
.get('/api/users')
.expect(200, done);
});
});
Now the issue comes when the actions behind a controller - lets say saveUser at POST /users - use external resources. For instance I need to validate the users phone number.
My controller looks like this:
save: async function(ctx, next) {
const userFromRequest = await parse(ctx);
try {
// validate data
await ctx.repo.validate(userFromRequest);
// validate mobile code
await ctx.repo.validateSMSCode(
userFromRequest.mobile_number_verification_token,
userFromRequest.mobile_number.prefix + userFromRequest.mobile_number.number
);
const user = await ctx.repo.create(userFromRequest);
return ctx.data(201, { user });
} catch (e) {
return ctx.error(422, e.message, e.meta);
}
}
I was hoping to be able to mock the ctx.repo on the request object but I can't seem to able to get a hold on it from test, which means that my tests are actually hitting the phone number verification service.
Are there any ways I could go around hitting that verification service ?
Have you considered using a mockup library like https://github.com/mfncooper/mockery?
Typically, when writing tests requiring external services, I mock the service client library module. For example, using mocha:
mockery = require('mockery');
repo = require('your-repo-module');
before(function() {
mockery.enable();
repo.validateSMSCode = function() {...};
mockery.registerMock('your-repo-module', repo);
}
This way, every time you require your-repo-module, the mocked module will be loaded rather than the original one. Until you disable the mock, obviously...
app.context is the prototype from which ctx is created from. You may
add additional properties to ctx by editing app.context. This is
useful for adding properties or methods to ctx to be used across your
entire app, which may be more performant (no middleware) and/or easier
(fewer require()s) at the expense of relying more on ctx, which could
be considered an anti-pattern.
app.context.someProp = "Some Value";
app.use(async (ctx) => {
console.log(ctx.someProp);
});
For your sample your re-define app.context.repo.validateSMSCode like this, assuming that you have following setup lines in your test:
import app from '../app'
import supertest from 'supertest'
app.context.repo.validateSMSCode = async function(ctx, next) {
// Your logic here.
};
const request = supertest.agent(app.listen())
After re-defining app.context.repo.validateSMSCode method that your will define in your test, will work, instead of original method.
https://github.com/koajs/koa/blob/v2.x/docs/api/index.md#appcontext
https://github.com/koajs/koa/issues/652