schema/list-view-personal-default.integration.test.mjs
Rama main · réplica de lectura del repositorio original.
/**
* An owner has at most one live personal default list view per record type.
*
* The unique partial index admits defaults for other owners, organization
* views, inactive views and non-default personal views, and refuses a second
* live personal default for the same organization, owner and record type.
*/
import assert from "node:assert/strict";
import { randomUUID } from "node:crypto";
import test from "node:test";
import pg from "pg";
const DB = Boolean(process.env.OPENBOOKS_DB_URL);
function adminConnectionString() {
const explicit = process.env.OPENBOOKS_TEST_ADMIN_DB_URL;
if (explicit) return explicit.trim();
const runtime = process.env.OPENBOOKS_DB_URL;
if (!runtime) return "";
const url = new URL(runtime);
url.username = "openbooks";
url.password = process.env.PGPASSWORD || "openbooks";
return url.href;
}
function postgresCode(error) {
let current = error;
for (let depth = 0; depth < 5 && current && typeof current === "object"; depth += 1) {
if (current.code) return current.code;
current = current.cause;
}
return undefined;
}
async function seedTenant(client) {
const orgId = randomUUID();
const ownerId = randomUUID();
const otherOwnerId = randomUUID();
await client.query(
`insert into orgs (id, name, base_currency, country, settings, env_kind)
values ($1, 'List view tenant', 'CAD', 'CA', '{}'::jsonb, 'production')`,
[orgId],
);
for (const [id, name] of [
[ownerId, "Owner"],
[otherOwnerId, "Other owner"],
]) {
await client.query(
`insert into users (id, org_id, email, name, password_hash, is_active)
values ($1, $2, $3, $4, 'x', true)`,
[id, orgId, `${id.slice(0, 8)}@list-view.test`, name],
);
}
return { orgId, ownerId, otherOwnerId };
}
async function insertListView(client, { orgId, name, scope, ownerId, isDefault, isActive }) {
const id = randomUUID();
await client.query(
`insert into list_views (
id, org_id, record_type, name, scope, owner_id, is_default, is_active, config
) values ($1, $2, 'invoice', $3, $4, $5, $6, $7, '{}'::jsonb)`,
[id, orgId, name, scope, ownerId, isDefault, isActive],
);
return id;
}
test(
"a second live personal list-view default for the same owner and record type is refused",
{ skip: !DB },
async () => {
const client = new pg.Client({ connectionString: adminConnectionString() });
await client.connect();
try {
await client.query("begin");
await client.query("select set_config('app.bypass_rls', 'on', true)");
const index = await client.query(
`select pg_get_indexdef(oid) as definition from pg_class
where relname = 'list_views_one_live_personal_default' and relkind = 'i'`,
);
assert.equal(index.rows.length, 1, "list_views_one_live_personal_default must exist");
assert.match(
index.rows[0].definition,
/^CREATE UNIQUE INDEX list_views_one_live_personal_default ON (?:public\.)?list_views USING btree \(org_id, owner_id, record_type\) WHERE \(\(scope = 'user'::text\) AND is_default AND is_active\)$/,
);
const tenant = await seedTenant(client);
const firstId = await insertListView(client, {
orgId: tenant.orgId,
name: "My invoices",
scope: "user",
ownerId: tenant.ownerId,
isDefault: true,
isActive: true,
});
for (const admitted of [
{
name: "Other owner invoices",
scope: "user",
ownerId: tenant.otherOwnerId,
isDefault: true,
isActive: true,
},
{ name: "Shared invoices", scope: "org", ownerId: null, isDefault: true, isActive: true },
{
name: "Inactive personal",
scope: "user",
ownerId: tenant.ownerId,
isDefault: true,
isActive: false,
},
{
name: "Non-default personal",
scope: "user",
ownerId: tenant.ownerId,
isDefault: false,
isActive: true,
},
]) {
await insertListView(client, { orgId: tenant.orgId, ...admitted });
}
await client.query("savepoint before_second_live_default");
await assert.rejects(
insertListView(client, {
orgId: tenant.orgId,
name: "Second default",
scope: "user",
ownerId: tenant.ownerId,
isDefault: true,
isActive: true,
}),
(error) => {
assert.equal(postgresCode(error), "23505");
return true;
},
);
await client.query("rollback to savepoint before_second_live_default");
const stored = await client.query(
`select id from list_views
where org_id = $1 and owner_id = $2 and record_type = 'invoice'
and scope = 'user' and is_default and is_active`,
[tenant.orgId, tenant.ownerId],
);
assert.deepEqual(
stored.rows.map((row) => row.id),
[firstId],
);
} finally {
await client.query("rollback").catch(() => undefined);
await client.end();
}
},
);