test(shops): add entity-schema cross-check for sellable loot bags

The migration spec only asserted SQL substrings against a mocked
QueryRunner and had no getMetadataArgsStorage() check that ShopOffer's
column options and partial unique indexes actually match the new
schema. Since ts-jest does not type-check in this package
(isolatedModules: true), this is the only automated guard against
entity/migration drift -- matches the house convention in
npc-system.migration.spec.ts and loot-bags.migration.spec.ts.
This commit is contained in:
Bastian Wagner
2026-08-22 17:59:37 +02:00
parent 3b28450fb1
commit c295bae63a

View File

@@ -1,6 +1,7 @@
import 'reflect-metadata';
import { QueryRunner } from 'typeorm';
import { getMetadataArgsStorage, QueryRunner } from 'typeorm';
import { SellableLootBags1796000000000 } from './1796000000000-SellableLootBags';
import { ShopOffer } from '../../shops/entities/shop-offer.entity';
async function runUp(): Promise<string[]> {
const query = jest.fn().mockResolvedValue(undefined);
@@ -73,3 +74,47 @@ describe('SellableLootBags1796000000000', () => {
);
});
});
describe('slice 0.8.5 entity schema', () => {
function column(target: unknown, propertyName: string) {
return getMetadataArgsStorage().columns.find(
(candidate) =>
candidate.target === target && candidate.propertyName === propertyName,
);
}
it('lets the item target sit empty when the offer sells a bag instead', () => {
expect(column(ShopOffer, 'itemDefinitionId')?.options.nullable).toBe(true);
});
it('gives a bag offer its own nullable uuid target', () => {
const lootBagDefinitionId = column(ShopOffer, 'lootBagDefinitionId');
expect(lootBagDefinitionId?.options.type).toBe('uuid');
expect(lootBagDefinitionId?.options.nullable).toBe(true);
});
it('requires every offer to carry its bypass conditions, empty or not', () => {
const bypassConditions = column(ShopOffer, 'bypassConditions');
expect(bypassConditions?.options.type).toBe('jsonb');
expect(bypassConditions?.options.nullable).toBeFalsy();
});
it('declares both partial unique indexes with their WHERE clauses', () => {
const indices = getMetadataArgsStorage().indices.filter(
(candidate) => candidate.target === ShopOffer,
);
const itemIndex = indices.find(
(candidate) => candidate.name === 'IDX_shop_offers_shop_item',
);
const bagIndex = indices.find(
(candidate) => candidate.name === 'IDX_shop_offers_shop_bag',
);
expect(itemIndex?.unique).toBe(true);
expect(itemIndex?.where).toBe('"item_definition_id" IS NOT NULL');
expect(bagIndex?.unique).toBe(true);
expect(bagIndex?.where).toBe('"loot_bag_definition_id" IS NOT NULL');
});
});