diff --git a/src/electron/platform/android/setup/android-setup-steps-configs.ts b/src/electron/platform/android/setup/android-setup-steps-configs.ts index be84288b493..71950e8512b 100644 --- a/src/electron/platform/android/setup/android-setup-steps-configs.ts +++ b/src/electron/platform/android/setup/android-setup-steps-configs.ts @@ -5,11 +5,14 @@ import { AndroidSetupActions } from 'electron/flux/action/android-setup-actions' import { AndroidSetupStoreCallbacks } from 'electron/flux/types/android-setup-state-machine-types'; import { AndroidSetupDeps } from 'electron/platform/android/setup/android-setup-deps'; import { AndroidSetupStepId } from 'electron/platform/android/setup/android-setup-step-id'; +import { detectDevices } from 'electron/platform/android/setup/steps/detect-devices'; +import { promptConnectToDevice } from 'electron/platform/android/setup/steps/prompt-connect-to-device'; +import { promptLocateAdb } from 'electron/platform/android/setup/steps/prompt-locate-adb'; import { StateMachineStepConfig, StateMachineStepConfigs, } from './state-machine/state-machine-step-configs'; -import { detectAdb } from './steps/detect.adb'; +import { detectAdb } from './steps/detect-adb'; export type AndroidSetupStepConfigDeps = AndroidSetupDeps & AndroidSetupStoreCallbacks; @@ -26,9 +29,9 @@ type AndroidSetupStepConfigs = StateMachineStepConfigs< export const allAndroidSetupStepConfigs: AndroidSetupStepConfigs = { 'detect-adb': detectAdb, - 'prompt-locate-adb': null, - 'prompt-connect-to-device': null, - 'detect-devices': null, + 'prompt-locate-adb': promptLocateAdb, + 'prompt-connect-to-device': promptConnectToDevice, + 'detect-devices': detectDevices, 'prompt-choose-device': null, 'detect-service': null, 'prompt-install-service': null, diff --git a/src/electron/platform/android/setup/steps/detect.adb.ts b/src/electron/platform/android/setup/steps/detect-adb.ts similarity index 80% rename from src/electron/platform/android/setup/steps/detect.adb.ts rename to src/electron/platform/android/setup/steps/detect-adb.ts index 9d12823bd99..4ba78040865 100644 --- a/src/electron/platform/android/setup/steps/detect.adb.ts +++ b/src/electron/platform/android/setup/steps/detect-adb.ts @@ -7,6 +7,6 @@ export const detectAdb: AndroidSetupStepConfig = deps => ({ actions: {}, onEnter: async () => { const detected = await deps.hasAdbPath(); - deps.stepTransition(detected ? 'detect-devices' : 'prompt-locate-adb'); + deps.stepTransition(detected ? 'prompt-connect-to-device' : 'prompt-locate-adb'); }, }); diff --git a/src/electron/platform/android/setup/steps/detect-devices.ts b/src/electron/platform/android/setup/steps/detect-devices.ts new file mode 100644 index 00000000000..309532fd41b --- /dev/null +++ b/src/electron/platform/android/setup/steps/detect-devices.ts @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { AndroidSetupStepConfig } from 'electron/platform/android/setup/android-setup-steps-configs'; + +export const detectDevices: AndroidSetupStepConfig = deps => { + return { + actions: { + cancel: () => { + deps.stepTransition('prompt-connect-to-device'); + }, + }, + onEnter: async () => { + const devices = await deps.getDevices(); + + switch (devices.length) { + case 0: { + deps.stepTransition('prompt-connect-to-device'); + break; + } + case 1: { + deps.setSelectedDeviceId(devices[0].id); + deps.stepTransition('detect-service'); + break; + } + default: { + deps.stepTransition('prompt-choose-device'); + break; + } + } + }, + }; +}; diff --git a/src/electron/platform/android/setup/steps/prompt-connect-to-device.ts b/src/electron/platform/android/setup/steps/prompt-connect-to-device.ts new file mode 100644 index 00000000000..969c28a0d9f --- /dev/null +++ b/src/electron/platform/android/setup/steps/prompt-connect-to-device.ts @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { AndroidSetupStepConfig } from 'electron/platform/android/setup/android-setup-steps-configs'; + +export const promptConnectToDevice: AndroidSetupStepConfig = deps => { + return { + actions: { + next: () => deps.stepTransition('detect-devices'), + }, + }; +}; diff --git a/src/electron/platform/android/setup/steps/prompt-locate-adb.ts b/src/electron/platform/android/setup/steps/prompt-locate-adb.ts new file mode 100644 index 00000000000..38db3d2e70a --- /dev/null +++ b/src/electron/platform/android/setup/steps/prompt-locate-adb.ts @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { AndroidSetupStepConfig } from 'electron/platform/android/setup/android-setup-steps-configs'; + +export const promptLocateAdb: AndroidSetupStepConfig = deps => { + return { + actions: { + saveAdbPath: (path: string) => { + deps.setAdbPath(path); + deps.stepTransition('prompt-connect-to-device'); + }, + }, + }; +}; diff --git a/src/tests/unit/tests/electron/platform/android/setup/steps/detect-adb.test.ts b/src/tests/unit/tests/electron/platform/android/setup/steps/detect-adb.test.ts index 04fff5fbb13..5cfb9aacc53 100644 --- a/src/tests/unit/tests/electron/platform/android/setup/steps/detect-adb.test.ts +++ b/src/tests/unit/tests/electron/platform/android/setup/steps/detect-adb.test.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import { AndroidSetupStepConfigDeps } from 'electron/platform/android/setup/android-setup-steps-configs'; -import { detectAdb } from 'electron/platform/android/setup/steps/detect.adb'; +import { detectAdb } from 'electron/platform/android/setup/steps/detect-adb'; import { Mock, MockBehavior, Times } from 'typemoq'; import { checkExpectedActionsAreDefined } from './actions-tester'; @@ -14,7 +14,7 @@ describe('Android setup step: detectAdb', () => { expect(step.onEnter).toBeDefined(); }); - it('onEnter transitions to detect-devices as expected', async () => { + it('onEnter transitions to prompt-connect-to-device as expected', async () => { const p = new Promise(resolve => resolve(true)); const depsMock = Mock.ofType(undefined, MockBehavior.Strict); @@ -23,7 +23,7 @@ describe('Android setup step: detectAdb', () => { .returns(_ => p) .verifiable(Times.once()); - depsMock.setup(m => m.stepTransition('detect-devices')).verifiable(Times.once()); + depsMock.setup(m => m.stepTransition('prompt-connect-to-device')).verifiable(Times.once()); const step = detectAdb(depsMock.object); await step.onEnter(); diff --git a/src/tests/unit/tests/electron/platform/android/setup/steps/detect-devices.test.ts b/src/tests/unit/tests/electron/platform/android/setup/steps/detect-devices.test.ts new file mode 100644 index 00000000000..912be8b02ff --- /dev/null +++ b/src/tests/unit/tests/electron/platform/android/setup/steps/detect-devices.test.ts @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { DeviceInfo } from 'electron/platform/android/android-service-configurator'; +import { AndroidSetupStepConfigDeps } from 'electron/platform/android/setup/android-setup-steps-configs'; +import { detectDevices } from 'electron/platform/android/setup/steps/detect-devices'; +import { Mock, MockBehavior, Times } from 'typemoq'; +import { checkExpectedActionsAreDefined } from './actions-tester'; + +describe('Android setup step: detectDevices', () => { + it('has expected properties', () => { + const deps = {} as AndroidSetupStepConfigDeps; + const step = detectDevices(deps); + checkExpectedActionsAreDefined(step, ['cancel']); + expect(step.onEnter).toBeDefined(); + }); + + it('cancel transitions to prompt-connect-to-device as expected', () => { + const depsMock = Mock.ofType(undefined, MockBehavior.Strict); + depsMock.setup(m => m.stepTransition('prompt-connect-to-device')).verifiable(Times.once()); + + const step = detectDevices(depsMock.object); + step.actions.cancel(); + + depsMock.verifyAll(); + }); + + it('onEnter transitions to prompt-connect-to-device as expected', async () => { + const devices: DeviceInfo[] = []; + const p = new Promise(resolve => resolve(devices)); + + const depsMock = Mock.ofType(undefined, MockBehavior.Strict); + depsMock + .setup(m => m.getDevices()) + .returns(_ => p) + .verifiable(Times.once()); + + depsMock.setup(m => m.stepTransition('prompt-connect-to-device')).verifiable(Times.once()); + + const step = detectDevices(depsMock.object); + await step.onEnter(); + + depsMock.verifyAll(); + }); + + it('onEnter transitions to detect-service as expected', async () => { + const devices: DeviceInfo[] = [ + { + id: 'device1', + } as DeviceInfo, + ]; + + const p = new Promise(resolve => resolve(devices)); + + const depsMock = Mock.ofType(undefined, MockBehavior.Strict); + depsMock + .setup(m => m.getDevices()) + .returns(_ => p) + .verifiable(Times.once()); + + depsMock.setup(m => m.stepTransition('detect-service')).verifiable(Times.once()); + depsMock.setup(m => m.setSelectedDeviceId('device1')).verifiable(Times.once()); + + const step = detectDevices(depsMock.object); + await step.onEnter(); + + depsMock.verifyAll(); + }); + + it('onEnter transitions to prompt-choose-device as expected', async () => { + const devices: DeviceInfo[] = [ + { + id: 'device1', + } as DeviceInfo, + { + id: 'device2', + } as DeviceInfo, + ]; + + const p = new Promise(resolve => resolve(devices)); + + const depsMock = Mock.ofType(undefined, MockBehavior.Strict); + depsMock + .setup(m => m.getDevices()) + .returns(_ => p) + .verifiable(Times.once()); + + depsMock.setup(m => m.stepTransition('prompt-choose-device')).verifiable(Times.once()); + + const step = detectDevices(depsMock.object); + await step.onEnter(); + + depsMock.verifyAll(); + }); +}); diff --git a/src/tests/unit/tests/electron/platform/android/setup/steps/prompt-connect-to-device.test.ts b/src/tests/unit/tests/electron/platform/android/setup/steps/prompt-connect-to-device.test.ts new file mode 100644 index 00000000000..8f837faf051 --- /dev/null +++ b/src/tests/unit/tests/electron/platform/android/setup/steps/prompt-connect-to-device.test.ts @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { AndroidSetupStepConfigDeps } from 'electron/platform/android/setup/android-setup-steps-configs'; +import { promptConnectToDevice } from 'electron/platform/android/setup/steps/prompt-connect-to-device'; +import { Mock, MockBehavior, Times } from 'typemoq'; +import { checkExpectedActionsAreDefined } from './actions-tester'; + +describe('Android setup step: promptConnectToDevice', () => { + it('has expected properties', () => { + const deps = {} as AndroidSetupStepConfigDeps; + const step = promptConnectToDevice(deps); + checkExpectedActionsAreDefined(step, ['next']); + expect(step.onEnter).not.toBeDefined(); + }); + + it('next transitions to detect-devices as expected', () => { + const depsMock = Mock.ofType(undefined, MockBehavior.Strict); + depsMock.setup(m => m.stepTransition('detect-devices')).verifiable(Times.once()); + + const step = promptConnectToDevice(depsMock.object); + step.actions.next(); + + depsMock.verifyAll(); + }); +}); diff --git a/src/tests/unit/tests/electron/platform/android/setup/steps/prompt-locate-adb.test.ts b/src/tests/unit/tests/electron/platform/android/setup/steps/prompt-locate-adb.test.ts new file mode 100644 index 00000000000..491d4fb1094 --- /dev/null +++ b/src/tests/unit/tests/electron/platform/android/setup/steps/prompt-locate-adb.test.ts @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { AndroidSetupStepConfigDeps } from 'electron/platform/android/setup/android-setup-steps-configs'; +import { promptLocateAdb } from 'electron/platform/android/setup/steps/prompt-locate-adb'; +import { Mock, MockBehavior, Times } from 'typemoq'; +import { checkExpectedActionsAreDefined } from './actions-tester'; + +describe('Android setup step: promptLocateAdb', () => { + it('has expected properties', () => { + const deps = {} as AndroidSetupStepConfigDeps; + const step = promptLocateAdb(deps); + checkExpectedActionsAreDefined(step, ['saveAdbPath']); + expect(step.onEnter).not.toBeDefined(); + }); + + it('saveAdbPath transitions to prompt-connect-to-device as expected', () => { + const testPath = 'my test path'; + + const depsMock = Mock.ofType(undefined, MockBehavior.Strict); + depsMock.setup(m => m.setAdbPath(testPath)).verifiable(Times.once()); + depsMock.setup(m => m.stepTransition('prompt-connect-to-device')).verifiable(Times.once()); + + const step = promptLocateAdb(depsMock.object); + step.actions.saveAdbPath(testPath); + + depsMock.verifyAll(); + }); +});