Skip to content

Commit

Permalink
move device rotation to generated code
Browse files Browse the repository at this point in the history
Closes #719
  • Loading branch information
Daniel Schmidt committed May 26, 2018
1 parent 604649e commit d52fd53
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 23 deletions.
14 changes: 2 additions & 12 deletions detox/src/devices/IosDriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const InvocationManager = require('../invoke').InvocationManager;
const invoke = require('../invoke');
const GREYConfigurationApi = require('./../ios/earlgreyapi/GREYConfiguration');
const GREYConfigurationDetox = require('./../ios/earlgreyapi/GREYConfigurationDetox');
const EarlyGrey = require('./../ios/earlgreyapi/EarlGrey');

class IosDriver extends DeviceDriverBase {
constructor(client) {
Expand Down Expand Up @@ -55,19 +56,8 @@ class IosDriver extends DeviceDriverBase {
}

async setOrientation(deviceId, orientation) {
// keys are possible orientations
const orientationMapping = {
landscape: 3, // top at left side landscape
portrait: 1 // non-reversed portrait
};
if (!Object.keys(orientationMapping).includes(orientation)) {
throw new Error(`setOrientation failed: provided orientation ${orientation} is not part of supported orientations: ${Object.keys(orientationMapping)}`);
}
const call = EarlyGrey.rotateDeviceToOrientationErrorOrNil(invoke.EarlGrey.instance,orientation);

const call = invoke.call(invoke.EarlGrey.instance,
'rotateDeviceToOrientation:errorOrNil:',
invoke.IOS.NSInteger(orientationMapping[orientation])
);
await this.client.execute(call);
}

Expand Down
83 changes: 83 additions & 0 deletions detox/src/ios/earlgreyapi/EarlGrey.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
This code is generated.
For more information see generation/README.md.
*/


function sanitize_uiDeviceOrientation(value) {
const orientationMapping = {
landscape: 3, // top at left side landscape
portrait: 1 // non-reversed portrait
};

return orientationMapping[value];
}
class EarlGreyImpl {
/*Provides the file name and line number of the code that is calling into EarlGrey.
In case of a failure, the information is used to tell XCTest the exact line which caused
the failure so it can be highlighted in the IDE.
@param fileName The name of the file where the failing code exists.
@param lineNumber The line number of the failing code.
@return An EarlGreyImpl instance, with details of the code invoking EarlGrey.
*/static invokedFromFileLineNumber(fileName, lineNumber) {
if (typeof fileName !== "string") throw new Error("fileName should be a string, but got " + (fileName + (" (" + (typeof fileName + ")"))));
if (typeof lineNumber !== "number") throw new Error("lineNumber should be a number, but got " + (lineNumber + (" (" + (typeof lineNumber + ")"))));
return {
target: {
type: "Class",
value: "EarlGreyImpl"
},
method: "invokedFromFile:lineNumber:",
args: [{
type: "NSString",
value: fileName
}, {
type: "NSInteger",
value: lineNumber
}]
};
}

/*Rotate the device to a given @c deviceOrientation. All device orientations except for
@c UIDeviceOrientationUnknown are supported. If a non-nil @c errorOrNil is provided, it will
be populated with the failure reason if the orientation change fails, otherwise a test failure
will be registered.
@param deviceOrientation The desired orientation of the device.
@param[out] errorOrNil Error that will be populated on failure. If @c nil, a test
failure will be reported if the rotation attempt fails.
@return @c YES if the rotation was successful, @c NO otherwise.
*/static rotateDeviceToOrientationErrorOrNil(element, deviceOrientation) {
if (!["landscape", "portrait"].some(option => option === deviceOrientation)) throw new Error("deviceOrientation should be one of [landscape, portrait], but got " + deviceOrientation);
return {
target: element,
method: "rotateDeviceToOrientation:errorOrNil:",
args: [{
type: "NSInteger",
value: sanitize_uiDeviceOrientation(deviceOrientation)
}]
};
}

/*Dismisses the keyboard by resigning the first responder, if any. Will populate the provided
error if the first responder is not present or if the keyboard is not visible.
@param[out] errorOrNil Error that will be populated on failure. If @c nil, a test
failure will be reported if the dismissing fails.
@return @c YES if the dismissing of the keyboard was successful, @c NO otherwise.
*/static dismissKeyboardWithError(element) {
return {
target: element,
method: "dismissKeyboardWithError:",
args: []
};
}

}

module.exports = EarlGreyImpl;
40 changes: 40 additions & 0 deletions detox/src/ios/earlgreyapi/GREYInteraction.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,26 @@ performAction:grey_tap()] // This should be separately called for the action.
};
}

/*Performs an @c action on the selected UI element with an error set on failure.
@param action The action to be performed on the @c element.
@param[out] errorOrNil Error populated on failure.
@throws NSException on action failure if @c errorOrNil is not set.
@return The provided GREYInteraction instance, with an action and an error that will be
populated on failure.
*/static performActionError(element, action) {
if (typeof action !== "object" || action.type !== "Invocation" || typeof action.value !== "object" || typeof action.value.target !== "object" || action.value.target.value !== "GREYActions") {
throw new Error('action should be a GREYAction, but got ' + JSON.stringify(action));
}

return {
target: element,
method: "performAction:error:",
args: [action]
};
}

