test(web): cover the difficulty-hint table and the last-difficulty setting

difficultyHints is walked against the Difficulty schema the same way
difficultyLabels already is, and the settings store gets coverage for
lastDifficulty: starts unset, persists across a reload, ignores a corrupt
stored value, and stays usable in memory when storage is hostile.
This commit is contained in:
tiennm99 committed 2026-09-21 16:59:39 +07:00
1 parent 2a94e05752
commit d5f89665d8
2 files changed
+32

No files matched your search

+9
View File
@@ -14,6 +14,7 @@ import {
PointKindSchema
} from '../src/lib/proto/noitu/v1/game_pb.js';
import {
difficultyHints,
difficultyLabels,
endReasonMessages,
errorFallback,
@@ -105,6 +106,14 @@ describe('difficulty labels', () => {
expect(difficultyLabels[value], `Difficulty ${value} has no label`).toBeTypeOf('string');
}
});
it('gives every playable difficulty a hint for the record line to fall back on', () => {
const playable = valuesOf(DifficultySchema).filter((v) => v !== Difficulty.UNSPECIFIED);
for (const value of playable) {
expect(difficultyHints[value], `Difficulty ${value} has no hint`).toBeTypeOf('string');
expect(difficultyHints[value].length).toBeGreaterThan(0);
}
});
});
describe('server error codes', () => {
+23
View File
@@ -138,6 +138,26 @@ describe('best scores', () => {
});
});
describe('last difficulty', () => {
it('starts with none picked, so a caller falls back to its own default', () => {
const store = createSettingsStore();
expect(store.state.lastDifficulty).toBeNull();
});
it('remembers the rung last picked', () => {
const store = createSettingsStore();
store.setLastDifficulty(Difficulty.HARD);
expect(store.state.lastDifficulty).toBe(Difficulty.HARD);
expect(createSettingsStore().state.lastDifficulty).toBe(Difficulty.HARD);
});
it('ignores a stored value that is not a number', () => {
localStorage.setItem('noitu.lastDifficulty', 'not-a-number');
expect(createSettingsStore().state.lastDifficulty).toBeNull();
});
});
describe('when storage is unavailable', () => {
it('constructs with working defaults instead of throwing', () => {
useStorage(hostileStorage());
@@ -145,6 +165,7 @@ describe('when storage is unavailable', () => {
expect(store.state.nickname).toBe('');
expect(store.state.bestScores).toEqual({});
expect(store.state.lastDifficulty).toBeNull();
expect(['light', 'dark']).toContain(store.state.theme);
});
@@ -155,10 +176,12 @@ describe('when storage is unavailable', () => {
expect(() => store.setNickname('Minh')).not.toThrow();
expect(() => store.setTheme('dark')).not.toThrow();
expect(store.recordScore(Difficulty.HARD, 7)).toBe(true);
expect(() => store.setLastDifficulty(Difficulty.EASY)).not.toThrow();
expect(store.state.nickname).toBe('Minh');
expect(store.state.theme).toBe('dark');
expect(store.bestScore(Difficulty.HARD)).toBe(7);
expect(store.state.lastDifficulty).toBe(Difficulty.EASY);
});
it('survives a browser that throws on the property itself', () => {