Testing
The package ships its own Jest suite and is designed to be straightforward to test inside consuming applications. This page walks through patterns for keeping your tests isolated and deterministic.
Built-In Suite
cd packages/netpress-permissions
npm test
Under the hood this runs:
NODE_OPTIONS='--experimental-vm-modules --import tsx' \
jest --config ./jest.config.js --runInBand --detectOpenHandles
The suite covers:
NetpressPermissionsTest.js— role/permission graph and morph lookupsAuthGuardTest.js— Express middleware (401 / 403 behaviour, policy + permission checks)PublisherTest.js— vendor:publish flow and provider hydration
Isolating State Between Tests
Authorization carries a lot of shared global state. Reset it in every test teardown:
import {
resetConnectionRegistry,
resetMorphMap,
resetAuthGuards,
resetPolicies,
container,
} from '@admicaa/netpress';
import {
resetPermissionsConfig,
} from '@admicaa/netpress-permissions';
afterEach(() => {
resetPermissionsConfig();
resetAuthGuards();
resetPolicies();
resetMorphMap();
resetConnectionRegistry();
container.reset();
});
A Minimal Integration Test
import knexLib from 'knex';
import { BaseModel, bindActiveConnection } from '@admicaa/netpress';
import {
Authorizable,
Permission,
Role,
createPermissionTables,
} from '@admicaa/netpress-permissions';
class User extends Authorizable(BaseModel) {
static table = 'users';
}
let knex;
beforeEach(async () => {
knex = knexLib({
client: 'better-sqlite3',
connection: { filename: ':memory:' },
useNullAsDefault: true,
});
await knex.schema.createTable('users', (table) => {
table.increments('id').primary();
table.string('name').notNullable();
});
await createPermissionTables(knex);
bindActiveConnection({ name: 'sqlite', driver: 'sqlite', client: knex, reset: true });
BaseModel.registerMorphMap({ user: User });
});
afterEach(async () => {
await knex.destroy();
});
it('grants a permission via a role', async () => {
const editor = await Role.findOrCreate('editor');
const publish = await Permission.findOrCreate('posts.publish');
await editor.givePermissionTo(publish);
const user = await User.create({ name: 'Amina' });
await user.assignRole(editor);
expect(await user.can('posts.publish')).toBe(true);
});
Testing Middleware
Invoke AuthGuard.*() directly without a running Express server:
function invoke(middleware, req = {}) {
return new Promise((resolve) => middleware(req, {}, resolve));
}
it('rejects guests', async () => {
const err = await invoke(AuthGuard.authenticated(), {});
expect(err).toMatchObject({ status: 401 });
});
The next callback receives the thrown exception, which lets Jest assert status codes without running the whole HTTP stack.
Mocking The User
For most tests it is simpler to use Authorizable(BaseModel) against an in-memory database than to mock the user. When you truly need a mock:
const fakeUser = {
id: 1,
hasPermissionTo: async () => true,
hasAnyRole: async () => true,
hasAllRoles: async () => true,
getRoleNames: async () => ['admin'],
};
The permission traits and AuthGuard only call the methods above, so a plain object works fine for unit tests that don't care about the persistence layer.