fff971ad15
listQuests no longer takes a body, battle-pass track is a union, scenario run status has no unknown_run. This ships loginWithCustom and quest metric helpers that never reached the registry after the v0.4.0 publish job failed.
102 lines
3.6 KiB
TypeScript
102 lines
3.6 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
import { RudderClient } from '../../src/client/RudderClient.js';
|
|
import { createFakeTokenStore } from '../helpers/FakeTokenStore.js';
|
|
import { createFakeGateway, type FakeGateway } from '../helpers/fakeGateway.js';
|
|
import { stubDeterministicUuid } from '../helpers/memoryPlanStore.js';
|
|
import { plan } from '../helpers/plan.js';
|
|
import type { RemoteConfig } from '../../src/generated/remote-config.js';
|
|
|
|
interface GameRemoteConfig extends Record<string, unknown> {
|
|
max_energy: number;
|
|
drop_rate: number;
|
|
pvp_enabled: boolean;
|
|
welcome_text: string;
|
|
boss: { hp: number; name: string };
|
|
legacy: string;
|
|
missing_declared: string;
|
|
}
|
|
|
|
function cfg(key: string, value: string, valueType: NonNullable<RemoteConfig['valueType']>, active = true): RemoteConfig {
|
|
return { key, value, valueType, active };
|
|
}
|
|
|
|
function makeClient(): RudderClient<GameRemoteConfig> {
|
|
return new RudderClient<GameRemoteConfig>({
|
|
baseUrl: 'https://api.test.rudder.build',
|
|
projectKey: 'test-project',
|
|
tokenStore: createFakeTokenStore(),
|
|
runtime: { planStateStore: null, loginEvent: null },
|
|
});
|
|
}
|
|
|
|
describe('E2E: remote config', () => {
|
|
let gateway: FakeGateway;
|
|
let client: RudderClient<GameRemoteConfig>;
|
|
|
|
beforeEach(() => {
|
|
stubDeterministicUuid();
|
|
gateway = createFakeGateway({
|
|
remoteConfigs: {
|
|
max_energy: cfg('max_energy', '50', 'int'),
|
|
drop_rate: cfg('drop_rate', '0.25', 'float'),
|
|
pvp_enabled: cfg('pvp_enabled', 'true', 'bool'),
|
|
welcome_text: cfg('welcome_text', 'Hello!', 'string'),
|
|
boss: cfg('boss', '{"hp":1000,"name":"Drake"}', 'json'),
|
|
legacy: cfg('legacy', 'old', 'string', false), // inactive — must be excluded
|
|
},
|
|
});
|
|
gateway.install();
|
|
client = makeClient();
|
|
});
|
|
|
|
afterEach(() => vi.unstubAllGlobals());
|
|
|
|
it('loads configs and reads them back with type coercion', async () => {
|
|
await client.auth.loginWithDevice();
|
|
|
|
expect(client.remoteConfig.status).toBe('ready');
|
|
expect(client.remoteConfig.get('max_energy', 0)).toBe(50);
|
|
expect(client.remoteConfig.get('drop_rate', 0)).toBeCloseTo(0.25);
|
|
expect(client.remoteConfig.get('pvp_enabled', false)).toBe(true);
|
|
expect(client.remoteConfig.get('welcome_text', '')).toBe('Hello!');
|
|
expect(client.remoteConfig.get('boss', { hp: 0, name: '' })).toEqual({
|
|
hp: 1000,
|
|
name: 'Drake',
|
|
});
|
|
});
|
|
|
|
it('inactive configs are not exposed; missing keys fall back to default', async () => {
|
|
await client.auth.loginWithDevice();
|
|
|
|
expect(client.remoteConfig.get('legacy', 'DEFAULT')).toBe('DEFAULT');
|
|
expect(client.remoteConfig.get('missing_declared', 'fallback')).toBe('fallback');
|
|
});
|
|
|
|
it('get() before login returns the default (no throw)', () => {
|
|
expect(client.remoteConfig.status).toBe('idle');
|
|
expect(client.remoteConfig.get('max_energy', 99)).toBe(99);
|
|
});
|
|
|
|
it('a remote_config_override scenario node patches the live cache', async () => {
|
|
client = new RudderClient<GameRemoteConfig>({
|
|
baseUrl: 'https://api.test.rudder.build',
|
|
projectKey: 'test-project',
|
|
tokenStore: createFakeTokenStore(),
|
|
runtime: { planStateStore: null },
|
|
});
|
|
gateway.onEvent(
|
|
'player_login',
|
|
plan('boost')
|
|
.node('override', 'remote_config_override', {
|
|
patches: [{ path: 'drop_rate', valueType: 'float', value: '0.9' }],
|
|
})
|
|
.build(),
|
|
);
|
|
|
|
await client.auth.loginWithDevice();
|
|
|
|
// The override is reflected immediately, without a reload.
|
|
expect(client.remoteConfig.get('drop_rate', 0)).toBeCloseTo(0.9);
|
|
});
|
|
});
|