简体   繁体   中英

Testing Node.js API that uses Sequelize with Mocha/Expect/Supertest

I have been working on a nodejs API that works with postgres and I'm having an issue testing with expect . Sequelize is returning all fields as a string value no matter what the type is.

When using .toMatchObject an error is thrown because in original object and in database id is a numeric value, but is returned as a string. Same happens with decimal.

Is there a way to get data how it's stored, not as string?

Is there different way to check if objects match without having to parse each attribute to be same type as original ?

I tried using raw:true as i read online, but it didnt work. Node version is 9.9, expect version is 22.4.3, sequelize version is 4.37

Testing code that fails is as follows:

it('should create new zgrada', (done) => {
    var newZgrada = {
        sifra_zgrade: 1006,
        ulica: "Derpa derpsona",
        kucni_broj: "77",
        dodatak_na_kucni_broj: "A"
    };
    request(app)
        .post('/zgrade')
        .send(newZgrada)
        .expect(200)
        .expect((res) => {
            expect(res.body.zgrada).toMatchObject(newZgrada);
        })
        .end((err, res) => {
            if (err) {
                return done(err);
            }

            db.zgrada.findAll({
                where: {
                    sifra_zgrade: newZgrada.sifra_zgrade
                }
            }).then((zgrada) => {
                expect(zgrada.length).toBe(1);
                expect(zgrada).toMatchObject(newZgrada);
                done();
            }).catch((e) => done(e));
        });
});

Error received is:

1) POST /zgrada should create new zgrada: Error: expect(received).toMatchObject(expected)

  Object {
    "dodatak_na_kucni_broj": "A",
    "kucni_broj": "77",
-   "sifra_zgrade": 1006,
+   "sifra_zgrade": "1006",
    "ulica": "Derpa derpsona",
  }

When I swap toMatchObject() with .toBe() then it works but I have to go through each attribute separately and cast the ones that are numeric to string first which is not practical for a bigger project with different models and many attributes.

edit: model definition (some attributes are left out but not relevant for error):

module.exports = (sequelize, DataTypes) => {
var Zgrada = sequelize.define('zgrada', {
    sifra_zgrade: {
        type: DataTypes.NUMERIC(0, 4),
        unique: true,
        primaryKey: true,
        allowNull: false
    },
    ulica: {
        type: DataTypes.STRING,
        allowNull: false
    },
    postanski_broj: {
        type: DataTypes.STRING
    },
    kucni_broj: {
        type: DataTypes.STRING
    },
    dodatak_na_kucni_broj: {
        type: DataTypes.STRING
    }
}

Post method:

router
    .post("/", async (req, res) => {
        try {
            var body = req.body;
            var zgrada = await db.zgrada.create({
                sifra_zgrade: body.sifra_zgrade,
                ulica: body.ulica,
                kucni_broj: body.kucni_broj,
                dodatak_na_kucni_broj: body.dodatak_na_kucni_broj,
            });
            res.send({
                zgrada
            });
        } catch (e) {
            res.status(400).send(e);
        }
    });
}

Thank you for help

Sequelize is returning all fields as a string value no matter what the type is.

Sequelize uses the pg module as a bridge for postgres. In pg , Decimal (alias: Numeric ) type are returned as String values by design for reasons concerned with the safety and precision of parseInt in JS. For more information see this Issue on node-postgres Github .

Is there a way to get data how it's stored, not as string?

As of Sequelize version 4.32.5, an underlying dependency regarding type parsing was changed and there is an open issue with the same concern as this question linked here .

In short, there isn't much you can do with your current setup.

Other Solutions:

1) Use a different type such as DataTypes.UUID or DataTypes.Integer if possible. Especially given that sifra_zgrade seems to be acting as an primary key/id column, it seems likely that the type could be changed.

2) Rollback to Sequelize version 4.23.3 and manually change how pg-types parses decimals only if you're operating within a safe decimal precision range :

var pg = require('pg');
pg.types.setTypeParser(1700, 'text', parseFloat);

Is there different way to check if objects match without having to parse each attribute to be same type as original ?

As far as I understand, solutions would have to use underlying type-converting comparisons ( == ) instead of strict equality comparisons.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM