UNPKG

scriptable-testlab

Version:

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

180 lines (150 loc) 5.46 kB
import {AbsAlert} from 'scriptable-abstract'; import {SystemState} from '../../system'; import {MockTextField} from './text-field'; interface AlertMockState { title: string; message: string; actions: string[]; textFields: MockTextField[]; destructiveActionIndex: number; cancelActionIndex: number; presentedResult: number; } const DEFAULT_STATE: AlertMockState = { title: '', message: '', actions: [], textFields: [], destructiveActionIndex: -1, cancelActionIndex: -1, presentedResult: 0, }; export class MockAlert extends AbsAlert<AlertMockState> { constructor() { super(DEFAULT_STATE); } get title(): string { return this.state.title; } set title(value: string) { if (value === null) throw new Error('Title cannot be null'); this.setState({title: value}); } get message(): string { return this.state.message; } set message(value: string) { if (value === null) throw new Error('Message cannot be null'); this.setState({message: value}); } get actions(): readonly string[] { return [...this.state.actions]; } get textFields(): readonly MockTextField[] { return new Proxy([...this.state.textFields], { get(target, prop) { if (typeof prop === 'string' && !isNaN(Number(prop))) { const index = Number(prop); if (index < 0 || index >= target.length) { throw new Error('Invalid text field index'); } } return Reflect.get(target, prop); }, }); } get destructiveAction(): string | undefined { return this.state.destructiveActionIndex >= 0 ? this.state.actions[this.state.destructiveActionIndex] : undefined; } get cancelAction(): string | undefined { return this.state.cancelActionIndex >= 0 ? this.state.actions[this.state.cancelActionIndex] : undefined; } addAction(title: string): void { if (!title) throw new Error('Action text cannot be empty'); const actions = [...this.state.actions]; const insertIndex = Math.min( this.state.cancelActionIndex >= 0 ? this.state.cancelActionIndex : actions.length, this.state.destructiveActionIndex >= 0 ? this.state.destructiveActionIndex : actions.length, ); actions.splice(insertIndex, 0, title); const newState: Partial<AlertMockState> = {actions}; if (this.state.cancelActionIndex >= insertIndex) { newState.cancelActionIndex = this.state.cancelActionIndex + 1; } if (this.state.destructiveActionIndex >= insertIndex) { newState.destructiveActionIndex = this.state.destructiveActionIndex + 1; } this.setState(newState); } addDestructiveAction(title: string): void { if (!title) throw new Error('Action text cannot be empty'); const actions = [...this.state.actions]; const insertIndex = this.state.cancelActionIndex >= 0 ? this.state.cancelActionIndex : actions.length; actions.splice(insertIndex, 0, title); const newState: Partial<AlertMockState> = { actions, destructiveActionIndex: insertIndex, }; if (this.state.cancelActionIndex >= insertIndex) { newState.cancelActionIndex = this.state.cancelActionIndex + 1; } this.setState(newState); } addCancelAction(title: string): void { if (!title) throw new Error('Action text cannot be empty'); const actions = [...this.state.actions, title]; this.setState({ actions, cancelActionIndex: actions.length - 1, }); } addTextField(placeholder?: string, text?: string): TextField { const textField = new MockTextField(); if (placeholder) textField.placeholder = placeholder; if (text) textField.text = text; const textFields = [...this.state.textFields, textField]; this.setState({textFields}); return textField; } addSecureTextField(placeholder?: string, text?: string): TextField { const textField = new MockTextField(); textField.isSecure = true; if (placeholder) textField.placeholder = placeholder; if (text) textField.text = text; const textFields = [...this.state.textFields, textField]; this.setState({textFields}); return textField; } textFieldValue(index: number): string { if (index < 0 || index >= this.state.textFields.length) return ''; return this.state.textFields[index]?.text ?? ''; } setPresentedResult(result: number): void { this.setState({presentedResult: result}); } async presentAlert(): Promise<number> { const systemResponse = SystemState.getAlertResponse(); if (systemResponse !== undefined) return systemResponse; if (this.state.presentedResult !== 0) return this.state.presentedResult; if (this.state.actions.length === 0) return -1; return this.state.presentedResult; } async presentSheet(): Promise<number> { return this.presentAlert(); } async present(): Promise<number> { return this.presentAlert(); } setState(newState: Partial<AlertMockState>): this { if (newState === null || newState === undefined) { throw new Error('State cannot be null or undefined'); } if ('title' in newState && (newState.title === null || newState.title === undefined)) { throw new Error('Title cannot be null or undefined'); } if ('message' in newState && (newState.message === null || newState.message === undefined)) { throw new Error('Message cannot be null or undefined'); } return super.setState(newState); } }