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

Add generation for GREYInteraction #564

Merged
merged 2 commits into from
Apr 19, 2018

Conversation

DanielMSchmidt
Copy link
Contributor

@DanielMSchmidt DanielMSchmidt commented Feb 6, 2018

This PR moves most iOS calls over to generated code (detox_selectElementWithMatcher is the only missing one and it's a bit of a special case.

@DanielMSchmidt DanielMSchmidt force-pushed the generation/ios-element-interaction branch 2 times, most recently from 138e75a to b206d1a Compare February 10, 2018 10:58
@rotemmiz
Copy link
Member

rotemmiz commented Mar 6, 2018

Is this still a WIP?

@DanielMSchmidt
Copy link
Contributor Author

Yes, but close to being finished

@rotemmiz rotemmiz changed the title Add generation for GREYInteraction [WIP] Add generation for GREYInteraction Mar 6, 2018
@DanielMSchmidt
Copy link
Contributor Author

I now rebased this PR. The original goal was more ambitious, but I think incremental steps forward are a nicer way to work together 🙈 I think this might help with #618 maybe only by us having a conversation about what these instance methods mean for us in detox 👍

@DanielMSchmidt DanielMSchmidt force-pushed the generation/ios-element-interaction branch from b206d1a to b8b2f2e Compare March 11, 2018 14:51
@DanielMSchmidt DanielMSchmidt changed the title [WIP] Add generation for GREYInteraction Add generation for GREYInteraction Mar 11, 2018
@@ -333,6 +333,28 @@ describe("iOS generation", () => {
});
});

