UNPKG

scriptable-testlab

Version:

A lightweight, efficient tool designed to manage and update scripts for Scriptable.

225 lines (205 loc) 5.26 kB
import {MockArgs} from './mocks/system/args'; import {MockConfig} from './mocks/system/config'; import {MockDevice} from './mocks/system/device'; import {MockLocation} from './mocks/system/location'; import {MockScript} from './mocks/system/script'; import {GlobalRegistry} from './registry'; import type {GlobalPreferences} from './types'; /** * Default preferences for all mocks */ export const DEFAULT_PREFERENCES: GlobalPreferences = { device: { name: 'iPhone Mock', systemName: 'iOS', systemVersion: '16.0', model: 'iPhone', screenSize: { width: 390, height: 844, }, screenResolution: { width: 1170, height: 2532, }, screenScale: 3, screenBrightness: 1, orientation: { isInPortrait: true, isInPortraitUpsideDown: false, isInLandscapeLeft: false, isInLandscapeRight: false, isFaceUp: false, isFaceDown: false, }, battery: { level: 1, isDischarging: false, isCharging: false, isFullyCharged: true, }, locale: { preferredLanguages: ['en'], locale: 'en_US', language: 'en', }, appearance: { isUsingDarkAppearance: false, }, volume: 0.5, }, config: { widgetFamily: 'small', runsInWidget: false, runsInApp: true, runsWithSiri: false, runsInActionExtension: false, runsInNotification: false, runsFromHomeScreen: false, runsInAccessoryWidget: false, }, script: { name: 'Test Script', }, args: { plainTexts: [], fileURLs: [], images: [], queryParameters: {}, }, location: { currentLocation: { latitude: 0, longitude: 0, altitude: 0, horizontalAccuracy: 5, verticalAccuracy: 5, }, accuracy: 'best', simulatedDelay: 100, }, }; /** * Preferences manager for Scriptable testing * Handles: * 1. Loading/saving preferences * 2. Merging updates * 3. Resetting to defaults * 4. Synchronizing with mocks */ export class Preferences { private static instance: Preferences; private current: GlobalPreferences; private constructor() { this.current = {...DEFAULT_PREFERENCES}; } static getInstance(): Preferences { if (!Preferences.instance) { Preferences.instance = new Preferences(); } return Preferences.instance; } /** * Get current preferences */ get(): GlobalPreferences { return this.current; } /** * Update preferences * @param preferences Partial preferences to merge */ update(preferences: Partial<GlobalPreferences>): void { this.current = this.merge(this.current, preferences); this.syncMocks(); } /** * Reset preferences to defaults */ reset(): void { this.current = {...DEFAULT_PREFERENCES}; this.syncMocks(); } /** * Load preferences from JSON string */ loadFromJSON(json: string): void { try { const preferences = JSON.parse(json); this.current = this.merge(DEFAULT_PREFERENCES, preferences); this.syncMocks(); } catch (error) { throw new Error(`Failed to parse preferences: ${error}`); } } /** * Save preferences to JSON string */ saveToJSON(): string { return JSON.stringify(this.current, null, 2); } /** * Get preferences for specific mock */ getMock<K extends keyof GlobalPreferences>(mockName: K): GlobalPreferences[K] { return this.current[mockName]; } /** * Update preferences for specific mock */ updateMock<K extends keyof GlobalPreferences>(mockName: K, preferences: Partial<GlobalPreferences[K]>): void { this.current = { ...this.current, [mockName]: { ...this.current[mockName], ...preferences, }, }; this.syncMocks(); } /** * Synchronize current preferences with all mocks */ private syncMocks(): void { // Sync device if (GlobalRegistry.has('Device')) { GlobalRegistry.get<MockDevice>('Device').setState(this.current.device); } // Sync config if (GlobalRegistry.has('config')) { GlobalRegistry.get<MockConfig>('config').setState(this.current.config); } // Sync script if (GlobalRegistry.has('Script')) { GlobalRegistry.get<MockScript>('Script').setState(this.current.script); } // Sync args if (GlobalRegistry.has('args')) { GlobalRegistry.get<MockArgs>('args').setState(this.current.args); } // Sync location if (GlobalRegistry.has('Location')) { GlobalRegistry.get<MockLocation>('Location').setState(this.current.location); } } /** * Deep merge preferences */ private merge(target: GlobalPreferences, source: Partial<GlobalPreferences>): GlobalPreferences { const result = {...target}; for (const key in source) { if (source.hasOwnProperty(key)) { const value = source[key as keyof GlobalPreferences]; if (value && typeof value === 'object' && !Array.isArray(value)) { result[key as keyof GlobalPreferences] = { ...result[key as keyof GlobalPreferences], ...value, }; } else { result[key as keyof GlobalPreferences] = value as any; } } } return result; } }