TenancyJS
Guides

Testing isolation

Prove - don't assume - that tenants can't see each other's data.

Isolation you haven't tested is isolation you don't have. TenancyJS is built around a single test shape, and it's the one you should write for your own models too: the two-tenant adversarial test.

The two-tenant adversarial test

Create two tenants with a colliding id on a row, then assert that each tenant sees only its own - and that the test would fail if isolation leaked.

// Given tenant A and tenant B each have an Order with id "same-id":
await manager.runWithTenant({ id: "a" }, () =>
  db.order.create({ data: { id: "same-id", total: 10 } }),
);
await manager.runWithTenant({ id: "b" }, () =>
  db.order.create({ data: { id: "same-id", total: 99 } }),
);

// A must see only A's row:
const seen = await manager.runWithTenant({ id: "a" }, () =>
  db.order.findMany(),
);
expect(seen).toEqual([{ id: "same-id", total: 10 }]);

This is exactly the bar TenancyJS holds itself to: a capability is only marked supported in the capability matrix after a test like this passes on a real database.

Also test that it fails closed

Assert that using an adapter with no active scope throws - so a missing context can never silently return unscoped data:

await expect(db.order.findMany()).rejects.toThrow(TenantContextError);

Conformance helpers

tenancyjs-testing provides runner-neutral fixtures and conformance contracts you can run against your own setup, so you're testing the same invariants the toolkit tests internally.

For Mongoose, remember isolation is facade-only - a test that reaches for the native model or collection is testing the wrong thing. See the Mongoose adapter.

On this page