如何使用Jest / Supertest / Knex / Postgres处理外键约束

时间:2019-12-25 23:15:58

标签: javascript node.js postgresql jestjs knex.js

我正在尝试为我的应用程序编写测试。我正在使用Jest&Supertest来运行所有测试。尝试运行测试套件时,出现关于外键约束的错误。

错误:

error: truncate "users" restart identity - cannot truncate a table referenced in a foreign key constrainterror: cannot truncate a table referenced in a foreign key constraint

这是我的server.spec.js文件:

const request = require('supertest');
const server = require('./server.js');
const db = require('../data/db-config.js');

describe('server.js', () => {
    describe('POST /register', () => {
        it('should return 201 created', async () => {
            const user = 
                { 
                    name: "test",
                    username: "test",
                    email: "test77@test.com",
                    password: "password"
                }
            const res = await request(server).post('/api/auth/register').send(user);
            expect(res.status).toBe(201);
        })

        beforeEach(async () => {
            await db("graphs").truncate();
            await db("users").truncate();
          });
    })
})

这是我的knex迁移文件:

exports.up = function(knex) {
  return (
      knex.schema
        .createTable('users', tbl => {
            tbl.increments();
            tbl.string('username', 255).notNullable();
            tbl.string('password', 255).notNullable();
            tbl.string('name', 255).notNullable();
            tbl.string('email', 255).unique().notNullable();
        })
        .createTable('graphs', tbl => {
          tbl.increments();
          tbl.string('graph_name', 255).notNullable();
          tbl.specificType('dataset', 'integer[]').notNullable();
          tbl
            .integer('user_id')
            .unsigned()
            .notNullable()
            .references('id')
            .inTable('users')
            .onDelete('CASCADE')
            .onUpdate('CASCADE');
        })
  )
};

exports.down = function(knex) {
  return (
      knex.schema
        .dropTableIfExists('graphs')  
        .dropTableIfExists('users')
  )
};

我在研究中遇到了以下答案:How to test tables linked with foreign keys?

我对Postgres和测试都是陌生的。有意义的是,我需要像在迁移中一样以相反的顺序删除表。但是,当我尝试在测试的beforeEach部分中截断它们时,表的列出顺序似乎无关紧要。

我不确定从这里到底要去哪里。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

我认为这里的诀窍是诉诸knex.raw

await db.raw('TRUNCATE graphs, users RESTART IDENTITY CASCADE');

CASCADE是因为您不希望外键约束成为障碍,而RESTART IDENTITY是因为Postgres的默认行为是不重置序列。参见TRUNCATE

虽然我们涉及的是相关主题,但让我介绍一些可能会使您的生活更轻松的事情:模板数据库!模板是Postgres可以用来从已知状态(通过复制)非常快速地重新创建数据库的数据库。这甚至比截断表还要快,并且允许我们在测试时跳过所有烦人的外键。

例如,您可以使用raw执行以下操作:

DROP DATABASE testdb;
CREATE DATABASE testdb TEMPLATE testdb_template;

这是一个非常便宜的操作,并且非常适合测试,因为每次执行测试时,您都可以从一个已知状态开始(不一定是空状态)。我想知道的警告是,您的knexfile.js将需要指定一个与具有足够凭据才能创建和删除数据库的用户建立连接(因此,可能仅知道localhost的“ admin”连接),并且该模板必须创建和维护。有关更多信息,请参见Template Databases