describe("instance methods", () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those tabs look awful in github :(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They look great. Don’t switch to spaces.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛒- i

@@ -7,13 +7,14 @@ const fs = require("fs");

const { methodNameToSnakeCase } = require("../helpers");
let globalFunctionUsage = {};
module.exports = function({
module.exports = function ({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please make it a bit more readable by creating a named function and exporting it, instead of exporting an anonymous one. Sorry for nitpicking, I just can't get used to this javascript jungle magic. :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, what would be a good name for a function that returns a code generator?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getGenerator ?

@@ -81,13 +89,22 @@ module.exports = function({
}

function createMethod(classJson, json) {
// For us this means that we don't set the class type, but let it be set from the outside
// This is an assumption based on our current experience with EarlGrey, we might need to rework this at some point
const isTranslucent = !json.static;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does translucent mean in this context ?

Copy link
Contributor Author

@DanielMSchmidt DanielMSchmidt Mar 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It means that we don't wrap the content as a class but add another argument called element to the function list, which is taken as the element to work on. From the return statements perspective the translucent naming makes sense, but we could also call it isInstanceMethod, might make more sense in this context

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I got it, can you elaborate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, pressed enter too early, does this make more sense?

@@ -112,7 +129,7 @@ module.exports = function({
return json;
}

function createMethodBody(classJson, json) {
function createMethodBody(classJson, json, isTranslucent) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try not to pass booleans in function params, it's very confusing.
https://martinfowler.com/bliki/FlagArgument.html

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead, just create two functions with clear naming

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this part down into the functions

t.identifier("type"),
t.stringLiteral(addArgumentTypeSanitizer(arg))
),
t.objectProperty(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this formatting the work of prettier ? It's very weird,
screen shot 2018-03-11 at 20 41 43

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prettier being prettier 🤷‍♂️

@@ -215,7 +243,7 @@ module.exports = function({
: typeCheckCreator(json);
}

return function(files) {
return function (files) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, javascript voodoo. I'm too old for this magic. ;(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is going on here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generator is returning a function to be invoked with files to generate the source code. The problem was that iOS and Android have a similar abstraction, so the easiest way to solve this without having to rewrite a lot was to wrap it into an anonymous functions with all the static values previously set being configurable and returning the old main logic as a function.

@@ -23,7 +23,6 @@
"jest": "^20.0.4",
"lerna": "2.0.0-rc.4",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need lerna here, it can be safely deleted

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure 👍

@rotemmiz
Copy link
Member

Of course this needs to pass e2e before merge (from travis log)

     Error: Error: target is invalid
      at Client.execute (/Users/travis/build/wix/detox/detox/src/client/Client.js:75:13)
      at <anonymous>

@DanielMSchmidt DanielMSchmidt force-pushed the generation/ios-element-interaction branch 4 times, most recently from a9f2559 to eeba8fa Compare March 12, 2018 21:26
@DanielMSchmidt
Copy link
Contributor Author

@rotemmiz I refactored the things you mentioned and got a working version up (let's see if CI agrees). I could only finish one of the calls, but left TODO items on the others. They "only" need a bit of fine tuning, but I thought this progress might already be helpful for you, especially in regards of #618

@rotemmiz
Copy link
Member

Awesome! Will we be able to generate non static invocations now ? Can't see an example in the new generated code, can you please point me to it ?

this._call = invoke.call(element._call, 'performAction:', action._call);
// TODO: move this.execute() here from the caller

this._call = GreyInteraction.performAction(callThunk(element), callThunk(action));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rotemmiz this is currently the only successful invocation of an instance method, I need to find out why the others fail, but I guess it's a call side problem

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this resolved ?

@DanielMSchmidt DanielMSchmidt force-pushed the generation/ios-element-interaction branch from eeba8fa to ba5df91 Compare March 14, 2018 07:44
@rotemmiz
Copy link
Member

Hey @DanielMSchmidt , anything to be done on your side ?

@DanielMSchmidt
Copy link
Contributor Author

Not yet, trying to get to it next weekend

@DanielMSchmidt DanielMSchmidt force-pushed the generation/ios-element-interaction branch from ba5df91 to 4d35bcc Compare March 27, 2018 20:45
@DanielMSchmidt DanielMSchmidt force-pushed the generation/ios-element-interaction branch from 4d35bcc to 8b6d9d9 Compare March 27, 2018 20:50
@DanielMSchmidt
Copy link
Contributor Author

@rotemmiz This is done now 👍 Let's get it into master ;)

@DanielMSchmidt DanielMSchmidt dismissed rotemmiz’s stale review April 12, 2018 20:14

Addressed changes

@DanielMSchmidt
Copy link
Contributor Author

@rotemmiz ping, could you review this PR? 🙏 😇

t.blockStatement(createMethodBody(classJson, json)),
false,
json.static
true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will this mean every method is static now ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then why passing this boolean anyway ? why not get rid of it ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a method of babel-types, I could write a wrapper like createStaticClassMethod, would that be more readable for you?

Every method is static, I choose to deal with instance methods a little different, I just let the target be passed in as the first argument. My point for this is that we have the class-like behavior more on the caller-side of this function and I don't want to duplicate it in any way. Also, the calls are more similar now than they would have been otherwise. If we want to change this somewhen I would propose we rethink this at a point in time when we get rid of these wrapper classes and access the generated code "directly", like in this proposal: #563

@@ -189,10 +214,12 @@ module.exports = function({
t.objectProperty(
t.identifier("target"),
t.objectExpression([
t.objectProperty(t.identifier("type"), t.stringLiteral("Class")),
t.objectProperty(t.identifier("type"), t.stringLiteral(json.static ? "Class" : "Invocation")),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, got it

});
ARG: t.identifier(name)
});
const isGreyAction = ({ name }) =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about just defining functions instead of assigning functions to variables ?

function isGreyAction({name}) {
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea 👍

@DanielMSchmidt
Copy link
Contributor Author

@rotemmiz Addressed your comments / replied. Thank you for taking the time to review <3

@DanielMSchmidt
Copy link
Contributor Author

Fun fact: This PR moves us from 47 to 40 open .call invocations

@rotemmiz rotemmiz merged commit 479a1b4 into master Apr 19, 2018
@rotemmiz rotemmiz deleted the generation/ios-element-interaction branch April 19, 2018 20:32
@rotemmiz
Copy link
Member

💪

@rotemmiz
Copy link
Member

@DanielMSchmidt , I'm getting a weird behaviour when running ci.ios.sh locally.
generation script generates something a bit different and breaks tests. Can you please take a look ?

@rotemmiz
Copy link
Member

I now get it, I switched to EarlGrey 1.13, there is some breakage, not sure what.

@rotemmiz
Copy link
Member

@LeoNatan, NS_REFINED_FOR_SWIFT macro was added to a few of EarlGrey's functions.
What should we do if we want to invoke this code through DTXMethodInvocation? should we just ignore it in the method signature ?

@LeoNatan
Copy link
Contributor

Refined means there is a better alternative for Swift. It has no influence on ObjC.

@rotemmiz
Copy link
Member

So
method: "performAction:"
not
method: "performAction:NS_REFINED_FOR_SWIFT"

right?

@LeoNatan
Copy link
Contributor

Yes, of course.

It's an attribute.
# define CF_REFINED_FOR_SWIFT __attribute__((swift_private))

@wix wix locked and limited conversation to collaborators Jul 23, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants