unexpected-knex
Version:
Support for testing Knex.js models and migrations using Unexpected
1,578 lines (1,470 loc) • 98.6 kB
JavaScript
const path = require('path');
const Knex = require('knex');
const QueryBuilder = require('knex/lib/query/querybuilder');
const unexpected = require('unexpected');
const mockFs = require('mock-fs');
const unexpectedRequire = require('unexpected-require');
const unexpectedKnex = require('../lib/unexpected-knex');
const dontIndent = require('dedent-js');
const assertErrorOuput = process.env.ASSERT_ERROR_OUTPUT !== 'false';
// This file is `require`d lazily by Knex's migrator, so we have to require it
// here so that it's cached by Node.js before we go on to mock out `require`.
require('knex/lib/migrations/util/import-file.js');
// Knex `require`s migrations lazily and in the process tries to figure out if
// it should use `import` or `require`. The following hacks make it bypass those
// checks and default to using `require`.
if (process.env.npm_package_json) delete process.env.npm_package_json;
if (process.env.npm_package_type) delete process.env.npm_package_type;
describe('unexpected-knex', function () {
const host = process.env.PGHOST || 'localhost';
const knex = Knex({
client: 'pg',
connection: {
host,
port: '5432',
database: 'postgres',
user: 'postgres',
password: 'postgres',
},
migrations: { directory: './migrations' },
});
// synonymous to './migrations' as specified in the knex config
const migrationsDirectory = `${process.cwd()}/migrations`;
const knexOutputBlock = dontIndent`
knex({
client: 'pg',
connection: {
host: '${host}',
port: '5432',
database: 'postgres',
user: 'postgres',
password: 'postgres'
},
migrations: { directory: './migrations' }
})`;
const expect = unexpected
.clone()
.use(unexpectedRequire)
.use(unexpectedKnex)
.addAssertion(
'<any> with fs mocked out <object> <assertion>',
function (expect, subject, mocks) {
expect.errorMode = 'bubble';
mockFs(mocks);
return expect
.shift()
.then(function () {
mockFs.restore();
})
.catch(function (e) {
mockFs.restore();
throw e;
});
},
)
.addAssertion(
'<any> with the migrations directory containing <object> <assertion>',
function (expect, subject, migrations, ...rest) {
expect.errorMode = 'bubble';
const filenames = Object.keys(migrations);
const fsContext = {
[migrationsDirectory]: filenames.reduce((context, filename) => {
// File content doesn't matter for the knex migrator, what
// matters is the require() context
context[filename] = '';
return context;
}, {}),
};
const requireContext = filenames.reduce((context, filename) => {
const absolutePath = path.resolve(migrationsDirectory, filename);
context[absolutePath] = migrations[filename];
return context;
}, {});
return expect.apply(expect, [
subject,
'with fs mocked out',
fsContext,
'with require mocked out',
requireContext,
...rest,
]);
},
)
.addAssertion(
'<any> with no migrations directory <assertion>',
function (expect, subject, ...rest) {
expect.errorMode = 'bubble';
return expect.apply(expect, [
subject,
'with fs mocked out',
{},
...rest,
]);
},
)
.addAssertion(
'<any> with an empty migrations directory <assertion>',
function (expect, subject, ...rest) {
expect.errorMode = 'bubble';
return expect.apply(expect, [
subject,
'with fs mocked out',
{
[migrationsDirectory]: {},
},
...rest,
]);
},
);
afterEach(function () {
const user = knex.client.config.connection.user;
return knex.raw(`
DROP SCHEMA IF EXISTS public CASCADE;
CREATE SCHEMA public;
GRANT ALL ON SCHEMA public TO "${user}";
GRANT ALL ON SCHEMA public TO public;
COMMENT ON SCHEMA public IS 'standard public schema';
DROP SCHEMA IF EXISTS other CASCADE;
CREATE SCHEMA other;
GRANT ALL ON SCHEMA other TO "${user}";
GRANT ALL ON SCHEMA other TO public;
`);
});
after(function () {
return knex.destroy();
});
describe('<knex> to have table <string>', function () {
it('fulfils if the table exists', function () {
return knex.schema
.createTable('foo', (table) => {
table.timestamps();
})
.then(() =>
expect(expect(knex, 'to have table', 'foo'), 'to be fulfilled'),
);
});
it('rejects if the table does not exist', function () {
return expect(
expect(knex, 'to have table', 'foo'),
'to be rejected with',
/to have table 'foo'/,
);
});
describe('with the schema-name included (dot-separated)', function () {
beforeEach(function () {
return knex.raw(`
CREATE SCHEMA foo;
`);
});
afterEach(function () {
return knex.raw(`
DROP SCHEMA IF EXISTS foo CASCADE;
`);
});
it('fulfils if the schema and table exist', function () {
return knex.schema
.withSchema('foo')
.createTable('foo', (table) => {
table.timestamps();
})
.then(() =>
expect(expect(knex, 'to have table', 'foo.foo'), 'to be fulfilled'),
);
});
it('rejects if the schema exists but the table does not', function () {
return knex.schema
.withSchema('foo')
.createTable('bar', (table) => {
table.timestamps();
})
.then(() =>
expect(
expect(knex, 'to have table', 'foo.foo'),
'to be rejected with',
/to have table 'foo.foo'/,
),
);
});
it('rejects if the schema does not exist', function () {
return expect(
expect(knex, 'to have table', 'foo.foo'),
'to be rejected with',
/to have table 'foo.foo'/,
);
});
});
});
describe('<knex> not to have table <string>', function () {
it('fulfils if the table does not exist', function () {
return expect(
expect(knex, 'not to have table', 'foo'),
'to be fulfilled',
);
});
it('rejects if the table exists', function () {
return knex.schema
.createTable('foo', (table) => {
table.timestamps();
})
.then(() =>
expect(
expect(knex, 'not to have table', 'foo'),
'to be rejected with',
/not to have table 'foo'/,
),
);
});
describe('with the schema-name included (dot-separated)', function () {
beforeEach(function () {
return knex.raw(`
CREATE SCHEMA foo;
`);
});
afterEach(function () {
return knex.raw(`
DROP SCHEMA IF EXISTS foo CASCADE;
`);
});
it('fulfils if the schema and table do not exist', function () {
return knex
.raw(
`
DROP SCHEMA IF EXISTS foo CASCADE;
`,
)
.then(() =>
expect(
expect(knex, 'not to have table', 'foo.foo'),
'to be fulfilled',
),
);
});
it('fulfils if the schema exists but the table does not', function () {
return knex.schema
.withSchema('foo')
.createTable('bar', (table) => {
table.timestamps();
})
.then(() =>
expect(
expect(knex, 'not to have table', 'foo.foo'),
'to be fulfilled',
),
);
});
it('rejects if the schema and table do exist', function () {
return knex.schema
.withSchema('foo')
.createTable('foo', (table) => {
table.timestamps();
})
.then(() =>
expect(
expect(knex, 'not to have table', 'foo.foo'),
'to be rejected with',
/not to have table 'foo.foo'/,
),
);
});
});
});
describe('<knex> with schema <string> <assertion?>', () => {
it('populates the query with the schema provided', function () {
return expect(
knex,
'with schema',
'foo',
'with table',
'bar',
'when passed as parameter to',
(query) => query.toQuery(),
'to be',
'select * from "foo"."bar"',
);
});
it('resolves with the query builder if no assertion is provided', function () {
return expect(
expect(knex, 'with schema', 'foo'),
'to be rejected with error satisfying',
// unexpected auto-runs the query since it's a thenable
{
message: 'select * - SELECT * with no tables specified is not valid',
},
);
});
it('bubbles up errors to the delegate assertion', function () {
return expect(
() => expect(knex, 'with schema', 'foo', 'to equal', 'foo'),
'to error with',
dontIndent`
expected 'select *' to equal 'foo'
`,
);
});
});
describe('<knex> to have column <object>', function () {
it('fulfils if the column exists', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(knex, 'to have column', { foo: 'bar' }),
'to be fulfilled',
),
);
});
it('rejects if the column does not exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(knex, 'to have column', { foo: 'baz' }),
'to be rejected with',
/to have column { foo: 'baz' }/,
),
);
});
it('rejects if the table itself does not exist', function () {
return expect(
expect(knex, 'to have column', { foo: 'bar' }),
'to be rejected with',
/to have column { foo: 'bar' }/,
);
});
it('throws if the object has more than one key', function () {
return expect(
() => expect(knex, 'to have column', { foo: 'bar', bar: 'baz' }),
'to error with',
/Provide a single column in the form: { tableName: columnName }/,
);
});
describe('with schema', () => {
it('fulfils if the column exists', function () {
return knex.schema
.withSchema('other')
.createTable('other_foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(knex, 'to have column', { 'other.other_foo': 'bar' }),
'to be fulfilled',
),
);
});
it('rejects if the coumn does not exist', function () {
return expect(
expect(knex, 'to have column', { 'test.foo': 'baz' }),
'to be rejected with',
/to have column { 'test.foo': 'baz' }/,
);
});
it('rejects if the table does not exist', function () {
return expect(
expect(knex, 'to have column', { 'other.lame': 'baz' }),
'to be rejected with',
/to have column { 'other.lame': 'baz' }/,
);
});
it('rejects if the schema does not exist', function () {
return expect(
expect(knex, 'to have column', { 'foo.bar': 'baz' }),
'to be rejected with',
/to have column { 'foo.bar': 'baz' }/,
);
});
});
});
describe('<knex> not to have column <object>', function () {
it('fulfils if the column does not exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(knex, 'not to have column', { foo: 'baz' }),
'to be fulfilled',
),
);
});
it('rejects if the column exists', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(knex, 'not to have column', { foo: 'bar' }),
'to be rejected with',
/not to have column { foo: 'bar' }/,
),
);
});
it('fulfils if the table itself does not exist', function () {
return expect(
expect(knex, 'not to have column', { foo: 'bar' }),
'to be fulfilled',
);
});
it('throws if the object has more than one key', function () {
return expect(
() => expect(knex, 'not to have column', { foo: 'bar', bar: 'baz' }),
'to error with',
/Provide a single column in the form: { tableName: columnName }/,
);
});
describe('with schema', () => {
it('fulfils if the column does not exist', function () {
return expect(
expect(knex, 'not to have column', { 'other.other_foo': 'bar' }),
'to be fulfilled',
);
});
it('fulfils if the table does not exist', function () {
return expect(
expect(knex, 'not to have column', { 'lame.lame': 'baz' }),
'to be fulfilled',
);
});
it('fulfils if the schema does not exist', function () {
return expect(
expect(knex, 'not to have column', { 'bar.foo': 'baz' }),
'to be fulfilled',
);
});
it('rejects if the coumn does exist', function () {
return knex.schema
.withSchema('other')
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(knex, 'not to have column', { 'other.foo': 'bar' }),
'to be rejected with',
/not to have column { 'other.foo': 'bar' }/,
),
);
});
});
});
describe('<knex> to have columns <object>', function () {
it('fulfils if all the columns exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
table.string('baz');
})
.then(() =>
expect(
expect(knex, 'to have columns', { foo: ['bar', 'baz'] }),
'to be fulfilled',
),
);
});
it('rejects if any of the columns does not exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(knex, 'to have columns', { foo: ['bar', 'baz'] }),
'to be rejected with error satisfying',
/expected knex to have column { foo: 'baz' }/,
),
);
});
it('rejects if all columns do not exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(knex, 'to have columns', { foo: ['baz', 'quux'] }),
'to be rejected with error satisfying',
/expected knex to have column { foo: '(baz|quux)' }/,
),
);
});
it('rejects if the table itself does not exist', function () {
return expect(
expect(knex, 'to have columns', { foo: ['baz', 'quux'] }),
'to be rejected with',
/expected knex to have column { foo: '(baz|quux)' }/,
);
});
it('fulfils if all the columns in all the tables exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
table.string('baz');
})
.then(() =>
knex.schema.createTable('bar', (table) => {
table.string('baz');
}),
)
.then(() =>
expect(
expect(knex, 'to have columns', {
foo: ['bar', 'baz'],
bar: 'baz',
}),
'to be fulfilled',
),
);
});
it('rejects if any of the columns in any of the tables does not exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex.schema.createTable('bar', (table) => {
table.string('baz');
}),
)
.then(() =>
expect(
expect(knex, 'to have columns', {
foo: ['bar', 'baz'],
bar: 'baz',
}),
'to be rejected with',
/expected knex to have column { (foo|bar): '(bar|baz)' }/,
),
);
});
it('rejects if all columns in all of the tables do not exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex.schema.createTable('bar', (table) => {
table.string('baz');
}),
)
.then(() =>
expect(
expect(knex, 'to have columns', { foo: 'quux', bar: 'quux' }),
'to be rejected with',
/expected knex to have column { (foo|bar): 'quux' }/,
),
);
});
it('rejects if one of the tables does not exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(knex, 'to have columns', { foo: 'bar', bar: 'quux' }),
'to be rejected with',
/expected knex to have column { bar: 'quux' }/,
),
);
});
it('rejects if the tables themselves do not exist', function () {
return expect(
expect(knex, 'to have columns', { foo: 'bar', bar: 'quux' }),
'to be rejected with',
/expected knex to have column { (foo|bar): '(bar|quux)' }/,
);
});
});
describe('<knex> not to have columns <object>', function () {
it('fulfils if all the columns do not exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
table.string('baz');
})
.then(() =>
expect(
expect(knex, 'not to have columns', { foo: ['quux1', 'quux2'] }),
'to be fulfilled',
),
);
});
it('rejects if any of the columns exists', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(knex, 'not to have columns', { foo: ['bar', 'baz'] }),
'to be rejected with',
/expected knex not to have column { foo: 'bar' }/,
),
);
});
it('rejects if all columns exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
table.string('baz');
})
.then(() =>
expect(
expect(knex, 'not to have columns', { foo: ['bar', 'baz'] }),
'to be rejected with',
/expected knex not to have column { foo: '(bar|baz)' }/,
),
);
});
it('fulfils if the table itself does not exist', function () {
return expect(
expect(knex, 'not to have columns', { foo: ['baz', 'quux'] }),
'to be fulfilled',
);
});
it('fulfils if all the columns in all the tables do not exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex.schema.createTable('bar', (table) => {
table.string('baz');
}),
)
.then(() =>
expect(
expect(knex, 'not to have columns', {
foo: ['quux1', 'quux2'],
bar: 'quux1',
}),
'to be fulfilled',
),
);
});
it('rejects if any of the columns in any of the tables exists', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex.schema.createTable('bar', (table) => {
table.string('baz');
}),
)
.then(() =>
expect(
expect(knex, 'not to have columns', {
foo: ['baz', 'bar'],
bar: 'quux',
}),
'to be rejected with',
/expected knex not to have column { foo: 'bar' }/,
),
);
});
it('rejects if all columns in all of the tables exist', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex.schema.createTable('bar', (table) => {
table.string('baz');
}),
)
.then(() =>
expect(
expect(knex, 'not to have columns', { foo: 'bar', bar: 'baz' }),
'to be rejected with',
/expected knex not to have column { (foo|bar): '(bar|baz)' }/,
),
);
});
it('fulfils if the tables themselves do not exist', function () {
return expect(
expect(knex, 'not to have columns', { foo: 'bar', bar: 'quux' }),
'to be fulfilled',
);
});
});
describe('<knex> with table <string> <assertion?>', function () {
it('passes a knex query to the next assertion', function () {
return expect(knex, 'with table', 'foo', 'to be a', QueryBuilder);
});
it('populates the query with the table provided', function () {
return expect(
knex,
'with table',
'foo',
'when passed as parameter to',
(query) => query.toQuery(),
'to be',
'select * from "foo"',
);
});
it('resolves with the query builder if no assertion is provided', function () {
return expect(
expect(knex, 'with table', 'foo'),
'to be rejected with error satisfying',
// unexpected auto-runs the query since it's a thenable
{ message: 'select * from "foo" - relation "foo" does not exist' },
);
});
it('bubbles up errors from the delegate assertion', function () {
return expect(
() => expect(knex, 'with table', 'foo', 'to equal', 'foo'),
'to error with',
dontIndent`
expected 'select * from "foo"' to equal 'foo'
`,
);
});
});
describe('<knexQuery> to have rows satisfying <array>', function () {
it('runs query.select() and asserts the data returned against the array', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex('foo').insert([{ bar: 'foobar1' }, { bar: 'foobar2' }]),
)
.then(() =>
expect(
expect(knex('foo'), 'to have rows satisfying', [
{ bar: 'foobar1' },
{ bar: 'foobar2' },
]),
'to be fulfilled',
),
);
});
it("works when there's only one record in the table", function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() => knex('foo').insert({ bar: 'foobar1' }))
.then(() =>
expect(
expect(knex('foo'), 'to have rows satisfying', [
{ bar: 'foobar1' },
]),
'to be fulfilled',
),
);
});
it("works when there's no data in the table", function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(knex('foo'), 'to have rows satisfying', []),
'to be fulfilled',
),
);
});
it("rejects with the correct error if the data doesn't match", function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex('foo').insert([{ bar: 'foobar1' }, { bar: 'foobar2' }]),
)
.then(() =>
expect(
expect(knex('foo'), 'to have rows satisfying', [
{ bar: 'foobar1' },
{ bar: 'foobar20' },
]),
'to be rejected with',
dontIndent`
expected 'select * from "foo"'
to have rows satisfying [ { bar: 'foobar1' }, { bar: 'foobar20' } ]
[
{ bar: 'foobar1' },
{
bar: 'foobar2' // should equal 'foobar20'
//
// -foobar2
// +foobar20
}
]`,
),
);
});
it('rejects with the correct error if the table is not empty but the array is', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex('foo').insert([{ bar: 'foobar1' }, { bar: 'foobar2' }]),
)
.then(() =>
expect(
expect(knex('foo'), 'to have rows satisfying', []),
'to be rejected with',
dontIndent`
expected 'select * from "foo"' to have rows satisfying []
[
{ bar: 'foobar1' }, // should be removed
{ bar: 'foobar2' } // should be removed
]`,
),
);
});
it('displays the rejection reason for failed queries', function () {
const errorOutput = dontIndent`
expected 'select * from "foo"'
to have rows satisfying [ { id: 1, bar: 'foobar1' }, { id: 2, bar: 'foobar2' } ]
expected 'select * from "foo"'
to be fulfilled with value satisfying [ { id: 1, bar: 'foobar1' }, { id: 2, bar: 'foobar2' } ]
expected 'select * from "foo"' to be fulfilled
'select * from "foo"' unexpectedly rejected with error({
message: 'select * from "foo" - relation "foo" does not exist',
length: 102, severity: 'ERROR', code: '42P01', detail: undefined,
hint: undefined, position: '15', internalPosition: undefined,
internalQuery: undefined, where: undefined, schema: undefined,
table: undefined, dataType: undefined, constraint: undefined,
file: 'parse_relation.c', routine: 'parserOpenTable'
})
`;
const assertion = assertErrorOuput
? ['to be rejected with error satisfying', errorOutput]
: ['to be rejected'];
return expect(
expect(knex('foo'), 'to have rows satisfying', [
{ id: 1, bar: 'foobar1' },
{ id: 2, bar: 'foobar2' },
]),
...assertion,
);
});
describe('with the "exhaustively" flag', function () {
it('rejects if the row contains more columns than the expected output', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
table.string('baz');
})
.then(() =>
knex('foo').insert([
{ bar: 'bar1', baz: 'baz1' },
{ bar: 'bar2', baz: 'baz2' },
]),
)
.then(() =>
expect(
expect(knex('foo'), 'to have rows exhaustively satisfying', [
{ bar: 'bar1' },
{ bar: 'bar2' },
]),
'to be rejected with',
dontIndent`
expected 'select * from "foo"'
to have rows exhaustively satisfying [ { bar: 'bar1' }, { bar: 'bar2' } ]
[
{
bar: 'bar1',
baz: 'baz1' // should be removed
},
{
bar: 'bar2',
baz: 'baz2' // should be removed
}
]`,
),
);
});
});
describe('without the "exhaustively" flag', function () {
it("doesn't reject if the row contains more columns than the expected output", function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
table.string('baz');
})
.then(() =>
knex('foo').insert([
{ bar: 'bar1', baz: 'baz1' },
{ bar: 'bar2', baz: 'baz2' },
]),
)
.then(() =>
expect(
expect(knex('foo'), 'to have rows satisfying', [
{ bar: 'bar1' },
{ bar: 'bar2' },
]),
'to be fulfilled',
),
);
});
});
});
describe('<knexQuery> to have sorted rows satisfying <array>', function () {
it('runs the query and asserts that the array returned is sorted by `id` in ascending order', function () {
return knex.schema
.createTable('foo', (table) => {
table.increments();
table.string('bar');
})
.then(() =>
knex('foo').insert([
{ id: 2, bar: 'foobar2' },
{ id: 1, bar: 'foobar1' },
]),
)
.then(() =>
expect(
expect(knex('foo'), 'to have sorted rows satisfying', [
{ id: 1, bar: 'foobar1' },
{ id: 2, bar: 'foobar2' },
]),
'to be fulfilled',
),
);
});
it("rejects with the correct error if the order of array items doesn't match", function () {
return knex.schema
.createTable('foo', (table) => {
table.increments();
table.string('bar');
})
.then(() =>
knex('foo').insert([
{ id: 1, bar: 'foobar1' },
{ id: 2, bar: 'foobar2' },
]),
)
.then(() => {
const errorOutput = dontIndent`
expected 'select * from "foo"'
to have sorted rows satisfying [ { id: 2, bar: 'foobar2' }, { id: 1, bar: 'foobar1' } ]
expected [ { id: 1, bar: 'foobar1' }, { id: 2, bar: 'foobar2' } ] sorted by
function ascendingOrder(a, b) {
return parseInt(a.id) - parseInt(b.id);
} to satisfy [ { id: 2, bar: 'foobar2' }, { id: 1, bar: 'foobar1' } ]
[
{
id: 1, // should equal 2
bar: 'foobar1' // should equal 'foobar2'
//
// -foobar1
// +foobar2
},
{
id: 2, // should equal 1
bar: 'foobar2' // should equal 'foobar1'
//
// -foobar2
// +foobar1
}
]`;
const assertion = assertErrorOuput
? ['to be rejected with error satisfying', errorOutput]
: ['to be rejected'];
return expect(
expect(knex('foo'), 'to have sorted rows satisfying', [
{ id: 2, bar: 'foobar2' },
{ id: 1, bar: 'foobar1' },
]),
...assertion,
);
});
});
it('displays the rejection reason for failed queries', function () {
const errorOutput = dontIndent`
expected 'select * from "foo"'
to have sorted rows satisfying [ { id: 1, bar: 'foobar1' }, { id: 2, bar: 'foobar2' } ]
expected 'select * from "foo"' to have rows satisfying
expect.it('sorted by', function ascendingOrder(a, b) {
return parseInt(a.id) - parseInt(b.id);
}, 'to [exhaustively] satisfy', [ { id: 1, bar: 'foobar1' }, { id: 2, bar: 'foobar2' } ])
expected 'select * from "foo"' to be fulfilled with value satisfying
expect.it('sorted by', function ascendingOrder(a, b) {
return parseInt(a.id) - parseInt(b.id);
}, 'to [exhaustively] satisfy', [ { id: 1, bar: 'foobar1' }, { id: 2, bar: 'foobar2' } ])
expected 'select * from "foo"' to be fulfilled
'select * from "foo"' unexpectedly rejected with error({
message: 'select * from "foo" - relation "foo" does not exist',
length: 102, severity: 'ERROR', code: '42P01', detail: undefined,
hint: undefined, position: '15', internalPosition: undefined,
internalQuery: undefined, where: undefined, schema: undefined,
table: undefined, dataType: undefined, constraint: undefined,
file: 'parse_relation.c', routine: 'parserOpenTable'
})
`;
const assertion = assertErrorOuput
? ['to be rejected with error satisfying', errorOutput]
: ['to be rejected'];
return expect(
expect(knex('foo'), 'to have sorted rows satisfying', [
{ id: 1, bar: 'foobar1' },
{ id: 2, bar: 'foobar2' },
]),
...assertion,
);
});
describe('with the "exhaustively" flag', function () {
it('rejects if all rows are not exhaustively described in the expected output', function () {
return knex.schema
.createTable('foo', (table) => {
table.increments();
table.string('bar');
})
.then(() =>
knex('foo').insert([
{ id: 1, bar: 'foobar1' },
{ id: 2, bar: 'foobar2' },
]),
)
.then(() => {
const errorOutput = dontIndent`
expected 'select * from "foo"'
to have sorted rows exhaustively satisfying [ { id: 1, bar: 'foobar1' }, { id: 2 } ]
expected [ { id: 1, bar: 'foobar1' }, { id: 2, bar: 'foobar2' } ] sorted by
function ascendingOrder(a, b) {
return parseInt(a.id) - parseInt(b.id);
} to exhaustively satisfy [ { id: 1, bar: 'foobar1' }, { id: 2 } ]
[
{ id: 1, bar: 'foobar1' },
{
id: 2,
bar: 'foobar2' // should be removed
}
]`;
const assertion = assertErrorOuput
? ['to be rejected with error satisfying', errorOutput]
: ['to be rejected'];
return expect(
expect(
knex('foo'),
'to have sorted rows exhaustively satisfying',
[{ id: 1, bar: 'foobar1' }, { id: 2 }],
),
...assertion,
);
});
});
});
describe('without the "exhaustively" flag', function () {
it("doesn't reject if some row is not exhaustively described in the expected output", function () {
return knex.schema
.createTable('foo', (table) => {
table.increments();
table.string('bar');
})
.then(() =>
knex('foo').insert([
{ id: 1, bar: 'foobar1' },
{ id: 2, bar: 'foobar2' },
]),
)
.then(() =>
expect(
expect(knex('foo'), 'to have sorted rows satisfying', [
{ id: 1, bar: 'foobar1' },
{ id: 2 },
]),
'to be fulfilled',
),
);
});
});
});
describe('<Promise> to fulfilled with sorted rows satisfying <array>', function () {
it('asserts that the promise is resolved with an array of objects sorted by an `id` property in ascending order', function () {
return expect(
expect(
Promise.resolve([
{ id: 2, bar: 'foobar2' },
{ id: 1, bar: 'foobar1' },
]),
'to be fulfilled with sorted rows satisfying',
[
{ id: 1, bar: 'foobar1' },
{ id: 2, bar: 'foobar2' },
],
),
'to be fulfilled',
);
});
it("rejects with the correct error if the order of array items doesn't match", function () {
const errorOutput = dontIndent`
expected Promise
to be fulfilled with sorted rows satisfying [ { id: 2, bar: 'foobar2' }, { id: 1, bar: 'foobar1' } ]
expected [ { id: 2, bar: 'foobar2' }, { id: 1, bar: 'foobar1' } ] sorted by
function ascendingOrder(a, b) {
return parseInt(a.id) - parseInt(b.id);
} to satisfy [ { id: 2, bar: 'foobar2' }, { id: 1, bar: 'foobar1' } ]
[
{
id: 1, // should equal 2
bar: 'foobar1' // should equal 'foobar2'
//
// -foobar1
// +foobar2
},
{
id: 2, // should equal 1
bar: 'foobar2' // should equal 'foobar1'
//
// -foobar2
// +foobar1
}
]`;
const assertion = assertErrorOuput
? ['to be rejected with error satisfying', errorOutput]
: ['to be rejected'];
return expect(
expect(
Promise.resolve([
{ id: 2, bar: 'foobar2' },
{ id: 1, bar: 'foobar1' },
]),
'to be fulfilled with sorted rows satisfying',
[
{ id: 2, bar: 'foobar2' },
{ id: 1, bar: 'foobar1' },
],
),
...assertion,
);
});
it('displays the rejection reason for rejected promises', function () {
const errorOutput = dontIndent`
expected Promise to be fulfilled with sorted rows satisfying [ 'foo', 'bar' ]
expected Promise to be fulfilled with value satisfying
expect.it('sorted by', function ascendingOrder(a, b) {
return parseInt(a.id) - parseInt(b.id);
}, 'to [exhaustively] satisfy', [ 'foo', 'bar' ])
expected Promise to be fulfilled
Promise unexpectedly rejected with Error('foo')
`;
const assertion = assertErrorOuput
? ['to be rejected with error satisfying', errorOutput]
: ['to be rejected'];
return expect(
expect(
Promise.reject(new Error('foo')),
'to be fulfilled with sorted rows satisfying',
['foo', 'bar'],
),
...assertion,
);
});
describe('with the "exhaustively" flag', function () {
it('rejects if all rows are not exhaustively described in the expected output', function () {
const errorOutput = dontIndent`
expected Promise
to be fulfilled with sorted rows exhaustively satisfying [ { id: 1, bar: 'foobar1' }, { id: 2 } ]
expected [ { id: 2, bar: 'foobar2' }, { id: 1, bar: 'foobar1' } ] sorted by
function ascendingOrder(a, b) {
return parseInt(a.id) - parseInt(b.id);
} to exhaustively satisfy [ { id: 1, bar: 'foobar1' }, { id: 2 } ]
[
{ id: 1, bar: 'foobar1' },
{
id: 2,
bar: 'foobar2' // should be removed
}
]`;
const assertion = assertErrorOuput
? ['to be rejected with error satisfying', errorOutput]
: ['to be rejected'];
return expect(
expect(
Promise.resolve([
{ id: 2, bar: 'foobar2' },
{ id: 1, bar: 'foobar1' },
]),
'to be fulfilled with sorted rows exhaustively satisfying',
[{ id: 1, bar: 'foobar1' }, { id: 2 }],
),
...assertion,
);
});
});
describe('without the "exhaustively" flag', function () {
it("doesn't reject if some row is not exhaustively described in the expected output", function () {
return expect(
expect(
Promise.resolve([
{ id: 2, bar: 'foobar2' },
{ id: 1, bar: 'foobar1' },
]),
'to be fulfilled with sorted rows satisfying',
[{ id: 1, bar: 'foobar1' }, { id: 2 }],
),
'to be fulfilled',
);
});
});
});
describe('<knexQuery> to be empty', function () {
it('runs the query and asserts that the returned array is empty', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(expect(knex('foo'), 'to be empty'), 'to be fulfilled'),
);
});
it('rejects with the correct error if the table has rows', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex('foo').insert([{ bar: 'foobar1' }, { bar: 'foobar2' }]),
)
.then(() =>
expect(
expect(knex('foo'), 'to be empty'),
'to be rejected with',
dontIndent`
expected 'select * from "foo"' to be empty
expected [ { bar: 'foobar1' }, { bar: 'foobar2' } ] to be empty`,
),
);
});
it('displays the rejection reason for failed queries', function () {
const errorOutput = dontIndent`
expected 'select * from "foo"' to be empty
expected 'select * from "foo"'
to have rows satisfying expect.it('[not] to be empty')
expected 'select * from "foo"'
to be fulfilled with value satisfying expect.it('[not] to be empty')
expected 'select * from "foo"' to be fulfilled
'select * from "foo"' unexpectedly rejected with error({
message: 'select * from "foo" - relation "foo" does not exist',
length: 102, severity: 'ERROR', code: '42P01', detail: undefined,
hint: undefined, position: '15', internalPosition: undefined,
internalQuery: undefined, where: undefined, schema: undefined,
table: undefined, dataType: undefined, constraint: undefined,
file: 'parse_relation.c', routine: 'parserOpenTable'
})
`;
const assertion = assertErrorOuput
? ['to be rejected with error satisfying', errorOutput]
: ['to be rejected'];
return expect(expect(knex('foo'), 'to be empty'), ...assertion);
});
describe("with the 'not' flag", function () {
it('runs the query and asserts that the returned array is not empty', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex('foo').insert([{ bar: 'foobar1' }, { bar: 'foobar2' }]),
)
.then(() =>
expect(expect(knex('foo'), 'not to be empty'), 'to be fulfilled'),
);
});
it('rejects with the correct error if the table is empty', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(knex('foo'), 'not to be empty'),
'to be rejected with',
dontIndent`
expected 'select * from "foo"' not to be empty
expected [] not to be empty`,
),
);
});
});
});
describe('<knexQuery> to have rows satisfying <expect.it>', function () {
it('runs query.select() and asserts the data returned against the assertion', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex('foo').insert([{ bar: 'foobar1' }, { bar: 'foobar2' }]),
)
.then(() =>
expect(
expect(
knex('foo'),
'to have rows satisfying',
expect.it('to equal', [{ bar: 'foobar1' }, { bar: 'foobar2' }]),
),
'to be fulfilled',
),
);
});
it("works when there's only one record in the table", function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() => knex('foo').insert({ bar: 'foobar1' }))
.then(() =>
expect(
expect(
knex('foo'),
'to have rows satisfying',
expect.it('to equal', [{ bar: 'foobar1' }]),
),
'to be fulfilled',
),
);
});
it("works when there's no data in the table", function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
expect(
expect(
knex('foo'),
'to have rows satisfying',
expect.it('to equal', []),
),
'to be fulfilled',
),
);
});
it("rejects with the correct error if the data doesn't match", function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex('foo').insert([{ bar: 'foobar1' }, { bar: 'foobar2' }]),
)
.then(() =>
expect(
expect(
knex('foo'),
'to have rows satisfying',
expect.it('to equal', [{ bar: 'foobar1' }, { bar: 'foobar20' }]),
),
'to be rejected with',
dontIndent`
expected 'select * from "foo"'
to have rows satisfying expect.it('to equal', [ { bar: 'foobar1' }, { bar: 'foobar20' } ])
expected [ { bar: 'foobar1' }, { bar: 'foobar2' } ]
to equal [ { bar: 'foobar1' }, { bar: 'foobar20' } ]
[
{ bar: 'foobar1' },
{
bar: 'foobar2' // should equal 'foobar20'
//
// -foobar2
// +foobar20
}
]`,
),
);
});
it('rejects with the correct error if the table is not empty but the array is', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex('foo').insert([{ bar: 'foobar1' }, { bar: 'foobar2' }]),
)
.then(() =>
expect(
expect(
knex('foo'),
'to have rows satisfying',
expect.it('to equal', []),
),
'to be rejected with',
dontIndent`
expected 'select * from "foo"' to have rows satisfying expect.it('to equal', [])
expected [ { bar: 'foobar1' }, { bar: 'foobar2' } ] to equal []
[
{ bar: 'foobar1' }, // should be removed
{ bar: 'foobar2' } // should be removed
]`,
),
);
});
});
describe('<knexQuery> to have a row satisfying <object>', function () {
it('runs query.select() and asserts the data returned against the object', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() => knex('foo').insert({ bar: 'foobar1' }))
.then(() =>
expect(
expect(knex('foo'), 'to have a row satisfying', { bar: 'foobar1' }),
'to be fulfilled',
),
);
});
it('asserts that at least one record in the table satisfies the object', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex('foo').insert([{ bar: 'foobar1' }, { bar: 'foobar2' }]),
)
.then(() =>
expect(
expect(knex('foo'), 'to have a row satisfying', { bar: 'foobar2' }),
'to be fulfilled',
),
);
});
it('does not assert against an empty object', function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex('foo').insert([{ bar: 'foobar1' }, { bar: 'foobar2' }]),
)
.then(() =>
expect(
() => expect(knex('foo'), 'to have a row satisfying', {}),
'to be rejected with',
dontIndent`
expected 'select * from "foo"' to have a row satisfying {}
cannot assert that a row has no columns or fields`,
),
);
});
it("rejects with the correct error if the data doesn't match", function () {
return knex.schema
.createTable('foo', (table) => {
table.string('bar');
})
.then(() =>
knex('foo').insert([{ bar: 'foobar1' }, { bar: 'foobar2' }]),
)
.then(() =>
expect(
expect(knex('foo'), 'to have a row satisfying', {
bar: 'foobar20',
}),
'to be rejected with',
do