refactor: make activate() read mana state from stores directly instead of requiring UI to pass gameState bag
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m28s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m28s
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { useDisciplineStore } from '../stores/discipline-slice';
|
||||
import { useManaStore } from '../stores/manaStore';
|
||||
|
||||
function resetDisciplineStore() {
|
||||
useDisciplineStore.setState({
|
||||
@@ -12,11 +13,14 @@ function resetDisciplineStore() {
|
||||
});
|
||||
}
|
||||
|
||||
describe('DisciplineStore — reactivate after deactivate (bug #163)', () => {
|
||||
describe('DisciplineStore — reactivate after deactivate', () => {
|
||||
beforeEach(resetDisciplineStore);
|
||||
|
||||
it('should reactivate a raw discipline after deactivate when rawMana is sufficient', () => {
|
||||
// First activation succeeds because disciplineState is undefined (optimistic)
|
||||
// Set up mana store with sufficient raw mana
|
||||
useManaStore.setState({ rawMana: 1000, elements: {} });
|
||||
|
||||
// First activation succeeds (reads rawMana from mana store)
|
||||
useDisciplineStore.getState().activate('raw-mastery');
|
||||
expect(useDisciplineStore.getState().activeIds).toContain('raw-mastery');
|
||||
|
||||
@@ -25,15 +29,19 @@ describe('DisciplineStore — reactivate after deactivate (bug #163)', () => {
|
||||
expect(useDisciplineStore.getState().activeIds).not.toContain('raw-mastery');
|
||||
expect(useDisciplineStore.getState().disciplines['raw-mastery'].paused).toBe(true);
|
||||
|
||||
// Reactivate WITH sufficient rawMana — should succeed
|
||||
useDisciplineStore.getState().activate('raw-mastery', { rawMana: 1000, elements: {}, signedPacts: [] });
|
||||
// Reactivate — reads rawMana=1000 from mana store, should succeed
|
||||
useDisciplineStore.getState().activate('raw-mastery');
|
||||
expect(useDisciplineStore.getState().activeIds).toContain('raw-mastery');
|
||||
expect(useDisciplineStore.getState().disciplines['raw-mastery'].paused).toBe(false);
|
||||
});
|
||||
|
||||
it('should NOT reactivate a raw discipline when rawMana is insufficient', () => {
|
||||
// Activate and build up XP
|
||||
// Activate with sufficient mana
|
||||
useManaStore.setState({ rawMana: 1000, elements: {} });
|
||||
useDisciplineStore.getState().activate('raw-mastery');
|
||||
expect(useDisciplineStore.getState().activeIds).toContain('raw-mastery');
|
||||
|
||||
// Build up XP via ticks
|
||||
useDisciplineStore.getState().processTick({ rawMana: 1000, elements: {} });
|
||||
useDisciplineStore.getState().processTick({ rawMana: 1000, elements: {} });
|
||||
const xp = useDisciplineStore.getState().disciplines['raw-mastery'].xp;
|
||||
@@ -43,29 +51,33 @@ describe('DisciplineStore — reactivate after deactivate (bug #163)', () => {
|
||||
useDisciplineStore.getState().deactivate('raw-mastery');
|
||||
expect(useDisciplineStore.getState().activeIds).not.toContain('raw-mastery');
|
||||
|
||||
// Reactivate with insufficient rawMana (0) — should fail
|
||||
useDisciplineStore.getState().activate('raw-mastery', { rawMana: 0, elements: {}, signedPacts: [] });
|
||||
// Set rawMana to 0 — reactivation should fail
|
||||
useManaStore.setState({ rawMana: 0, elements: {} });
|
||||
useDisciplineStore.getState().activate('raw-mastery');
|
||||
expect(useDisciplineStore.getState().activeIds).not.toContain('raw-mastery');
|
||||
});
|
||||
|
||||
it('should reactivate a discipline with elements after deactivating it', () => {
|
||||
useDisciplineStore.getState().activate('attune-fire', {
|
||||
useManaStore.setState({
|
||||
rawMana: 0,
|
||||
elements: { fire: { unlocked: true, current: 100, max: 100, baseMax: 100 } },
|
||||
});
|
||||
|
||||
useDisciplineStore.getState().activate('attune-fire');
|
||||
expect(useDisciplineStore.getState().activeIds).toContain('attune-fire');
|
||||
|
||||
useDisciplineStore.getState().deactivate('attune-fire');
|
||||
expect(useDisciplineStore.getState().activeIds).not.toContain('attune-fire');
|
||||
|
||||
useDisciplineStore.getState().activate('attune-fire', {
|
||||
elements: { fire: { unlocked: true, current: 100, max: 100, baseMax: 100 } },
|
||||
});
|
||||
// Reactivate — reads elements from mana store
|
||||
useDisciplineStore.getState().activate('attune-fire');
|
||||
expect(useDisciplineStore.getState().activeIds).toContain('attune-fire');
|
||||
expect(useDisciplineStore.getState().disciplines['attune-fire'].paused).toBe(false);
|
||||
});
|
||||
|
||||
it('should reactivate after processTick auto-pauses due to no mana', () => {
|
||||
useDisciplineStore.getState().activate('raw-mastery', { rawMana: 100, elements: {} });
|
||||
useManaStore.setState({ rawMana: 100, elements: {} });
|
||||
useDisciplineStore.getState().activate('raw-mastery');
|
||||
expect(useDisciplineStore.getState().activeIds).toContain('raw-mastery');
|
||||
|
||||
// Tick with no mana — discipline auto-pauses
|
||||
@@ -73,14 +85,16 @@ describe('DisciplineStore — reactivate after deactivate (bug #163)', () => {
|
||||
expect(useDisciplineStore.getState().activeIds).not.toContain('raw-mastery');
|
||||
expect(useDisciplineStore.getState().disciplines['raw-mastery'].paused).toBe(true);
|
||||
|
||||
// Reactivate with sufficient mana
|
||||
useDisciplineStore.getState().activate('raw-mastery', { rawMana: 1000, elements: {} });
|
||||
// Restore mana and reactivate
|
||||
useManaStore.setState({ rawMana: 1000, elements: {} });
|
||||
useDisciplineStore.getState().activate('raw-mastery');
|
||||
expect(useDisciplineStore.getState().activeIds).toContain('raw-mastery');
|
||||
expect(useDisciplineStore.getState().disciplines['raw-mastery'].paused).toBe(false);
|
||||
});
|
||||
|
||||
it('should preserve XP when deactivating and reactivating', () => {
|
||||
useDisciplineStore.getState().activate('raw-mastery', { rawMana: 1000, elements: {} });
|
||||
useManaStore.setState({ rawMana: 1000, elements: {} });
|
||||
useDisciplineStore.getState().activate('raw-mastery');
|
||||
useDisciplineStore.getState().processTick({ rawMana: 1000, elements: {} });
|
||||
useDisciplineStore.getState().processTick({ rawMana: 1000, elements: {} });
|
||||
useDisciplineStore.getState().processTick({ rawMana: 1000, elements: {} });
|
||||
@@ -90,11 +104,30 @@ describe('DisciplineStore — reactivate after deactivate (bug #163)', () => {
|
||||
expect(useDisciplineStore.getState().disciplines['raw-mastery'].xp).toBe(3);
|
||||
expect(useDisciplineStore.getState().disciplines['raw-mastery'].paused).toBe(true);
|
||||
|
||||
useDisciplineStore.getState().activate('raw-mastery', { rawMana: 1000, elements: {} });
|
||||
useDisciplineStore.getState().activate('raw-mastery');
|
||||
expect(useDisciplineStore.getState().activeIds).toContain('raw-mastery');
|
||||
expect(useDisciplineStore.getState().disciplines['raw-mastery'].xp).toBe(3);
|
||||
|
||||
useDisciplineStore.getState().processTick({ rawMana: 1000, elements: {} });
|
||||
expect(useDisciplineStore.getState().disciplines['raw-mastery'].xp).toBe(4);
|
||||
});
|
||||
|
||||
it('should use gameState overrides when explicitly provided (for test control)', () => {
|
||||
// Even though mana store has no mana, explicit override should work
|
||||
useManaStore.setState({ rawMana: 0, elements: {} });
|
||||
|
||||
// First activation: no state yet, so canProceed returns true (optimistic)
|
||||
useDisciplineStore.getState().activate('raw-mastery');
|
||||
expect(useDisciplineStore.getState().activeIds).toContain('raw-mastery');
|
||||
|
||||
useDisciplineStore.getState().deactivate('raw-mastery');
|
||||
|
||||
// Reactivate with explicit override — bypasses store reads
|
||||
useDisciplineStore.getState().activate('raw-mastery', {
|
||||
rawMana: 1000,
|
||||
elements: {},
|
||||
signedPacts: [],
|
||||
});
|
||||
expect(useDisciplineStore.getState().activeIds).toContain('raw-mastery');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user