diff --git a/muxplex/frontend/app.js b/muxplex/frontend/app.js index a5ca450..052348c 100644 --- a/muxplex/frontend/app.js +++ b/muxplex/frontend/app.js @@ -1910,17 +1910,56 @@ function _createSessionInput() { } /** - * Replace the header + button with an inline text input for session naming. - * Hides the button, inserts the input before it, and focuses it. - * On Enter: if name is non-empty after trim, calls createNewSession(name). + * Create an optional device with Local + remote options', () => { + // Verify function is exported + assert.strictEqual(typeof app._createDeviceSelect, 'function', '_createDeviceSelect must be exported'); + + // Set up server settings with multi_device_enabled + remote_instances + device_name + app._setServerSettings({ + multi_device_enabled: true, + remote_instances: [{ name: 'Remote A', url: 'http://a' }], + device_name: 'MyDevice', + }); + + // Mock document.createElement to capture created elements + const origCE = globalThis.document.createElement; + const builtOptions = []; + let selectEl = null; + + globalThis.document.createElement = (tag) => { + if (tag === 'select') { + selectEl = { + tagName: 'SELECT', + className: '', + value: '', + options: builtOptions, + appendChild: (child) => { builtOptions.push(child); }, + addEventListener: () => {}, + }; + return selectEl; + } + // option elements + return { tagName: tag.toUpperCase(), value: '', textContent: '', selected: false }; + }; + + const result = app._createDeviceSelect(); + globalThis.document.createElement = origCE; + + assert.ok(result !== null, '_createDeviceSelect must return non-null when multi_device_enabled + remotes present'); + assert.strictEqual(result.className, 'new-session-device-select', 'select must have className new-session-device-select'); + assert.strictEqual(builtOptions.length, 2, 'must have 2 options: local + 1 remote'); + assert.strictEqual(builtOptions[0].value, '', 'first option value must be empty string (local)'); + assert.strictEqual(builtOptions[0].textContent, 'MyDevice', 'first option text must use device_name'); + assert.strictEqual(builtOptions[1].value, '0', 'remote option value must be "0" (String(index))'); + assert.strictEqual(builtOptions[1].textContent, 'Remote A', 'remote option text must use remote.name'); +}); + +test('showNewSessionInput creates device select when multi_device_enabled with remotes', () => { + app._setServerSettings({ + multi_device_enabled: true, + remote_instances: [{ name: 'Remote B', url: 'http://b' }], + device_name: 'LocalDev', + }); + + const origCE = globalThis.document.createElement; + const createdTags = []; + const insertedEls = []; + + globalThis.document.createElement = (tag) => { + createdTags.push(tag); + return { + tagName: tag.toUpperCase(), + className: '', + type: '', + placeholder: '', + autocomplete: '', + spellcheck: false, + value: '', + style: {}, + options: [], + appendChild: () => {}, + addEventListener: () => {}, + focus: () => {}, + }; + }; + + const btn = { + style: {}, + parentNode: { + insertBefore: (el) => { insertedEls.push(el); }, + }, + }; + + app.showNewSessionInput(btn); + globalThis.document.createElement = origCE; + + assert.ok(createdTags.includes('select'), 'showNewSessionInput must create a