Adds API filter registry, style theme registry, SW bitmask cache clear, KV namespacing, session expiry checks, accessibility improvements, and expanded test coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
212 lines
7.0 KiB
JavaScript
212 lines
7.0 KiB
JavaScript
/**
|
|
* Tests for platform/env.js
|
|
* Uses Node.js built-in test runner (node --test)
|
|
*/
|
|
|
|
import { test, describe, beforeEach } from 'node:test';
|
|
import assert from 'node:assert';
|
|
import {
|
|
initEnv,
|
|
getConfig,
|
|
getConfigSync,
|
|
setConfig,
|
|
getConfigDict,
|
|
isDevelopment,
|
|
isProduction,
|
|
isServiceWorkerEnabledSync,
|
|
resolveServiceWorkerEnabled,
|
|
CONFIG_KEYS
|
|
} from '../src/platform/env.js';
|
|
import { getProvider } from '../src/platform/storage.js';
|
|
|
|
describe('env.js', () => {
|
|
beforeEach(() => {
|
|
// Reset config before each test
|
|
initEnv({});
|
|
});
|
|
|
|
describe('initEnv', () => {
|
|
test('should initialize config with provided values', () => {
|
|
const appConfig = {
|
|
name: 'TestApp',
|
|
displayName: 'Test Application',
|
|
brandLogo: '/logo.png',
|
|
ui_shell: 'DashboardShell',
|
|
storage: { backend: 'indexedDB' },
|
|
api: { baseURL: '/api/v1' },
|
|
modules: ['core', 'dummy']
|
|
};
|
|
|
|
initEnv(appConfig);
|
|
|
|
const config = getConfigDict();
|
|
assert.strictEqual(config.APP_NAME, 'TestApp');
|
|
assert.strictEqual(config.APP_DISPLAY_NAME, 'Test Application');
|
|
assert.strictEqual(config.BRAND_LOGO, '/logo.png');
|
|
assert.strictEqual(config.UI_SHELL, 'DashboardShell');
|
|
assert.strictEqual(config.STORAGE_BACKEND, 'indexedDB');
|
|
assert.strictEqual(config.API_BASE_URL, '/api/v1');
|
|
assert.deepStrictEqual(config.MODULES, ['core', 'dummy']);
|
|
});
|
|
|
|
test('should use defaults when values are missing', () => {
|
|
const appConfig = {
|
|
name: 'TestApp'
|
|
};
|
|
|
|
initEnv(appConfig);
|
|
|
|
const config = getConfigDict();
|
|
assert.strictEqual(config.APP_NAME, 'TestApp');
|
|
assert.strictEqual(config.APP_DISPLAY_NAME, 'TestApp'); // Falls back to name
|
|
assert.strictEqual(config.BRAND_LOGO, '/favicon.svg'); // Default
|
|
assert.strictEqual(config.UI_SHELL, 'EmptyShell'); // Default
|
|
assert.strictEqual(config.STORAGE_BACKEND, 'localStorage'); // Default
|
|
assert.strictEqual(config.API_BASE_URL, '/api'); // Default
|
|
assert.deepStrictEqual(config.MODULES, []); // Default
|
|
});
|
|
});
|
|
|
|
describe('getConfig', () => {
|
|
beforeEach(() => {
|
|
initEnv({
|
|
name: 'TestApp',
|
|
displayName: 'Test Display Name'
|
|
});
|
|
});
|
|
|
|
test('should return config value from dictionary', async () => {
|
|
const value = await getConfig(CONFIG_KEYS.APP_NAME);
|
|
assert.strictEqual(value, 'TestApp');
|
|
});
|
|
|
|
test('should return altValue when key not found', async () => {
|
|
// Note: getConfig checks import.meta.env which may not be available in Node
|
|
// This test verifies the fallback behavior
|
|
const value = await getConfig('NON_EXISTENT_KEY', 'default');
|
|
assert.strictEqual(value, 'default');
|
|
});
|
|
|
|
test('should return null when key not found and no altValue', async () => {
|
|
// Note: getConfig checks import.meta.env which may not be available in Node
|
|
// This test verifies the fallback behavior
|
|
const value = await getConfig('NON_EXISTENT_KEY');
|
|
// May return null or undefined depending on import.meta.env availability
|
|
assert.ok(value === null || value === undefined);
|
|
});
|
|
|
|
test('locked keys ignore persisted storage overrides', async () => {
|
|
initEnv({
|
|
name: 'TestApp',
|
|
api: { base_url: '/api/profile' },
|
|
modules: ['rt', 'game']
|
|
});
|
|
|
|
const configStorage = getProvider('kv', 'config');
|
|
await configStorage.set(CONFIG_KEYS.API_BASE_URL, '/api/stale');
|
|
await configStorage.set(CONFIG_KEYS.MODULES, ['stale']);
|
|
|
|
assert.strictEqual(await getConfig(CONFIG_KEYS.API_BASE_URL), '/api/profile');
|
|
assert.deepStrictEqual(await getConfig(CONFIG_KEYS.MODULES), ['rt', 'game']);
|
|
});
|
|
});
|
|
|
|
describe('getConfigSync', () => {
|
|
test('should return in-memory config without storage reads', () => {
|
|
initEnv({
|
|
name: 'SyncApp',
|
|
api: { base_url: '/api/sync' }
|
|
});
|
|
|
|
assert.strictEqual(getConfigSync(CONFIG_KEYS.APP_NAME), 'SyncApp');
|
|
assert.strictEqual(getConfigSync(CONFIG_KEYS.API_BASE_URL), '/api/sync');
|
|
assert.strictEqual(getConfigSync('MISSING', 'fallback'), 'fallback');
|
|
});
|
|
});
|
|
|
|
describe('setConfig', () => {
|
|
beforeEach(() => {
|
|
initEnv({
|
|
name: 'TestApp'
|
|
});
|
|
});
|
|
|
|
test('should update existing config key in dictionary', async () => {
|
|
await setConfig(CONFIG_KEYS.APP_NAME, 'UpdatedApp');
|
|
const value = await getConfig(CONFIG_KEYS.APP_NAME);
|
|
assert.strictEqual(value, 'UpdatedApp');
|
|
});
|
|
|
|
test('should handle new keys (may attempt storage)', async () => {
|
|
// Since it's a new key, it should attempt to store in storage
|
|
// We just verify it doesn't throw
|
|
await assert.doesNotReject(async () => {
|
|
await setConfig('custom.key', 'customValue');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('getConfigDict', () => {
|
|
test('should return a copy of config dictionary', () => {
|
|
initEnv({
|
|
name: 'TestApp',
|
|
displayName: 'Test Display'
|
|
});
|
|
|
|
const config1 = getConfigDict();
|
|
const config2 = getConfigDict();
|
|
|
|
// Should be equal but not the same object (copy)
|
|
assert.deepStrictEqual(config1, config2);
|
|
assert.notStrictEqual(config1, config2);
|
|
});
|
|
|
|
test('should return config with defaults when initialized with empty object', () => {
|
|
initEnv({});
|
|
const config = getConfigDict();
|
|
// initEnv sets defaults even with empty object
|
|
assert.ok('APP_NAME' in config);
|
|
assert.ok('BRAND_LOGO' in config);
|
|
assert.strictEqual(config.BRAND_LOGO, '/favicon.svg');
|
|
});
|
|
});
|
|
|
|
describe('CONFIG_KEYS', () => {
|
|
test('should export all expected config keys', () => {
|
|
assert.ok('APP_NAME' in CONFIG_KEYS);
|
|
assert.ok('APP_DISPLAY_NAME' in CONFIG_KEYS);
|
|
assert.ok('BRAND_LOGO' in CONFIG_KEYS);
|
|
assert.ok('UI_SHELL' in CONFIG_KEYS);
|
|
assert.ok('STORAGE_BACKEND' in CONFIG_KEYS);
|
|
assert.ok('API_BASE_URL' in CONFIG_KEYS);
|
|
assert.ok('MODULES' in CONFIG_KEYS);
|
|
assert.ok('SERVICE_WORKER_ENABLED' in CONFIG_KEYS);
|
|
});
|
|
});
|
|
|
|
describe('service worker profile flag', () => {
|
|
test('resolveServiceWorkerEnabled defaults to true', () => {
|
|
assert.strictEqual(resolveServiceWorkerEnabled({}), true);
|
|
});
|
|
|
|
test('resolveServiceWorkerEnabled reads service_worker.enabled', () => {
|
|
assert.strictEqual(resolveServiceWorkerEnabled({ service_worker: { enabled: false } }), false);
|
|
assert.strictEqual(resolveServiceWorkerEnabled({ pwa: { service_worker: { enabled: false } } }), false);
|
|
});
|
|
|
|
test('initEnv seeds SERVICE_WORKER_ENABLED into config', () => {
|
|
initEnv({ service_worker: { enabled: false } });
|
|
assert.strictEqual(isServiceWorkerEnabledSync(), false);
|
|
assert.strictEqual(getConfigDict()[CONFIG_KEYS.SERVICE_WORKER_ENABLED], false);
|
|
});
|
|
});
|
|
|
|
describe('isDevelopment and isProduction', () => {
|
|
test('should be functions', () => {
|
|
assert.strictEqual(typeof isDevelopment, 'function');
|
|
assert.strictEqual(typeof isProduction, 'function');
|
|
});
|
|
});
|
|
});
|
|
|