Skip to content

Commit

Permalink
Move openURL and sendUserNotification to deliverPayload
Browse files Browse the repository at this point in the history
Add test for including more than one payload
  • Loading branch information
LeoNatan committed Mar 14, 2018
1 parent 69cd84c commit a45b04c
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 99 deletions.
63 changes: 33 additions & 30 deletions detox/ios/Detox/DetoxManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -124,45 +124,48 @@ - (void)websocketDidReceiveAction:(NSString *)type withParams:(NSDictionary *)pa
[self.webSocket sendAction:@"cleanupDone" withParams:@{} withMessageId:messageId];
return;
}
else if([type isEqualToString:@"userNotification"])
else if([type isEqualToString:@"deliverPayload"])
{
NSURL* userNotificationDataURL = [NSURL fileURLWithPath:params[@"detoxUserNotificationDataURL"]];
BOOL delay = [params[@"delayPayload"] boolValue];

void (^block)(void) = ^{
[DetoxAppDelegateProxy.currentAppDelegateProxy dispatchUserNotificationFromDataURL:userNotificationDataURL delayUntilActive:delay];
[self.webSocket sendAction:@"userNotificationDone" withParams:@{} withMessageId: messageId];
void (^block)(void);
//Send webSocket and messageId as params so the block is of global type, instead of being allocated on every message.
void (^sendDoneAction)(WebSocket* webSocket, NSNumber* messageId) = ^ (WebSocket* webSocket, NSNumber* messageId) {
[webSocket sendAction:@"deliverPayloadDone" withParams:@{} withMessageId: messageId];
};

if(delay == YES)
if(params[@"url"])
{
block();
return;
NSURL* URLToOpen = [NSURL URLWithString:params[@"url"]];

NSParameterAssert(URLToOpen != nil);

NSString* sourceApp = params[@"sourceApp"];

NSMutableDictionary* options = [@{UIApplicationLaunchOptionsURLKey: URLToOpen} mutableCopy];
if(sourceApp != nil)
{
options[UIApplicationLaunchOptionsSourceApplicationKey] = sourceApp;
}

block = ^{
[DetoxAppDelegateProxy.currentAppDelegateProxy dispatchOpenURL:URLToOpen options:options delayUntilActive:delay];

sendDoneAction(self.webSocket, messageId);
};
}

[EarlGrey detox_safeExecuteSync:block];
}
else if([type isEqualToString:@"openURL"])
{
NSURL* URLToOpen = [NSURL URLWithString:params[@"url"]];
BOOL delay = [params[@"delayPayload"] boolValue];

NSParameterAssert(URLToOpen != nil);

NSString* sourceApp = params[@"sourceApp"];

NSMutableDictionary* options = [@{UIApplicationLaunchOptionsURLKey: URLToOpen} mutableCopy];
if(sourceApp != nil)
else if(params[@"detoxUserNotificationDataURL"])
{
options[UIApplicationLaunchOptionsSourceApplicationKey] = sourceApp;
}

void (^block)(void) = ^{
[DetoxAppDelegateProxy.currentAppDelegateProxy dispatchOpenURL:URLToOpen options:options delayUntilActive:delay];
NSURL* userNotificationDataURL = [NSURL fileURLWithPath:params[@"detoxUserNotificationDataURL"]];

[self.webSocket sendAction:@"openURLDone" withParams:@{} withMessageId: messageId];
};
NSParameterAssert(userNotificationDataURL != nil);

block = ^{
[DetoxAppDelegateProxy.currentAppDelegateProxy dispatchUserNotificationFromDataURL:userNotificationDataURL delayUntilActive:delay];

sendDoneAction(self.webSocket, messageId);
};
}

if(delay == YES)
{
Expand Down
8 changes: 2 additions & 6 deletions detox/src/client/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ class Client {
await this.sendAction(new actions.ReloadReactNative());
}

async sendUserNotification(params) {
await this.sendAction(new actions.SendUserNotification(params));
}

async waitUntilReady() {
await this.sendAction(new actions.Ready());
this.isConnected = true;
Expand All @@ -56,8 +52,8 @@ class Client {
await this.sendAction(new actions.Shake());
}

async openURL(params) {
await this.sendAction(new actions.OpenURL(params));
async deliverPayload(params) {
await this.sendAction(new actions.DeliverPayload(params));
}

async execute(invocation) {
Expand Down
14 changes: 3 additions & 11 deletions detox/src/client/Client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,10 @@ describe('Client', () => {
}
});

it(`sendUserNotification() - should receive ready from device and resolve`, async () => {
it(`deliverPayload() - should send an 'deliverPayload' action and resolve when 'deliverPayloadDone' returns`, async () => {
await connect();
client.ws.send.mockReturnValueOnce(response("userNotificationDone", {}, 1));
await client.sendUserNotification();

expect(client.ws.send).toHaveBeenCalledTimes(2);
});

it(`openURL() - should send an 'openURL' action and resolve when 'openURLDone' returns`, async () => {
await connect();
client.ws.send.mockReturnValueOnce(response("openURLDone", {}, 1));
await client.openURL({url: 'url'});
client.ws.send.mockReturnValueOnce(response("deliverPayloadDone", {}, 1));
await client.deliverPayload({url: 'url'});

expect(client.ws.send).toHaveBeenCalledTimes(2);
});
Expand Down
19 changes: 4 additions & 15 deletions detox/src/client/actions/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,23 +93,13 @@ class Invoke extends Action {
}
}

class SendUserNotification extends Action {
class DeliverPayload extends Action {
constructor(params) {
super('userNotification', params);
super('deliverPayload', params);
}

async handle(response) {
this.expectResponseOfType(response, 'userNotificationDone');
}
}

class OpenURL extends Action {
constructor(params) {
super('openURL', params);
}

async handle(response) {
this.expectResponseOfType(response, 'openURLDone');
this.expectResponseOfType(response, 'deliverPayloadDone');
}
}

Expand Down Expand Up @@ -147,8 +137,7 @@ module.exports = {
Invoke,
ReloadReactNative,
Cleanup,
OpenURL,
SendUserNotification,
DeliverPayload,
CurrentStatus,
Shake,
AppWillTerminateWithError
Expand Down
30 changes: 20 additions & 10 deletions detox/src/devices/Device.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,18 @@ class Device {

async launchApp(params = {newInstance: false}, bundleId) {
await this._artifactsCopier.handleAppRelaunch();

if (params.url && params.userNotification) {
throw new Error(`Call to 'launchApp(${JSON.stringify(params)})' cannot contain both url and userNotification payloads.`);

let paramsCounter = 0;

const singleParams = ['url', 'userNotification'];
singleParams.forEach((item) => {
if(params[item]) {
paramsCounter += 1;
}
})

if (paramsCounter > 1) {
throw new Error(`Call to 'launchApp(${JSON.stringify(params)})' must contain only one of ${JSON.stringify(singleParams)}.`);
}

if (params.delete) {
Expand All @@ -69,6 +78,9 @@ class Device {
} else if (params.userNotification) {
const notificationFilePath = this.deviceDriver.createPushNotificationJson(params.userNotification);
baseLaunchArgs['detoxUserNotificationDataURL'] = notificationFilePath;
//`params` will be used later for `deliverPayload`, so remove the actual notification and add the file URL
delete params.userNotification;
params.detoxUserNotificationDataURL = notificationFilePath;
}

if (params.permissions) {
Expand All @@ -77,11 +89,9 @@ class Device {

const _bundleId = bundleId || this._bundleId;
if (this._isAppInBackground(params, _bundleId)) {
if (params.url) {
await this.openURL({...params, delayPayload: true});
} else if (params.userNotification) {
await this.deviceDriver.sendUserNotification({...baseLaunchArgs, delayPayload: true});
}
if (params.url || params.detoxUserNotificationDataURL) {
await this.deviceDriver.deliverPayload({...params, delayPayload: true});
}
}

const processId = await this.deviceDriver.launch(this._deviceId, _bundleId, this._prepareLaunchArgs(baseLaunchArgs));
Expand Down Expand Up @@ -134,7 +144,7 @@ class Device {
throw new Error(`openURL must be called with JSON params, and a value for 'url' key must be provided. example: await device.openURL({url: "url", sourceApp[optional]: "sourceAppBundleID"}`);
}

await this.deviceDriver.openURL(this._deviceId, params);
await this.deviceDriver.deliverPayload(params);
}

async shutdown() {
Expand All @@ -153,7 +163,7 @@ class Device {

async sendUserNotification(params) {
const notificationFilePath = this.deviceDriver.createPushNotificationJson(params);
await this.deviceDriver.sendUserNotification({'detoxUserNotificationDataURL': notificationFilePath});
await this.deviceDriver.deliverPayload({'detoxUserNotificationDataURL': notificationFilePath});
}

async setURLBlacklist(urlList) {
Expand Down
42 changes: 31 additions & 11 deletions detox/src/devices/Device.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ describe('Device', () => {
device = validDevice();
await device.openURL({url: 'url'});

expect(device.deviceDriver.openURL).toHaveBeenCalledWith(device._deviceId, {url: 'url'});
expect(device.deviceDriver.deliverPayload).toHaveBeenCalledWith({url: 'url'});
});

it(`openURL(notAnObject) should pass to device driver`, async () => {
Expand Down Expand Up @@ -353,7 +353,7 @@ describe('Device', () => {
await device.sendUserNotification('notif');

expect(device.deviceDriver.createPushNotificationJson).toHaveBeenCalledTimes(1)
expect(device.deviceDriver.sendUserNotification).toHaveBeenCalledTimes(1);
expect(device.deviceDriver.deliverPayload).toHaveBeenCalledTimes(1);
});

it(`setLocation() should pass to device driver`, async () => {
Expand Down Expand Up @@ -466,8 +466,7 @@ describe('Device', () => {
await device.prepare({launchApp: true});
await device.launchApp({newInstance: false});

expect(device.deviceDriver.openURL).not.toHaveBeenCalled();
expect(device.deviceDriver.sendUserNotification).not.toHaveBeenCalled();
expect(device.deviceDriver.deliverPayload).not.toHaveBeenCalled();
});

it(`launchApp({url: url}) should check if process is in background and use openURL() instead of launch args`, async () => {
Expand All @@ -479,7 +478,7 @@ describe('Device', () => {
await device.prepare({launchApp: true});
await device.launchApp({url: 'url://me'});

expect(device.deviceDriver.openURL).toHaveBeenCalledTimes(1);
expect(device.deviceDriver.deliverPayload).toHaveBeenCalledTimes(1);
});

it(`launchApp({url: url}) should check if process is in background and if not use launch args`, async () => {
Expand All @@ -494,7 +493,7 @@ describe('Device', () => {
await device.prepare();
await device.launchApp(launchParams);

expect(device.deviceDriver.openURL).toHaveBeenCalledTimes(0);
expect(device.deviceDriver.deliverPayload).not.toHaveBeenCalled();
});

it(`launchApp({url: url}) should check if process is in background and use openURL() instead of launch args`, async () => {
Expand All @@ -508,24 +507,25 @@ describe('Device', () => {
await device.prepare({launchApp: true});
await device.launchApp(launchParams);

expect(device.deviceDriver.openURL).toHaveBeenCalledTimes(1);
expect(device.deviceDriver.deliverPayload).toHaveBeenCalledTimes(1);
});

it(`launchApp({userNotification:userNotification}) should check if process is in background and if it is use sendUserNotification`, async () => {
it(`launchApp({userNotification:userNotification}) should check if process is in background and if it is use deliverPayload`, async () => {
const launchParams = {userNotification: 'notification'};
const processId = 1;

device = validDevice();
device.deviceDriver.getBundleIdFromBinary.mockReturnValue('test.bundle');
device.deviceDriver.launch.mockReturnValueOnce(processId).mockReturnValueOnce(processId);
device.deviceDriver.createPushNotificationJson = () => "url";

await device.prepare({launchApp: true});
await device.launchApp(launchParams);

expect(device.deviceDriver.sendUserNotification).toHaveBeenCalledTimes(1);
expect(device.deviceDriver.deliverPayload).toHaveBeenCalledTimes(1);
});

it(`launchApp({userNotification:userNotification}) should check if process is in background and if not use launch args`, async () => {
it(`launchApp({userNotification: userNotification}) should check if process is in background and if not use launch args`, async () => {
const launchParams = {userNotification: 'notification'};
const processId = 1;
const newProcessId = 2;
Expand All @@ -537,7 +537,27 @@ describe('Device', () => {
await device.prepare();
await device.launchApp(launchParams);

expect(device.deviceDriver.sendUserNotification).toHaveBeenCalledTimes(0);
expect(device.deviceDriver.deliverPayload).not.toHaveBeenCalled();
});

it(`launchApp({userNotification: userNotification, url: url}) should fail`, async () => {
const launchParams = {userNotification: 'notification', url: 'url://me'};
const processId = 1;

device = validDevice();
device.deviceDriver.getBundleIdFromBinary.mockReturnValue('test.bundle');
device.deviceDriver.launch.mockReturnValueOnce(processId).mockReturnValueOnce(processId);

await device.prepare();

try {
await device.launchApp(launchParams);
fail('should throw');
} catch (ex) {
expect(ex).toBeDefined();
}

expect(device.deviceDriver.deliverPayload).not.toHaveBeenCalled();
});

async function launchAndTestBinaryPath(configuration) {
Expand Down
8 changes: 2 additions & 6 deletions detox/src/devices/DeviceDriverBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class DeviceDriverBase {
return await Promise.resolve('');
}

async openURL(params) {
return await Promise.resolve('');
async deliverPayload(params) {
return await this.client.deliverPayload(params);
}

async setLocation(lat, lon) {
Expand All @@ -59,10 +59,6 @@ class DeviceDriverBase {
return await this.client.reloadReactNative();
}

async sendUserNotification(params) {
await this.client.sendUserNotification(params);
}

createPushNotificationJson(notification) {

}
Expand Down
4 changes: 0 additions & 4 deletions detox/src/devices/IosDriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ class IosDriver extends DeviceDriverBase {
return notificationFilePath;
}

async openURL(deviceId, params) {
await this.client.openURL(params);
}

async setURLBlacklist(urlList) {
await this.client.execute(GREYConfiguration.setURLBlacklist(urlList));
}
Expand Down
4 changes: 2 additions & 2 deletions detox/test/e2e/k-user-notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ describe(':ios: User Notifications', () => {
await expect(element(by.text('From calendar'))).toBeVisible();
});

it('Background push notification', async () => {
it.only('Background push notification', async () => {
await device.launchApp({newInstance: true});
await device.sendToHome();
await device.launchApp({newInstance: false, userNotification: userNotificationPushTrigger});
await expect(element(by.text('From push'))).toBeVisible();
});

it('Background calendar notification', async () => {
it.only('Background calendar notification', async () => {
await device.launchApp({newInstance: true});
await device.sendToHome();
await device.launchApp({newInstance: false, userNotification: userNotificationCalendarTrigger});
Expand Down
Loading

0 comments on commit a45b04c

Please sign in to comment.