Repository navigation
feat(android): add settings bluetooth on|off #3721
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e1affad
e7d9772
73effc5
458e9d1
d06c6ff
8e302d9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -227,6 +227,29 @@ test('settings text-size reads the category the owner holds without mutating any | |||||||
| expect(fixtureSettingsMutations).toHaveLength(0); | ||||||||
| }); | ||||||||
|
|
||||||||
| test('settings bluetooth on an iOS simulator is refused at admission, before dispatch', async () => { | ||||||||
| const sessionStore = makeSessionStore(); | ||||||||
| const sessionName = 'ios-bluetooth'; | ||||||||
| sessionStore.publish(sessionName, makeSession(sessionName, iosSimulatorDevice)); | ||||||||
|
|
||||||||
| const response = await handleSnapshotCommands({ | ||||||||
| createCommandSurface: fakeCreateCommandSurface, | ||||||||
| platformServices: daemonPlatformServicesFixture(), | ||||||||
| req: snapshotRequest(sessionName, 'settings', { positionals: ['bluetooth', 'on'] }), | ||||||||
| sessionName, | ||||||||
| logPath: '/tmp/daemon.log', | ||||||||
| sessionStore, | ||||||||
| }); | ||||||||
|
|
||||||||
| expect(response?.ok).toBe(false); | ||||||||
| if (response && !response.ok) { | ||||||||
| expect(response.error.code).toBe('UNSUPPORTED_OPERATION'); | ||||||||
| expect(response.error.message).toBe('settings bluetooth is not supported on this device'); | ||||||||
| expect(response.error.details?.reason).toBe('unsupported-platform-leaf'); | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: This test claims the Bluetooth request is refused before dispatch, but it does not assert the typed dispatch disclosure. Add Prompt for AI agents
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not fixing this one here. The refusal comes from the shared |
||||||||
| } | ||||||||
| expect(fixtureSettingsMutations).toHaveLength(0); | ||||||||
| }); | ||||||||
|
|
||||||||
| test('settings on the macOS host refuses a setting it does not serve, read and write alike', async () => { | ||||||||
| const sessionStore = makeSessionStore(); | ||||||||
| const sessionName = 'macos-settings'; | ||||||||
|
|
@@ -655,31 +678,34 @@ test('settings mobile-data reaches the Android owner as an on/off mutation', asy | |||||||
| expect(fixtureSettingsMutations.at(-1)).toMatchObject({ setting: 'mobile-data', state: 'off' }); | ||||||||
| }); | ||||||||
|
|
||||||||
| test('settings Android mobile-data refuses a named app before reaching the owner', async () => { | ||||||||
| const sessionStore = makeSessionStore(); | ||||||||
| const sessionName = 'android-mobile-data-app-refused'; | ||||||||
| sessionStore.publish(sessionName, makeSession(sessionName, androidDevice)); | ||||||||
| test.each(['mobile-data', 'bluetooth'])( | ||||||||
| 'settings Android %s refuses a named app before reaching the owner', | ||||||||
| async (setting) => { | ||||||||
| const sessionStore = makeSessionStore(); | ||||||||
| const sessionName = `android-${setting}-app-refused`; | ||||||||
| sessionStore.publish(sessionName, makeSession(sessionName, androidDevice)); | ||||||||
|
|
||||||||
| const response = await handleSnapshotCommands({ | ||||||||
| createCommandSurface: fakeCreateCommandSurface, | ||||||||
| platformServices: daemonPlatformServicesFixture(), | ||||||||
| req: snapshotRequest(sessionName, 'settings', { | ||||||||
| positionals: ['mobile-data', 'off'], | ||||||||
| input: { app: 'com.example.app' }, | ||||||||
| }), | ||||||||
| sessionName, | ||||||||
| logPath: '/tmp/daemon.log', | ||||||||
| sessionStore, | ||||||||
| }); | ||||||||
| const response = await handleSnapshotCommands({ | ||||||||
| createCommandSurface: fakeCreateCommandSurface, | ||||||||
| platformServices: daemonPlatformServicesFixture(), | ||||||||
| req: snapshotRequest(sessionName, 'settings', { | ||||||||
| positionals: [setting, 'off'], | ||||||||
| input: { app: 'com.example.app' }, | ||||||||
| }), | ||||||||
| sessionName, | ||||||||
| logPath: '/tmp/daemon.log', | ||||||||
| sessionStore, | ||||||||
| }); | ||||||||
|
|
||||||||
| expect(response?.ok).toBe(false); | ||||||||
| expect(fixtureSettingsMutations).toHaveLength(0); | ||||||||
| if (response && !response.ok) { | ||||||||
| expect(response.error.code).toBe('INVALID_ARGS'); | ||||||||
| expect(response.error.details?.reason).toBe('setting_app_not_consumed'); | ||||||||
| expect(response.error.details?.dispatched).toBe('no'); | ||||||||
| } | ||||||||
| }); | ||||||||
| expect(response?.ok).toBe(false); | ||||||||
| expect(fixtureSettingsMutations).toHaveLength(0); | ||||||||
| if (response && !response.ok) { | ||||||||
| expect(response.error.code).toBe('INVALID_ARGS'); | ||||||||
| expect(response.error.details?.reason).toBe('setting_app_not_consumed'); | ||||||||
| expect(response.error.details?.dispatched).toBe('no'); | ||||||||
| } | ||||||||
| }, | ||||||||
| ); | ||||||||
|
|
||||||||
| test('settings macOS permission grant refuses a named app before reaching the owner', async () => { | ||||||||
| const sessionStore = makeSessionStore(); | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import { test } from 'vitest'; | ||
| import assert from 'node:assert/strict'; | ||
| import { readAndroidSdkInt } from '../device-sdk-int.ts'; | ||
| import { withFakeAdb, type FakeAdbResponse } from './test-utils/fake-adb.ts'; | ||
|
|
||
| test.each([ | ||
| { response: '34\n', expected: 34 }, | ||
| { response: '', expected: null }, | ||
| { response: 'unknown', expected: null }, | ||
| { response: '0', expected: null }, | ||
| { response: '27garbage', expected: null }, | ||
| { response: { stderr: 'error: closed', exitCode: 1 }, expected: null }, | ||
| ] satisfies { response: FakeAdbResponse; expected: number | null }[])( | ||
| 'readAndroidSdkInt reads $response as $expected', | ||
| async ({ response, expected }) => { | ||
| await withFakeAdb( | ||
| () => response, | ||
| async ({ calls, device }) => { | ||
| assert.equal((await readAndroidSdkInt(device)).sdkInt, expected); | ||
| assert.deepEqual(calls, [['shell', 'getprop', 'ro.build.version.sdk']]); | ||
| }, | ||
| ); | ||
| }, | ||
| ); |
Uh oh!
There was an error while loading. Please reload this page.