fix(shop): render a bag offer's capacity line once, not twice
`resolveTarget` gave a bag target the same string for `description` and `effectSummary`, and the shop row renders both, so the slice's two flagship offers showed "Capacity: 5 Raider Trophies" on consecutive lines. Spec §5's worked example shows it once. A bag definition carries no flavour text of its own, so the description is now empty and the row omits the span entirely rather than emitting an empty one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -307,9 +307,11 @@ export class ShopService {
|
||||
definitionId: offer.lootBagDefinition.id,
|
||||
key: offer.lootBagDefinition.key,
|
||||
name: offer.lootBagDefinition.name,
|
||||
// A bag definition carries no flavour text of its own; the capacity
|
||||
// line is the honest description of what it is.
|
||||
description: describeBagEffect(offer.lootBagDefinition),
|
||||
// A bag definition carries no flavour text of its own. The capacity
|
||||
// line is the whole of what there is to say about it, and it is already
|
||||
// carried by `effectSummary`; repeating it here would render it twice
|
||||
// (slice §5 shows the line once).
|
||||
description: '',
|
||||
iconPath: offer.lootBagDefinition.iconPath,
|
||||
effectSummary: describeBagEffect(offer.lootBagDefinition),
|
||||
};
|
||||
|
||||
@@ -234,9 +234,11 @@
|
||||
/>
|
||||
<div class="shop-row__naming">
|
||||
<span class="shop-row__name">{{ offer.itemName }}</span>
|
||||
<span class="shop-row__description">{{
|
||||
offer.itemDescription
|
||||
}}</span>
|
||||
@if (offer.itemDescription) {
|
||||
<span class="shop-row__description">{{
|
||||
offer.itemDescription
|
||||
}}</span>
|
||||
}
|
||||
@if (offer.effectSummary) {
|
||||
<span class="shop-row__effect" data-effect>{{
|
||||
offer.effectSummary
|
||||
|
||||
@@ -232,6 +232,11 @@ async function renderMerchantWithShop(
|
||||
return { fixture, element, store };
|
||||
}
|
||||
|
||||
/** How many times `needle` shows up in `haystack` -- `toContain` cannot say. */
|
||||
function countOccurrences(haystack: string, needle: string): number {
|
||||
return haystack.split(needle).length - 1;
|
||||
}
|
||||
|
||||
describe('MerchantPageComponent', () => {
|
||||
afterEach(() => TestBed.resetTestingModule());
|
||||
|
||||
@@ -383,13 +388,15 @@ describe('MerchantPageComponent', () => {
|
||||
|
||||
it('shows the requirement and the current value on a locked offer', async () => {
|
||||
// A visible lock with a number attached is a goal; a hidden offer is not
|
||||
// (slice §5).
|
||||
// (slice §5). Shaped like the real Trophy Pouch offer: a bag definition
|
||||
// carries no flavour text, so the API sends an empty description and the
|
||||
// capacity line arrives once, as the effect.
|
||||
const { fixture } = await renderMerchantWithShop({
|
||||
offers: [
|
||||
{
|
||||
itemKey: 'basic-trophy-pouch',
|
||||
itemName: 'Basic Trophy Pouch',
|
||||
itemDescription: 'Capacity: 5 Raider Trophies',
|
||||
itemDescription: '',
|
||||
iconPath: '/images/items/basic-trophy-pouch.png',
|
||||
currencyType: 'SILVER',
|
||||
price: 40,
|
||||
@@ -414,6 +421,14 @@ describe('MerchantPageComponent', () => {
|
||||
);
|
||||
expect(row.textContent).toContain('Requires Border Watch Reputation 25');
|
||||
expect(row.textContent).toContain('Current: 14');
|
||||
// Once, not twice: slice §5's worked example shows the capacity line a
|
||||
// single time.
|
||||
expect(
|
||||
countOccurrences(row.textContent, 'Capacity: 5 Raider Trophies'),
|
||||
).toBe(1);
|
||||
// An empty description renders nothing at all, rather than an empty span
|
||||
// that would let a duplicated capacity line back in unnoticed.
|
||||
expect(row.querySelector('.shop-row__description')).toBeNull();
|
||||
expect(row.querySelector('button').disabled).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user