/*Performs an assertion that evaluates @c matcher on the selected UI element.
@param matcher The matcher to be evaluated on the @c element.
Expand All @@ -98,6 +118,26 @@ performAction:grey_tap()] // This should be separately called for the action.
};
}

/*Performs an assertion that evaluates @c matcher on the selected UI element.
@param matcher The matcher to be evaluated on the @c element.
@param[out] errorOrNil Error populated on failure.
@throws NSException on assertion failure if @c errorOrNil is not set.
@return The provided GREYInteraction instance, with a matcher to be evaluated on an element and
an error that will be populated on failure.
*/static assertWithMatcherError(element, matcher) {
if (typeof matcher !== "object" || matcher.type !== "Invocation" || typeof matcher.value !== "object" || typeof matcher.value.target !== "object" || matcher.value.target.value !== "GREYMatchers") {
throw new Error('matcher should be a GREYMatcher, but got ' + JSON.stringify(matcher));
}

return {
target: element,
method: "assertWithMatcher:error:",
args: [matcher]
};
}

/*In case of multiple matches, selects the element at the specified index. In case of the
index being over the number of matched elements, it throws an exception. Please make sure
that this is used after you've created the matcher. For example, in case three elements are
Expand Down
40 changes: 31 additions & 9 deletions generation/adapters/ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ const typeCheckInterfaces = {
'id<GREYMatcher>': isGreyMatcher,
'GREYElementInteraction*': isGreyElementInteraction,
UIAccessibilityTraits: isArray,
id: isDefined
id: isDefined,
UIDeviceOrientation: isOneOf(["landscape", "portrait"])
};

const contentSanitizersForType = {
Expand All @@ -50,10 +51,15 @@ const contentSanitizersForType = {
name: 'sanitize_uiAccessibilityTraits',
value: callGlobal('sanitize_uiAccessibilityTraits')
},
'GREYElementInteraction*': {
type: 'Invocation',
name: 'sanitize_greyElementInteraction',
value: callGlobal('sanitize_greyElementInteraction')
"GREYElementInteraction*": {
type: "Invocation",
name: "sanitize_greyElementInteraction",
value: callGlobal("sanitize_greyElementInteraction")
},
UIDeviceOrientation: {
type: "NSInteger",
name: "sanitize_uiDeviceOrientation",
value: callGlobal("sanitize_uiDeviceOrientation")
}
};

Expand All @@ -62,20 +68,36 @@ module.exports = generator({
contentSanitizersForFunction: {},
contentSanitizersForType,
supportedTypes: [
'CFTimeInterval',
'CGFloat',
'CGPoint',
'GREYContentEdge',
'GREYDirection',
'GREYElementInteraction*',
'id',
'id<GREYAction>',
'id<GREYMatcher>',
'NSInteger',
'NSString *',
'NSString',
'NSUInteger',
'id<GREYAction>',
'id<GREYMatcher>',
'CFTimeInterval',
'UIAccessibilityTraits',
'id'
"__strong NSError **",
"CFTimeInterval",
"CGFloat",
"CGPoint",
"GREYContentEdge",
"GREYDirection",
"GREYElementInteraction*",
"id",
"id<GREYAction>",
"id<GREYMatcher>",
"NSInteger",
"NSString *",
"NSString",
"NSUInteger",
"UIAccessibilityTraits",
"UIDeviceOrientation",
],
renameTypesMap: {
NSUInteger: 'NSInteger',
Expand Down
12 changes: 11 additions & 1 deletion generation/core/global-functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,22 @@ function sanitize_greyElementInteraction(value) {
};
} // END sanitize_greyElementInteraction

function sanitize_uiDeviceOrientation(value) {
const orientationMapping = {
landscape: 3, // top at left side landscape
portrait: 1 // non-reversed portrait
};

return orientationMapping[value];
} // END sanitize_uiDeviceOrientation

module.exports = {
sanitize_greyDirection,
sanitize_greyContentEdge,
sanitize_uiAccessibilityTraits,
sanitize_android_direction,
sanitize_android_edge,
sanitize_matcher,
sanitize_greyElementInteraction
sanitize_greyElementInteraction,
sanitize_uiDeviceOrientation
};
4 changes: 3 additions & 1 deletion generation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ const iosFiles = {
"../detox/ios/Detox/GREYConfiguration+Detox.h":
"../detox/src/ios/earlgreyapi/GREYConfigurationDetox.js",
"../detox/ios/EarlGrey/EarlGrey/Common/GREYConfiguration.h":
"../detox/src/ios/earlgreyapi/GREYConfiguration.js"
"../detox/src/ios/earlgreyapi/GREYConfiguration.js",
"../detox/ios/EarlGrey/EarlGrey/EarlGrey.h":
"../detox/src/ios/earlgreyapi/EarlGrey.js"
};

generateIOSAdapters(iosFiles);
Expand Down

0 comments on commit d52fd53

Please sign in to comment.