diff --git a/packages/contracts/src/clipboard-runtime.test.ts b/packages/contracts/src/clipboard-runtime.test.ts index 8ee5f845ba..eee72ae1c9 100644 --- a/packages/contracts/src/clipboard-runtime.test.ts +++ b/packages/contracts/src/clipboard-runtime.test.ts @@ -21,18 +21,51 @@ const device = { const local = (resolveInteractor: LocalInteractorOperationResolver) => localInteractorSource({ device, resolveInteractor }); -test('builds the exact clipboard operation fact catalog', () => { +test('builds the exact clipboard operation fact catalog for an owner that names both halves', () => { const read = { available: true } as const; const write = { available: false, reason: 'owner-capability-missing', } as const; - expect(clipboardRuntimeOperationFacts({ read, write })).toEqual({ + expect( + clipboardRuntimeOperationFacts({ + unsupported: write, + read, + write, + }), + ).toEqual({ readClipboard: read, writeClipboard: write, }); }); +test('a half the owner never names reports the denial the owner stated for the family, verbatim — omission is a classified refusal, never an unclassified half and never an implied success', () => { + const denial = { + available: false, + reason: 'unsupported-platform-leaf', + hint: 'clipboard is not supported on Vega OS.', + } as const; + + expect( + clipboardRuntimeOperationFacts({ unsupported: denial, read: { available: true } }), + ).toEqual({ + readClipboard: { available: true }, + writeClipboard: denial, + }); +}); + +test('an owner serving neither clipboard half names the family denial once and still answers with the exhaustive shape', () => { + const denial = { available: false, reason: 'unsupported-platform-leaf' } as const; + + const facts = clipboardRuntimeOperationFacts({ unsupported: denial }); + + expect(facts).toEqual({ + readClipboard: denial, + writeClipboard: denial, + }); + expect(Object.isFrozen(facts)).toBe(true); +}); + test('a local read binding returns the interactor pasteboard text verbatim', async () => { const readClipboard = vi.fn(async () => 'copied\ntext'); const resolveInteractor = vi.fn(async () => ({ readClipboard }) as unknown as Interactor); diff --git a/packages/contracts/src/clipboard-runtime.ts b/packages/contracts/src/clipboard-runtime.ts index dcbb033981..bb60e8021e 100644 --- a/packages/contracts/src/clipboard-runtime.ts +++ b/packages/contracts/src/clipboard-runtime.ts @@ -1,5 +1,5 @@ import type { Interactor, RunnerContext } from './interactor-types.ts'; -import type { RuntimeOperationFact } from './platform-runtime.ts'; +import type { RuntimeOperationFact, RuntimeOperationUnavailability } from './platform-runtime.ts'; import type { SnapshotRuntimeExecution } from './snapshot-runtime.ts'; /** @@ -41,14 +41,32 @@ export type ClipboardRuntimeOperationFacts = Readonly<{ }>; /** - * Read and write are separate cells because an owner can genuinely have one without the other — - * a WebDriver provider whose Appium clipboard extension exposes only a getter is the real case — - * and `clipboard read` must not be refused because the write half is missing. + * What an owner declares about the clipboard. Read and write stay separate cells because an owner + * can genuinely have one without the other — a WebDriver provider whose Appium clipboard extension + * exposes only a getter is the real case — and `clipboard read` must not be refused because the + * write half is missing. + * + * Both halves ride one shell command set on every other owner, so an owner with neither names + * `unsupported` once and a half it never names reports that denial verbatim: omission is a + * classified refusal, never an unclassified half and never an implied success. An owner states a + * half only to say something the family denial does not. */ +export type ClipboardRuntimeOperationFactsInput = Readonly<{ + unsupported: RuntimeOperationUnavailability; + read?: RuntimeOperationFact; + write?: RuntimeOperationFact; +}>; + +/** Builds the exhaustive owner claims for the two clipboard operations. */ export function clipboardRuntimeOperationFacts( - input: Readonly<{ read: RuntimeOperationFact; write: RuntimeOperationFact }>, + input: ClipboardRuntimeOperationFactsInput, ): ClipboardRuntimeOperationFacts { - return Object.freeze({ readClipboard: input.read, writeClipboard: input.write }); + const declared = (fact: RuntimeOperationFact | undefined): RuntimeOperationFact => + fact ?? input.unsupported; + return Object.freeze({ + readClipboard: declared(input.read), + writeClipboard: declared(input.write), + }); } /** diff --git a/packages/contracts/src/platform-runtime-unavailable.test.ts b/packages/contracts/src/platform-runtime-unavailable.test.ts index 306dcd4506..bfff68ccfc 100644 --- a/packages/contracts/src/platform-runtime-unavailable.test.ts +++ b/packages/contracts/src/platform-runtime-unavailable.test.ts @@ -48,8 +48,7 @@ const UNAVAILABLE_FACTS: UnavailablePlatformRuntimeFacts = { orientation: { available: false, reason: 'unsupported-provider-mode' }, tvRemote: { available: false, reason: 'unsupported-provider-mode' }, keyboard: { available: false, reason: 'unsupported-provider-mode' }, - readClipboard: { available: false, reason: 'unsupported-provider-mode' }, - writeClipboard: { available: false, reason: 'unsupported-provider-mode' }, + clipboard: { available: false, reason: 'unsupported-provider-mode' }, appSwitcher: { available: false, reason: 'unsupported-provider-mode' }, triggerAppEvent: { available: false, reason: 'unsupported-provider-mode' }, setSetting: { available: false, reason: 'unsupported-provider-mode' }, @@ -96,6 +95,12 @@ test('generic unavailable binding preserves exact provider ownership and mode', reason: 'unsupported-provider-mode', }); } + for (const operation of ['readClipboard', 'writeClipboard'] as const) { + assert.deepEqual(binding.facts.operations[operation], { + available: false, + reason: 'unsupported-provider-mode', + }); + } // `apps` is left unclassified above (an optional cell): it inherits the network gap's reason. assert.deepEqual(binding.facts.operations.listApps, { available: false, diff --git a/packages/contracts/src/platform-runtime-unavailable.ts b/packages/contracts/src/platform-runtime-unavailable.ts index 9735b0575e..de682a1f04 100644 --- a/packages/contracts/src/platform-runtime-unavailable.ts +++ b/packages/contracts/src/platform-runtime-unavailable.ts @@ -62,8 +62,7 @@ export type UnavailablePlatformRuntimeFacts = Readonly<{ orientation: RuntimeOperationUnavailability; tvRemote: RuntimeOperationUnavailability; keyboard: RuntimeOperationUnavailability; - readClipboard: RuntimeOperationUnavailability; - writeClipboard: RuntimeOperationUnavailability; + clipboard: RuntimeOperationUnavailability; appSwitcher: RuntimeOperationUnavailability; triggerAppEvent: RuntimeOperationUnavailability; setSetting: RuntimeOperationUnavailability; @@ -118,8 +117,7 @@ const UNAVAILABLE_CELLS = { orientation: true, tvRemote: true, keyboard: true, - readClipboard: true, - writeClipboard: true, + clipboard: true, appSwitcher: true, triggerAppEvent: true, setSetting: true, @@ -239,10 +237,7 @@ export function createUnavailablePlatformRuntimeFacts( ...orientationRuntimeOperationFacts({ orientation: frozen.orientation }), ...tvRemoteRuntimeOperationFacts({ tvRemote: frozen.tvRemote }), ...keyboardRuntimeOperationFacts({ unsupported: frozen.keyboard }), - ...clipboardRuntimeOperationFacts({ - read: frozen.readClipboard, - write: frozen.writeClipboard, - }), + ...clipboardRuntimeOperationFacts({ unsupported: frozen.clipboard }), ...appSwitcherRuntimeOperationFacts({ appSwitcher: frozen.appSwitcher }), ...appEventRuntimeOperationFacts({ triggerAppEvent: frozen.triggerAppEvent }), ...settingsRuntimeOperationFacts({ setSetting: frozen.setSetting }), diff --git a/packages/platform-android/src/runtime.ts b/packages/platform-android/src/runtime.ts index 0e0ed64cba..99a66bbc9d 100644 --- a/packages/platform-android/src/runtime.ts +++ b/packages/platform-android/src/runtime.ts @@ -377,7 +377,11 @@ export function createAndroidPlatformRuntime(host: PlatformRuntimeHost): Platfor }), // Read and write share one cell: `cmd clipboard` either has a shell implementation on this // build or it has none, and no Android build ships one half of it. - ...clipboardRuntimeOperationFacts({ read: clipboardCell, write: clipboardCell }), + ...clipboardRuntimeOperationFacts({ + unsupported: clipboardCell.available ? clipboardShellUnavailable : clipboardCell, + read: clipboardCell, + write: clipboardCell, + }), ...audioProbeRuntimeOperationFacts({ capture: androidAudioProbeCaptureFact(device), query: audioQueryUnavailable, diff --git a/packages/platform-apple/src/system/runtime.ts b/packages/platform-apple/src/system/runtime.ts index 4aaab146ce..b5cef7d877 100644 --- a/packages/platform-apple/src/system/runtime.ts +++ b/packages/platform-apple/src/system/runtime.ts @@ -4,7 +4,10 @@ import { clipboardRuntimeOperationFacts } from '@agent-device/contracts/clipboar import { settingsRuntimeOperationFacts } from '@agent-device/contracts/settings-runtime'; import { bindAdmittedLocalInteractorOperations } from '@agent-device/contracts/interactor-operation-catalog'; import type { PlatformRuntimeHost } from '@agent-device/contracts/platform-runtime-operations'; -import type { RuntimeOperationFact } from '@agent-device/contracts/platform-runtime'; +import type { + RuntimeOperationFact, + RuntimeOperationUnavailability, +} from '@agent-device/contracts/platform-runtime'; import { resolveDeviceAppleOs, type DeviceInfo } from '@agent-device/kernel/device'; const available = Object.freeze({ available: true } as const); @@ -113,6 +116,15 @@ function appleAppEventFact(device: DeviceInfo): RuntimeOperationFact { return resolveDeviceAppleOs(device) === 'watchos' ? appleWatchOsUnavailable : available; } +/** + * The clipboard denial this leaf reports for a half it does not name: the leaf's own refusal where + * it has one, since a leaf that serves clipboard today has no clipboard refusal to state. + */ +function appleClipboardFamilyUnavailable(device: DeviceInfo): RuntimeOperationUnavailability { + const cell = appleClipboardFact(device); + return cell.available ? clipboardLeafUnavailable : cell; +} + /** The system-surface cells: clipboard read/write, app-event delivery, settings, and alerts. */ export function appleSystemFacts(device: DeviceInfo) { const clipboard = appleClipboardFact(device); @@ -120,7 +132,11 @@ export function appleSystemFacts(device: DeviceInfo) { // press its buttons, so splitting them would invent a cell no Apple owner is ever in. const alert = appleAlertFact(device); return Object.freeze({ - ...clipboardRuntimeOperationFacts({ read: clipboard, write: clipboard }), + ...clipboardRuntimeOperationFacts({ + unsupported: appleClipboardFamilyUnavailable(device), + read: clipboard, + write: clipboard, + }), ...alertRuntimeOperationFacts({ read: alert, wait: alert, accept: alert, dismiss: alert }), ...appEventRuntimeOperationFacts({ triggerAppEvent: appleAppEventFact(device) }), ...settingsRuntimeOperationFacts({ diff --git a/packages/platform-harmonyos/src/runtime.ts b/packages/platform-harmonyos/src/runtime.ts index 5e2412f51b..853c0ba378 100644 --- a/packages/platform-harmonyos/src/runtime.ts +++ b/packages/platform-harmonyos/src/runtime.ts @@ -296,10 +296,7 @@ export function createHarmonyPlatformRuntime(host: PlatformRuntimeHost): Platfor enter: harmonyFocusFact(device), }), // HarmonyOS exposes no clipboard automation operation. - ...clipboardRuntimeOperationFacts({ - read: harmonyPlatformLeafUnavailable, - write: harmonyPlatformLeafUnavailable, - }), + ...clipboardRuntimeOperationFacts({ unsupported: harmonyPlatformLeafUnavailable }), ...audioProbeRuntimeOperationFacts({ capture: audioProbeUnavailable, query: audioProbeUnavailable, diff --git a/packages/platform-linux/src/runtime.ts b/packages/platform-linux/src/runtime.ts index 91f668cc6f..d00c6d8be7 100644 --- a/packages/platform-linux/src/runtime.ts +++ b/packages/platform-linux/src/runtime.ts @@ -196,8 +196,7 @@ function linuxFacts(device: DeviceInfo): RuntimeFacts home: homeKindUnavailable, orientation: linuxPlatformLeafUnavailable, tvRemote: linuxPlatformLeafUnavailable, - readClipboard: clipboardKindUnavailable, - writeClipboard: clipboardKindUnavailable, + clipboard: clipboardKindUnavailable, // The Linux interactor's own `appSwitcher` throws unsupported, and the retired descriptor // declared `linux: {}`, so no Linux cell was ever admitted. appSwitcher: linuxPlatformLeafUnavailable, @@ -269,6 +268,7 @@ function linuxFacts(device: DeviceInfo): RuntimeFacts // Parity with the retired `clipboard` capability bucket (`{ device: true }`): wl-clipboard // / xclip / xsel drive the desktop session's selection, and no other Linux cell has one. ...clipboardRuntimeOperationFacts({ + unsupported: clipboardKindUnavailable, read: linuxDesktopFact(device, clipboardKindUnavailable), write: linuxDesktopFact(device, clipboardKindUnavailable), }), diff --git a/packages/platform-vega/src/runtime.ts b/packages/platform-vega/src/runtime.ts index 279f51f8c3..3e9b809df7 100644 --- a/packages/platform-vega/src/runtime.ts +++ b/packages/platform-vega/src/runtime.ts @@ -191,8 +191,7 @@ function vegaFacts(device: DeviceInfo): RuntimeFacts home: homeUnavailable, orientation: orientationUnavailable, tvRemote: tvRemoteUnavailable, - readClipboard: clipboardUnavailable, - writeClipboard: clipboardUnavailable, + clipboard: clipboardUnavailable, appSwitcher: appSwitcherUnavailable, triggerAppEvent: appEventUnavailable, setSetting: settingsUnavailable, diff --git a/packages/platform-web/src/runtime.ts b/packages/platform-web/src/runtime.ts index 0c6b8207da..14fdb58c6b 100644 --- a/packages/platform-web/src/runtime.ts +++ b/packages/platform-web/src/runtime.ts @@ -413,10 +413,7 @@ function webRuntimeFacts( ...keyboardRuntimeOperationFacts({ unsupported: navigationUnavailable }), // The web backend never carried a `clipboard` capability bucket (`WEB_QUERY_COMMANDS` // lists `audio` alone), so no clipboard cell was ever admitted here. - ...clipboardRuntimeOperationFacts({ - read: navigationUnavailable, - write: navigationUnavailable, - }), + ...clipboardRuntimeOperationFacts({ unsupported: navigationUnavailable }), // Parity with the retired `WEB_QUERY_COMMANDS` graft, which admitted `audio` on every web // device; the provider that carries no probe transport still refuses at execution. ...audioProbeRuntimeOperationFacts({ capture: audioCaptureUnavailable, query: available }), diff --git a/packages/provider-limrun/src/app-log-runtime.ts b/packages/provider-limrun/src/app-log-runtime.ts index 92562f4d4b..e3863fd286 100644 --- a/packages/provider-limrun/src/app-log-runtime.ts +++ b/packages/provider-limrun/src/app-log-runtime.ts @@ -109,8 +109,7 @@ export function createLimrunPlatformRuntimeOwner( orientation: liveSessionUnavailable, tvRemote: liveSessionUnavailable, keyboard: liveSessionUnavailable, - readClipboard: liveSessionUnavailable, - writeClipboard: liveSessionUnavailable, + clipboard: liveSessionUnavailable, appSwitcher: liveSessionUnavailable, triggerAppEvent: liveSessionUnavailable, setSetting: liveSessionUnavailable, diff --git a/packages/provider-limrun/src/interaction-operations.ts b/packages/provider-limrun/src/interaction-operations.ts index 80343e8811..3e3f318eb5 100644 --- a/packages/provider-limrun/src/interaction-operations.ts +++ b/packages/provider-limrun/src/interaction-operations.ts @@ -59,6 +59,11 @@ const gestureUnsupportedProviderMode = Object.freeze({ available: false, reason: 'unsupported-provider-mode', } as const); +/** What an unnamed clipboard half reports on a live Limrun session. */ +const clipboardUnsupportedProviderMode = Object.freeze({ + available: false, + reason: 'unsupported-provider-mode', +} as const); const androidTvMultiTouchUnavailable = Object.freeze({ available: false, reason: 'unsupported-platform-leaf', @@ -267,9 +272,23 @@ export function limrunClipboardOperationFacts( device: DeviceInfo, liveSessionUnavailable?: RuntimeOperationUnavailability, ) { - const cell = - liveSessionUnavailable ?? (device.platform === 'android' ? available : clipboardUnavailableIos); - return Object.freeze({ ...clipboardRuntimeOperationFacts({ read: cell, write: cell }) }); + if (liveSessionUnavailable) { + return Object.freeze({ + ...clipboardRuntimeOperationFacts({ unsupported: liveSessionUnavailable }), + }); + } + if (device.platform !== 'android') { + return Object.freeze({ + ...clipboardRuntimeOperationFacts({ unsupported: clipboardUnavailableIos }), + }); + } + return Object.freeze({ + ...clipboardRuntimeOperationFacts({ + unsupported: clipboardUnsupportedProviderMode, + read: available, + write: available, + }), + }); } const alertUnavailableIos = Object.freeze({ diff --git a/packages/provider-webdriver/src/platform-runtime.ts b/packages/provider-webdriver/src/platform-runtime.ts index 2e82d2952a..c011a140d2 100644 --- a/packages/provider-webdriver/src/platform-runtime.ts +++ b/packages/provider-webdriver/src/platform-runtime.ts @@ -519,8 +519,7 @@ function webDriverFacts( orientation: inactiveSession, tvRemote: inactiveSession, keyboard: inactiveSession, - readClipboard: inactiveSession, - writeClipboard: inactiveSession, + clipboard: inactiveSession, appSwitcher: inactiveSession, triggerAppEvent: inactiveSession, setSetting: inactiveSession, @@ -563,8 +562,7 @@ function webDriverFacts( orientation: orientationUnavailable, tvRemote: tvRemoteUnavailable, keyboard: keyboardUnavailable, - readClipboard: clipboardUnavailable, - writeClipboard: clipboardUnavailable, + clipboard: clipboardUnavailable, appSwitcher: appSwitcherUnavailable, triggerAppEvent: appEventUnavailable, setSetting: settingsUnavailable, @@ -653,6 +651,7 @@ function webDriverFacts( // Appium — which does expose the clipboard extension. The refusal moves to where it can be // true: the interactor, per session. ...clipboardRuntimeOperationFacts({ + unsupported: clipboardUnavailable, read: declared('clipboard.read', clipboardUnavailable), write: declared('clipboard.write', clipboardUnavailable), }), diff --git a/src/__tests__/test-utils/runtime-operation-facts.ts b/src/__tests__/test-utils/runtime-operation-facts.ts index fb3b415be4..c12d93236a 100644 --- a/src/__tests__/test-utils/runtime-operation-facts.ts +++ b/src/__tests__/test-utils/runtime-operation-facts.ts @@ -1,5 +1,6 @@ import { applicationLifecycleOperationFacts } from '@agent-device/contracts/application-lifecycle-runtime'; import { audioProbeRuntimeOperationFacts } from '@agent-device/contracts/audio-probe-runtime'; +import { clipboardRuntimeOperationFacts } from '@agent-device/contracts/clipboard-runtime'; import { elementTextRuntimeOperationFacts } from '@agent-device/contracts/element-text-runtime'; import { gestureRuntimeOperationFacts } from '@agent-device/contracts/gesture-runtime'; import { keyboardRuntimeOperationFacts } from '@agent-device/contracts/keyboard-runtime'; @@ -60,8 +61,7 @@ export const unavailableDeploymentSnapshotAndShutdownOperationFacts = Object.fre setOrientation: unavailable, tvRemote: unavailable, ...keyboardRuntimeOperationFacts({ unsupported: unavailable }), - readClipboard: unavailable, - writeClipboard: unavailable, + ...clipboardRuntimeOperationFacts({ unsupported: unavailable }), appSwitcher: unavailable, triggerAppEvent: unavailable, setSetting: unavailable, @@ -119,8 +119,7 @@ export function createUnavailableRuntimeFactsForTest( orientation: fact, tvRemote: fact, keyboard: fact, - readClipboard: fact, - writeClipboard: fact, + clipboard: fact, appSwitcher: fact, triggerAppEvent: fact, setSetting: fact, diff --git a/src/daemon/handlers/__tests__/install-source.test.ts b/src/daemon/handlers/__tests__/install-source.test.ts index 338364d7dd..da71443415 100644 --- a/src/daemon/handlers/__tests__/install-source.test.ts +++ b/src/daemon/handlers/__tests__/install-source.test.ts @@ -14,6 +14,7 @@ import { } from '@agent-device/contracts/platform-runtime'; import { audioProbeRuntimeOperationFacts } from '@agent-device/contracts/audio-probe-runtime'; import { perfRuntimeOperationFacts } from '@agent-device/contracts/perf-runtime'; +import { clipboardRuntimeOperationFacts } from '@agent-device/contracts/clipboard-runtime'; import { gestureRuntimeOperationFacts } from '@agent-device/contracts/gesture-runtime'; import { keyboardRuntimeOperationFacts } from '@agent-device/contracts/keyboard-runtime'; import type { PlatformRuntimeOperations } from '@agent-device/contracts/platform-runtime-operations'; @@ -377,8 +378,7 @@ function sourceRuntimeFacts( setOrientation: unavailable, tvRemote: unavailable, ...keyboardRuntimeOperationFacts({ unsupported: unavailable }), - readClipboard: unavailable, - writeClipboard: unavailable, + ...clipboardRuntimeOperationFacts({ unsupported: unavailable }), appSwitcher: unavailable, triggerAppEvent: unavailable, setSetting: unavailable, diff --git a/src/daemon/handlers/__tests__/session-clipboard.test.ts b/src/daemon/handlers/__tests__/session-clipboard.test.ts index 280fa76359..8b99e82bb4 100644 --- a/src/daemon/handlers/__tests__/session-clipboard.test.ts +++ b/src/daemon/handlers/__tests__/session-clipboard.test.ts @@ -51,9 +51,10 @@ function harness( const writeClipboard = vi.fn(async () => undefined); const runtimeFacts: RuntimeFacts = { device: { ...deviceShape(device), providerMode: 'local' }, - operations: clipboardRuntimeOperationFacts( - facts, - ) as RuntimeFacts['operations'], + operations: clipboardRuntimeOperationFacts({ + unsupported: unavailable, + ...facts, + }) as RuntimeFacts['operations'], }; const binding = { device, diff --git a/src/daemon/handlers/__tests__/session-state.test.ts b/src/daemon/handlers/__tests__/session-state.test.ts index 27485b29c0..3f2dfcd976 100644 --- a/src/daemon/handlers/__tests__/session-state.test.ts +++ b/src/daemon/handlers/__tests__/session-state.test.ts @@ -59,8 +59,7 @@ test('boot rejects --headless outside Android directly', async () => { orientation: { available: false, reason: 'owner-capability-missing' }, tvRemote: { available: false, reason: 'owner-capability-missing' }, keyboard: { available: false, reason: 'owner-capability-missing' }, - readClipboard: { available: false, reason: 'owner-capability-missing' }, - writeClipboard: { available: false, reason: 'owner-capability-missing' }, + clipboard: { available: false, reason: 'owner-capability-missing' }, appSwitcher: { available: false, reason: 'owner-capability-missing' }, triggerAppEvent: { available: false, reason: 'owner-capability-missing' }, setSetting: { available: false, reason: 'owner-capability-missing' }, @@ -166,8 +165,7 @@ test('appstate rejects web before Android app-state backend dispatch', async () orientation: { available: false, reason: 'unsupported-platform-leaf' }, tvRemote: { available: false, reason: 'unsupported-platform-leaf' }, keyboard: { available: false, reason: 'unsupported-platform-leaf' }, - readClipboard: { available: false, reason: 'unsupported-platform-leaf' }, - writeClipboard: { available: false, reason: 'unsupported-platform-leaf' }, + clipboard: { available: false, reason: 'unsupported-platform-leaf' }, appSwitcher: { available: false, reason: 'unsupported-platform-leaf' }, triggerAppEvent: { available: false, reason: 'unsupported-platform-leaf' }, setSetting: { available: false, reason: 'unsupported-platform-leaf' }, diff --git a/src/platform-runtime-gateway.test.ts b/src/platform-runtime-gateway.test.ts index ff2e292b82..5d151cfff6 100644 --- a/src/platform-runtime-gateway.test.ts +++ b/src/platform-runtime-gateway.test.ts @@ -67,8 +67,7 @@ describe('composed platform runtime gateway', () => { orientation: unavailable, tvRemote: unavailable, keyboard: unavailable, - readClipboard: unavailable, - writeClipboard: unavailable, + clipboard: unavailable, appSwitcher: unavailable, triggerAppEvent: unavailable, setSetting: unavailable, @@ -166,8 +165,7 @@ describe('composed platform runtime gateway', () => { orientation: unavailable, tvRemote: unavailable, keyboard: unavailable, - readClipboard: unavailable, - writeClipboard: unavailable, + clipboard: unavailable, appSwitcher: unavailable, triggerAppEvent: unavailable, setSetting: unavailable,