Tiny Fixtures
`tiny-fixtures` is a lightweight JavaScript/TypeScript library designed to simplify the creation and management of database fixtures specifically for testing environments. Currently at version 0.3.0, it is built to integrate with PostgreSQL databases, relying on `node-postgres` connection pools for its operations. The package's primary export is the `tinyFixtures` function, which, when initialized with a database pool, returns a `createFixtures` function. This function facilitates the generation of `setup` and `teardown` routines for specified tables and data arrays. A key differentiator is its robust handling of foreign key relationships, allowing testers to reference IDs of newly inserted parent records when creating child fixtures. The library aims to provide clean, isolated test data for each test run while importantly preserving existing data in development databases, thereby enhancing the local development workflow. It maintains a 'tiny' footprint by emphasizing explicit control over fixture ordering, particularly for relational data.
Common errors
-
TypeError: tinyFixtures is not a function
cause Attempting to use `require()` for an ESM module or incorrect named import syntax in a CommonJS context.fixEnsure your project is configured for ESM (e.g., `"type": "module"` in `package.json`) and use `import { tinyFixtures } from 'tiny-fixtures';`. -
TypeError: Cannot read properties of undefined (reading 'getRefByKey')
cause This error typically occurs when `getRefByKey` is called on an object that is not a valid fixture reference or if the third return value from `createFixtures` was not correctly destructured or used out of scope.fixVerify that you are correctly destructuring the third array element, e.g., `const [setup, teardown, users] = createFixtures('users', [...]);`, and then using `users[index].getRefByKey('id')` to get the reference. -
Error: connect ECONNREFUSED
cause The `node-postgres` connection pool provided to `tinyFixtures` is unable to establish a connection to the PostgreSQL database, often due to incorrect connection parameters, the database server not running, or firewall issues.fixDouble-check your `pg.Pool` configuration (host, port, user, password, database) and ensure the PostgreSQL database server is running and accessible from where your tests are executed.
Warnings
- gotcha Tiny Fixtures is currently only tested and compatible with PostgreSQL databases. It specifically expects a `node-postgres` connection pool for database interactions. Using it with other SQL dialects (e.g., MySQL, SQLite) or alternative ORMs/database drivers may lead to unexpected behavior or errors.
- gotcha When defining fixtures across multiple tables with foreign key relationships, the order in which `setup` and `teardown` functions are called is crucial for maintaining referential integrity. Parent table setups must always precede child table setups, and conversely, child table teardowns must precede parent table teardowns.
Install
-
npm install tiny-fixtures -
yarn add tiny-fixtures -
pnpm add tiny-fixtures
Imports
- tinyFixtures
const { tinyFixtures } = require('tiny-fixtures');import { tinyFixtures } from 'tiny-fixtures'; - FixtureManager
import type { FixtureManager } from 'tiny-fixtures'; - Ref
import type { Ref } from 'tiny-fixtures';
Quickstart
import { tinyFixtures } from 'tiny-fixtures';
import { Pool } from 'pg'; // Assuming 'pg' is installed and configured
import { expect } from 'chai'; // Assuming a testing framework like Mocha/Chai
// Dummy connection pool (replace with your actual database pool)
const pool = new Pool({
user: process.env.DB_USER ?? 'testuser',
host: process.env.DB_HOST ?? 'localhost',
database: process.env.DB_NAME ?? 'testdb',
password: process.env.DB_PASSWORD ?? 'testpassword',
port: parseInt(process.env.DB_PORT ?? '5432', 10),
});
// Dummy function to fetch users (replace with actual DB query)
const getUsers = async () => {
const client = await pool.connect();
try {
const res = await client.query('SELECT id, email, username FROM users;');
return res.rows;
} finally {
client.release();
}
};
const getUserMessages = async (userId: number) => {
const client = await pool.connect();
try {
const res = await client.query('SELECT message FROM user_messages WHERE user_id = $1;', [userId]);
return res.rows;
} finally {
client.release();
}
}
const { createFixtures } = tinyFixtures(pool);
describe('my test cases with foreign keys', () => {
const [setupUserFixtures, teardownUserFixtures, users] = createFixtures('users', [
{
email: 'foo@bar.co',
username: 'tinyAnt'
}, {
email: 'bar@foo.co',
username: 'antTiny',
}
]);
const [setupUserMessageFixtures, teardownUserMessageFixtures] = createFixtures(
'user_messages',
[{
user_id: users[0].getRefByKey('id'),
message: 'Foobar did the bar foo good',
},
{
user_id: users[0].getRefByKey('id'),
message: 'I am a meat popsicle',
}]
);
beforeEach(async () => {
await setupUserFixtures();
await setupUserMessageFixtures();
});
afterEach(async () => {
await teardownUserMessageFixtures();
await teardownUserFixtures();
});
it('should have a user with two messages, and one with none', async () => {
const dbUsers = await getUsers();
expect(dbUsers).to.have.length(2);
const messagesForUser1 = await getUserMessages(dbUsers[0].id);
const messagesForUser2 = await getUserMessages(dbUsers[1].id);
expect(messagesForUser1).to.have.length(2);
expect(messagesForUser2).to.have.length(0);
});
});