Skip to content
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

feat(android-setup): Add code to set the app name from the device in the setup store #2911

Merged
merged 5 commits into from
Jun 19, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/electron/flux/store/android-setup-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class AndroidSetupStore extends BaseStoreImpl<AndroidSetupStoreData> {
stepTransition: this.stepTransition,
setSelectedDevice: this.setSelectedDevice,
setAvailableDevices: this.setAvailableDevices,
setApplicationName: this.setApplicationName,
});
}

Expand Down Expand Up @@ -67,4 +68,9 @@ export class AndroidSetupStore extends BaseStoreImpl<AndroidSetupStoreData> {
// emitChange will be called from step transition when the step changes
this.state.availableDevices = devices;
};

private setApplicationName = (appName?: string): void => {
// emitChange will be called from step transition when the step changes
this.state.applicationName = appName;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type AndroidSetupStoreCallbacks = {
stepTransition: AndroidSetupStepTransitionCallback;
setSelectedDevice: (device: DeviceInfo) => void;
setAvailableDevices: (devices: DeviceInfo[]) => void;
setApplicationName: (appName?: string) => void;
};

export type AndroidSetupStateMachineFactory = (
Expand Down
2 changes: 2 additions & 0 deletions src/electron/flux/types/android-setup-store-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ export type AndroidSetupStoreData = {
selectedDevice?: DeviceInfo;

availableDevices?: DeviceInfo[];

applicationName?: string;
};
1 change: 1 addition & 0 deletions src/electron/platform/android/setup/android-setup-deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export type AndroidSetupDeps = {
installService: () => Promise<boolean>;
hasExpectedPermissions: () => Promise<boolean>;
setTcpForwarding: () => Promise<boolean>;
getApplicationName: () => Promise<string>;
};
13 changes: 13 additions & 0 deletions src/electron/platform/android/setup/live-android-setup-deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
PackageInfo,
PermissionInfo,
} from 'electron/platform/android/android-service-configurator';
import { DeviceConfigFetcher } from 'electron/platform/android/device-config-fetcher';
import { AndroidSetupDeps } from 'electron/platform/android/setup/android-setup-deps';

export class LiveAndroidSetupDeps implements AndroidSetupDeps {
Expand All @@ -23,6 +24,7 @@ export class LiveAndroidSetupDeps implements AndroidSetupDeps {
private readonly configStore: UserConfigurationStore,
private readonly apkLocator: AndroidServiceApkLocator,
private readonly userConfigMessageCreator: UserConfigMessageCreator,
private readonly fetchDeviceConfig: DeviceConfigFetcher,
private readonly logger: Logger,
) {}

Expand Down Expand Up @@ -101,6 +103,17 @@ export class LiveAndroidSetupDeps implements AndroidSetupDeps {
return false;
};

public getApplicationName = async (): Promise<string> => {
try {
const config = await this.fetchDeviceConfig(62442);
return config.appIdentifier;
} catch (error) {
this.logger.log(error);
}

return '';
};

private async getInstalledVersion(): Promise<string> {
const info: PackageInfo = await this.serviceConfig.getPackageInfo(this.selectedDeviceId);
return info?.versionName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@ import { AndroidSetupStepConfig } from 'electron/platform/android/setup/android-
export const configuringPortForwarding: AndroidSetupStepConfig = deps => ({
actions: {},
onEnter: async () => {
deps.setApplicationName(); // init

const configured = await deps.setTcpForwarding();
deps.stepTransition(
configured
? 'prompt-connected-start-testing'
: 'prompt-configuring-port-forwarding-failed',
);

if (configured === false) {
deps.stepTransition('prompt-configuring-port-forwarding-failed');
return;
}

// device is good to go; so we can get the current app name
const appName = await deps.getApplicationName();
deps.setApplicationName(appName);
deps.stepTransition('prompt-connected-start-testing');
},
});
5 changes: 4 additions & 1 deletion src/electron/views/renderer-initializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,12 @@ getPersistedData(indexedDBInstance, indexedDBDataKeysToFetch).then(
const dispatcher = new DirectActionMessageDispatcher(interpreter);
const userConfigMessageCreator = new UserConfigMessageCreator(dispatcher);

const fetchDeviceConfig = createDeviceConfigFetcher(axios.get);

const apkLocator: AndroidServiceApkLocator = new AndroidServiceApkLocator(
ipcRendererShim.getAppPath,
);

const androidSetupStore = new AndroidSetupStore(
androidSetupActions,
createAndroidSetupStateMachineFactory(
Expand All @@ -205,6 +208,7 @@ getPersistedData(indexedDBInstance, indexedDBDataKeysToFetch).then(
userConfigurationStore,
apkLocator,
userConfigMessageCreator,
fetchDeviceConfig,
logger,
),
),
Expand Down Expand Up @@ -258,7 +262,6 @@ getPersistedData(indexedDBInstance, indexedDBDataKeysToFetch).then(
]);

const fetchScanResults = createScanResultsFetcher(axios.get);
const fetchDeviceConfig = createDeviceConfigFetcher(axios.get);

const featureFlagsController = new FeatureFlagsController(featureFlagStore, interpreter);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,36 @@ describe('AndroidSetupStore', () => {
stateMachineFactoryMock.verifyAll();
});

it('ensure setApplicationName function results in store update', () => {
const appName = 'Star Wars -- Episode Test';

const initialData: AndroidSetupStoreData = { currentStepId: 'detect-adb' };
const expectedData: AndroidSetupStoreData = {
currentStepId: 'detect-adb',
applicationName: appName,
};

let storeCallbacks: AndroidSetupStoreCallbacks;

const stateMachineFactoryMock = Mock.ofInstance(mockableStateMachineFactory);
stateMachineFactoryMock
.setup(m => m(It.isAny()))
.callback(sc => (storeCallbacks = sc))
.verifiable(Times.once());

const store = new AndroidSetupStore(
new AndroidSetupActions(),
stateMachineFactoryMock.object,
);
store.initialize(initialData);

storeCallbacks.setApplicationName(appName);

expect(store.getState()).toEqual(expectedData);

stateMachineFactoryMock.verifyAll();
});

const createAndroidSetupStoreTester = (
actionToInvoke: keyof AndroidSetupActions,
stateMachineFactory: AndroidSetupStateMachineFactory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
PackageInfo,
PermissionInfo,
} from 'electron/platform/android/android-service-configurator';
import { DeviceConfig } from 'electron/platform/android/device-config';
import { DeviceConfigFetcher } from 'electron/platform/android/device-config-fetcher';
import { LiveAndroidSetupDeps } from 'electron/platform/android/setup/live-android-setup-deps';
import { IMock, Mock, MockBehavior, Times } from 'typemoq';

Expand All @@ -27,6 +29,7 @@ describe('LiveAndroidSetupDeps', () => {
let configStoreMock: IMock<UserConfigurationStore>;
let apkLocatorMock: IMock<AndroidServiceApkLocator>;
let configMessageCreatorMock: IMock<UserConfigMessageCreator>;
let fetchConfigMock: IMock<DeviceConfigFetcher>;
let loggerMock: IMock<Logger>;
let testSubject: LiveAndroidSetupDeps;

Expand All @@ -42,12 +45,14 @@ describe('LiveAndroidSetupDeps', () => {
undefined,
MockBehavior.Strict,
);
fetchConfigMock = Mock.ofInstance((port: number) => new Promise<DeviceConfig>(() => null));
loggerMock = Mock.ofType<Logger>();
testSubject = new LiveAndroidSetupDeps(
serviceConfigFactoryMock.object,
configStoreMock.object,
apkLocatorMock.object,
configMessageCreatorMock.object,
fetchConfigMock.object,
loggerMock.object,
);
});
Expand Down Expand Up @@ -418,6 +423,25 @@ describe('LiveAndroidSetupDeps', () => {
verifyAllMocks();
});

it('getApplicationName returns app name when successful', async () => {
const config: DeviceConfig = {
appIdentifier: 'Wonderful App',
} as DeviceConfig;

const p = new Promise<DeviceConfig>(resolve => resolve(config));

fetchConfigMock
.setup(m => m(62442))
.returns(() => p)
.verifiable();

const appName = await testSubject.getApplicationName();

expect(appName).toEqual(config.appIdentifier);

verifyAllMocks();
});

it('setTcpForwarding returns true if no error', async () => {
serviceConfigMock.setup(m => m.setTcpForwarding(undefined)).verifiable(Times.once());
await initializeServiceConfig();
Expand All @@ -428,4 +452,17 @@ describe('LiveAndroidSetupDeps', () => {

verifyAllMocks();
});

it('getApplicationName returns epty string on error', async () => {
RobGallo marked this conversation as resolved.
Show resolved Hide resolved
fetchConfigMock
.setup(m => m(62442))
.throws(Error('some error'))
.verifiable();

const appName = await testSubject.getApplicationName();

expect(appName).toEqual('');

verifyAllMocks();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,27 @@ describe('Android setup step: configuringPortForwarding', () => {
});

it('onEnter transitions to prompt-connected-start-testing on success', async () => {
const p = new Promise<boolean>(resolve => resolve(true));
const appName = 'my app name';

const tcpForwardingPromise = new Promise<boolean>(resolve => resolve(true));
const appNamePromise = new Promise<string>(resolve => resolve(appName));

const depsMock = Mock.ofType<AndroidSetupStepConfigDeps>(undefined, MockBehavior.Strict);
depsMock
.setup(m => m.setTcpForwarding())
.returns(_ => p)
.returns(_ => tcpForwardingPromise)
.verifiable(Times.once());

depsMock.setup(m => m.stepTransition('prompt-connected-start-testing'));

depsMock
.setup(m => m.stepTransition('prompt-connected-start-testing'))
.setup(m => m.getApplicationName())
.returns(_ => appNamePromise)
.verifiable(Times.once());

depsMock.setup(m => m.setApplicationName(undefined)).verifiable(Times.once());
depsMock.setup(m => m.setApplicationName(appName)).verifiable(Times.once());

const step = configuringPortForwarding(depsMock.object);
await step.onEnter();

Expand All @@ -42,6 +51,8 @@ describe('Android setup step: configuringPortForwarding', () => {
.returns(_ => p)
.verifiable(Times.once());

depsMock.setup(m => m.setApplicationName(undefined)).verifiable(Times.once());

depsMock
.setup(m => m.stepTransition('prompt-configuring-port-forwarding-failed'))
.verifiable(Times.once());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('Android setup step: detectPermissions', () => {
expect(step.onEnter).toBeDefined();
});

it('onEnter transitions to configuring-port-forwarding as expected', async () => {
it('onEnter transitions to configuring-port-forwarding on success', async () => {
const p = new Promise<boolean>(resolve => resolve(true));

const depsMock = Mock.ofType<AndroidSetupStepConfigDeps>(undefined, MockBehavior.Strict);
Expand All @@ -23,17 +23,15 @@ describe('Android setup step: detectPermissions', () => {
.returns(_ => p)
.verifiable(Times.once());

depsMock
.setup(m => m.stepTransition('configuring-port-forwarding'))
.verifiable(Times.once());
depsMock.setup(m => m.stepTransition('configuring-port-forwarding'));

const step = detectPermissions(depsMock.object);
await step.onEnter();

depsMock.verifyAll();
});

it('onEnter transitions to prompt-install-service as expected', async () => {
it('onEnter transitions to prompt-grant-permissions as expected', async () => {
RobGallo marked this conversation as resolved.
Show resolved Hide resolved
const p = new Promise<boolean>(resolve => resolve(false));

const depsMock = Mock.ofType<AndroidSetupStepConfigDeps>(undefined, MockBehavior.Strict);
Expand Down