4

I am trying to write unittests for a loopback model using jasmine. My model has the usual CRUD endpoints but I have defined a custom '/products/:id/upload' endpoint which expects a form with files.

My model looks like

'use strict';

var loopback = require('loopback');

var ProductSchema = {
    location: {
        type: String, 
        required: true
    },
    version: {
        type: String,
        required: true
    },
    id: { type: Number, id: 1, generated: true }
};

var opts = {
    strict: true
};

var dataSource = loopback.createDataSource({
    connector: loopback.Memory
});
var Product = dataSource.createModel('Product', ProductSchema, opts);


Product.beforeRemote('upload', function(ctx){
    var uploader = function(req, res){
        // parse a multipart form
        res({
            result:'success'
        });
    };
    function createProduct(uploaderResult){
        // create a product out of the uploaded file
        ctx.res.send({
            result: uploaderResult.result
        });
    }
    uploader.upload(ctx.req, createProduct);
});

Product.upload = function () {
    // empty function - all the logic takes place inside before remote
};

loopback.remoteMethod(
    Product.upload,
    {
        accepts : [{arg: 'uploadedFiles', http: function(ctx){
                        return function() {
                            return { files : ctx.req.body.uploadedFiles, context : ctx };
                        };
                    }},
                   {arg: 'id', type: 'string'}],
        returns : {arg: 'upload_result', type: String},
        http: {path:'/:id/upload', verb: 'post'}
    }
);

module.exports = Product;

My end goal is to test the logic of the "createProduct". My test looks like

'use strict';

describe('Product Model', function(){
    var app = require('../../app');
    var loopback = require('loopback');
    var ProductModel;
    beforeEach(function(){
        app = loopback();
        app.boot(__dirname+'/../../'); // contains a 'models' folder
        ProductModel = loopback.getModel('Product');
        var dataSource = loopback.createDataSource({
            connector: loopback.Memory
        });

        ProductModel.attachTo(dataSource);
    });

    it('should load file ', function(){
        console.log(ProductModel.beforeRemote.toString());
        console.log(ProductModel);
        ProductModel.upload();
    });
});

By calling ProductModel.upload(); I was hoping to trigger the before remote hook which would exercise the the createProduct. I could test "createProduct" in isolation but then I would omit the fact that createProduct ends up being called as a result of upload.

To be perfectly clear, the core question is: How do I exercise remote method hooks inside unittests ?

1 Answers1

2

It was suggested to use supertest as an http server. Below there is a code snippet illustrating how to do it in jasmine

describe('My product suite', function(){
    var request = require('supertest');
    var app;

    beforeEach(function(){
        app = loopback();
        // don't forget to add REST to the app
        app.use(app.rest());
    });

    it('should load file', function() {
      request(app).post('/products/id-of-existing-product/upload')
        .attach('file', 'path/to/local/file/to/upload.png')
        .expect(200)
        .end(function(err, res) {
          if (err) return done(err);
          // res is the HTTP response
          // you can assert on res.body, etc.
        });
    });
});
  • Are there fixtures, so i can generate a guest instead of having to register? – Strawberry Aug 23 '14 at 02:00
  • I am not sure what needs to be registered. Could you please clarify ? – Leonidas Kapsokalivas Aug 26 '14 at 10:34
  • For example, registering a user, and logging in to get an auth token. It would be convenient to have fixtures in these situations instead of making a series of requests every time. – Strawberry Aug 26 '14 at 10:44
  • shouldnt the `app` variable be declared outside of the `beforeEach` function, so it would be available to supertest inside of the `it`. Also, I keep getting a 404 instead of 200 using this test. Any idea why? – britztopher Sep 16 '14 at 14:28
  • can you please udpate the answer with the context from the original question? There is no sign in this answer of including the model that the OP wanted to test. – Alexander Mills Oct 24 '16 at 23:05
  • Is this considered a unit test? It looks like a functional test to me. https://stackoverflow.com/a/2741836/6651596 – SifouTifou Oct 16 '19 at 20:34