mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-30 19:48:32 +01:00
feat(catalog): graduated cosmetic ladder + per-session test-unlock
Step 1 — real tiered unlocks (was flat: any credit unlocked skins+iso+3D):
- entitlements DEFAULT_CATALOG + migration 025 graduate the ladder — unlock by
lifetime credit spend OR subscription tier, whichever first:
Fancy (generated-skins) 1 credit / supporter (tier 1)
Iso (iso-dungeon) 10 credits / premium (tier 2)
3D (kenney-3d-characters) 25 credits / operator (tier 3)
- Migration 025 UPDATEs the already-seeded 024 rows (idempotent).
- Tests updated to assert the ladder (1cr -> Fancy only; 10 -> +Iso; 25 -> all).
Step 2 — test the premium modes without paying:
- renderModes: ?unlock=1 (sticky via localStorage) flips RENDER_MODE_TEST_UNLOCKS
for THAT browser only, so Fancy/Iso/3D are all clickable; ?unlock=0 turns it off.
Suite 57 suites / 414 tests green.
This commit is contained in:
@@ -22,12 +22,19 @@ describe('three-way unlock — default (seed) catalog', () => {
|
||||
expect(s.tier).toBe(0);
|
||||
});
|
||||
|
||||
test('backward-compat: buying any credit unlocks the seed packs (all threshold 1)', () => {
|
||||
test('graduated ladder: 1 credit unlocks Fancy (skins) only, not Iso or 3D', () => {
|
||||
const s = snapshotForUser({ credits: 5, total_credits_purchased: 1 });
|
||||
expect(s.packs['generated-skins']).toBe(true); // threshold 1
|
||||
expect(s.packs['iso-dungeon']).toBe(false); // threshold 10
|
||||
expect(s.packs['kenney-3d-characters']).toBe(false); // threshold 25
|
||||
expect(s.premium).toBe(true); // a premium pack IS unlocked
|
||||
});
|
||||
|
||||
test('graduated ladder: 25 credits unlocks the whole ladder', () => {
|
||||
const s = snapshotForUser({ credits: 0, total_credits_purchased: 25 });
|
||||
expect(s.packs['generated-skins']).toBe(true);
|
||||
expect(s.packs['iso-dungeon']).toBe(true);
|
||||
expect(s.packs['kenney-3d-characters']).toBe(true);
|
||||
expect(s.premium).toBe(true);
|
||||
});
|
||||
|
||||
test('a credit buyer is NOT auto-promoted to a premium tier', () => {
|
||||
@@ -91,7 +98,7 @@ describe('canUsePack reads the snapshot', () => {
|
||||
const locked = snapshotForUser({ total_credits_purchased: 0 });
|
||||
expect(Entitlements.canUsePack(locked, 'roguelike-interior')).toBe(true); // free
|
||||
expect(Entitlements.canUsePack(locked, 'iso-dungeon')).toBe(false); // locked
|
||||
const unlocked = snapshotForUser({ total_credits_purchased: 1 });
|
||||
const unlocked = snapshotForUser({ total_credits_purchased: 10 }); // iso threshold is 10
|
||||
expect(Entitlements.canUsePack(unlocked, 'iso-dungeon')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -47,9 +47,10 @@ describe('recordDirectEntryPurchase', () => {
|
||||
expect(insert[0]).toMatch(/'direct_entry'/); // audits the purchase leg
|
||||
expect(insert[0]).toMatch(/'game_entry'/); // audits the spend leg
|
||||
|
||||
// The seed premium packs (threshold 1) are now unlocked, exactly like a credit purchase.
|
||||
expect(rec.entitlements.packs['iso-dungeon']).toBe(true);
|
||||
// A direct entry = 1 credit, which unlocks Fancy (generated-skins, threshold 1) but not the
|
||||
// pricier Iso (10) / 3D (25) tiers.
|
||||
expect(rec.entitlements.packs['generated-skins']).toBe(true);
|
||||
expect(rec.entitlements.packs['iso-dungeon']).toBe(false);
|
||||
expect(rec.entitlements.premium).toBe(true);
|
||||
// ...but a direct buyer is still NOT a premium tier.
|
||||
expect(rec.entitlements.level).toBe('free');
|
||||
|
||||
@@ -11,14 +11,14 @@ describe('cosmetic entitlements', () => {
|
||||
expect(Entitlements.normalizeAppearance({ avatar: 'kenney-survivor-male' }, entitlements).avatar).toBe('default');
|
||||
});
|
||||
|
||||
test('any credits purchase unlocks the preview premium packs', () => {
|
||||
test('graduated ladder: credit spend unlocks packs by threshold', () => {
|
||||
const entitlements = Entitlements.snapshotForUser({ credits: 7, total_credits_purchased: 10 });
|
||||
|
||||
expect(entitlements.premium).toBe(true);
|
||||
expect(entitlements.level).toBe('free'); // spend unlocks packs by threshold, but isn't a premium tier
|
||||
expect(entitlements.packs['generated-skins']).toBe(true);
|
||||
expect(entitlements.packs['iso-dungeon']).toBe(true);
|
||||
expect(entitlements.packs['kenney-3d-characters']).toBe(true);
|
||||
expect(entitlements.packs['generated-skins']).toBe(true); // threshold 1
|
||||
expect(entitlements.packs['iso-dungeon']).toBe(true); // threshold 10 — just reached
|
||||
expect(entitlements.packs['kenney-3d-characters']).toBe(false); // threshold 25 — not yet
|
||||
expect(Entitlements.normalizeAppearance({ avatar: 'monero-knight' }, entitlements).avatar).toBe('monero-knight');
|
||||
});
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ describe('IdentityService', () => {
|
||||
|
||||
expect(snapshot.appearance).toEqual(db.state.user.appearance);
|
||||
expect(snapshot.entitlements.premium).toBe(true);
|
||||
expect(snapshot.entitlements.packs['iso-dungeon']).toBe(true);
|
||||
expect(snapshot.entitlements.packs['generated-skins']).toBe(true); // 5 credits >= threshold 1
|
||||
expect(snapshot.entitlements.packs['iso-dungeon']).toBe(false); // < threshold 10
|
||||
});
|
||||
|
||||
test('saves normalized appearance and refreshes the session cache', async () => {
|
||||
|
||||
Reference in New Issue
Block a user