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

iOS: perform actions on UIPickerView #605

Merged
merged 21 commits into from
Mar 26, 2018
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
3 changes: 2 additions & 1 deletion detox/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"eslint.enable": false
"eslint.enable": false,
"git.ignoreLimitWarning": true
}
10 changes: 10 additions & 0 deletions detox/src/ios/expect.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,13 @@ class SwipeAction extends Action {
}
}

class ScrollColumnToValue extends Action {
constructor(column,value) {
super();
this._call = invoke.callDirectly(GreyActions.actionForSetPickerColumnToValue(column,value))
}
}

class Interaction {
async execute() {
//if (!this._call) throw new Error(`Interaction.execute cannot find a valid _call, got ${typeof this._call}`);
Expand Down Expand Up @@ -284,6 +291,9 @@ class Element {
this._selectElementWithMatcher(this._originalMatcher._avoidProblematicReactNativeElements());
return await new ActionInteraction(this, new SwipeAction(direction, speed, percentage)).execute();
}
async setColumnToValue(column,value) {
return await new ActionInteraction(this, new ScrollColumnToValue(column, value)).execute();
}
}

class Expect {}
Expand Down
17 changes: 17 additions & 0 deletions detox/test/e2e/p-datePicker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
describe('DatePicker', () => {
beforeEach(async () => {
await device.reloadReactNative();
});

beforeEach(async () => {
await element(by.text('DatePicker')).tap();
});

it('check and scroll datePicker', async () => {
await expect(element(by.type('UIPickerView'))).toBeVisible();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why by type and not by id? Does it not work?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

UIPickerView have not accessibility ID, testID = {'CustomDatePicker'} need to be deleted

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a problem. If user has more than one pickers, the API will break

Copy link
Contributor

Choose a reason for hiding this comment

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

UIPickerView is a UIView, so it can have an accessibility ID. Are you seeing that UIDatePicker does not forward that ID?

Copy link
Contributor Author

@DmitryPonomarenko DmitryPonomarenko Mar 6, 2018

Choose a reason for hiding this comment

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

I checked that UI element via AccessebilityInspector (from Xcode Instruments), and now I found only one way to get element by type

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, thanks

Choose a reason for hiding this comment

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

It won't work on android

Copy link
Contributor

Choose a reason for hiding this comment

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

We know. We want to hone down iOS support first, then we will implement Android as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

This test should be wrapped with if(iOS).

await element(by.type('UIPickerView')).setColumnToValue(1,"6");
await element(by.type('UIPickerView')).setColumnToValue(2,"34");
Copy link
Contributor

Choose a reason for hiding this comment

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

Right now, this test checks nothing. There should be a label in the screen, and on date picker change value, it should update. You should then assert that the label has the correct value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Checking label with text will be always true, because this label always on date picker, I think right solution is checking property of datePicker current value or something like that, now I work in this direction, add this functionality asap

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't understand. The label is updated with the value set in the picker. So if you select 6:41, it won't say "6:34" in the label. If you assert that label.text == "6:34", you will test that the picker really changed value. That's what we want to test in the testing suite.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my example if element (UIPickerView) can't find variable with current column or value test will be failed

Copy link
Contributor

Choose a reason for hiding this comment

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

But that is not what we test in the suite. We test that the native system behaves as expected following Detox changes.

});

});

60 changes: 58 additions & 2 deletions detox/test/ios/example.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,34 @@
remoteGlobalIDString = 58B5119B1A9E6C1200147676;
remoteInfo = RCTText;
};
D58447AF204E9C6000248543 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = EBF21BDC1FC498900052F4D5;
remoteInfo = jsinspector;
};
D58447B1204E9C6000248543 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = EBF21BFA1FC4989A0052F4D5;
remoteInfo = "jsinspector-tvOS";
};
D58447B3204E9C6000248543 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 9936F3131F5F2E4B0010BF04;
remoteInfo = privatedata;
};
D58447B5204E9C6000248543 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 9936F32F1F5F2E5B0010BF04;
remoteInfo = "privatedata-tvOS";
};
/* End PBXContainerItemProxy section */

/* Begin PBXCopyFilesBuildPhase section */
Expand Down Expand Up @@ -1032,6 +1060,34 @@
remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
D58447B0204E9C6000248543 /* libjsinspector.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libjsinspector.a;
remoteRef = D58447AF204E9C6000248543 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
D58447B2204E9C6000248543 /* libjsinspector-tvOS.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = "libjsinspector-tvOS.a";
remoteRef = D58447B1204E9C6000248543 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
D58447B4204E9C6000248543 /* libprivatedata.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libprivatedata.a;
remoteRef = D58447B3204E9C6000248543 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
D58447B6204E9C6000248543 /* libprivatedata-tvOS.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = "libprivatedata-tvOS.a";
remoteRef = D58447B5204E9C6000248543 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */

/* Begin PBXResourcesBuildPhase section */
Expand Down Expand Up @@ -1145,7 +1201,7 @@
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_BUNDLE_IDENTIFIER = org.reactjs.native.example.example;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this change necessary?

PRODUCT_NAME = example;
};
name = Debug;
Expand All @@ -1162,7 +1218,7 @@
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_BUNDLE_IDENTIFIER = org.reactjs.native.example.example;
PRODUCT_NAME = example;
};
name = Release;
Expand Down
33 changes: 33 additions & 0 deletions detox/test/src/Screens/DatePickerScreen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { Component } from 'react';
import {
Text,
View,
StyleSheet,
DatePickerIOS
} from 'react-native';

export default class DatePickerScreen extends Component {

constructor(props) {
super(props);
}

render() {
return (
<View style={{flex: 1, paddingTop: 20, justifyContent: 'center', alignItems: 'center'}}>
<DatePickerIOS
style = {styles.datePicker}
date = {new Date()}
/>
</View>
);
}
}

const styles = StyleSheet.create({
datePicker: {
width:'100%',
height:200,
backgroundColor:'green',
}
});
2 changes: 2 additions & 0 deletions detox/test/src/Screens/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import NetworkScreen from './NetworkScreen';
import AnimationsScreen from './AnimationsScreen';
import LocationScreen from './LocationScreen';
import ShakeScreen from './ShakeScreen';
import DatePickerScreen from './DatePickerScreen'

export {
SanityScreen,
Expand All @@ -28,4 +29,5 @@ export {
AnimationsScreen,
LocationScreen,
ShakeScreen
DatePickerScreen
};
1 change: 1 addition & 0 deletions detox/test/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class example extends Component {
{this.renderScreenButton('Network', Screens.NetworkScreen)}
{this.renderScreenButton('Animations', Screens.AnimationsScreen)}
{this.renderScreenButton('Location', Screens.LocationScreen)}
{this.renderScreenButton('DatePicker', Screens.DatePickerScreen)}
{this.renderButton('Crash', () => {
throw new Error('Simulated Crash')
})}
Expand Down
11 changes: 11 additions & 0 deletions docs/APIRef.ActionsOnElement.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Actions are functions that emulate user behavior. They are being performed on ma
- [`.scroll()`](#scrollpixels-direction)
- [`.scrollTo()`](#scrolltoedge)
- [`.swipe()`](#swipedirection-speed-percentage)
- [`.setColumnToValue()`](#set-column-to-value)


### `tap()`
Expand Down Expand Up @@ -107,3 +108,13 @@ await element(by.id('scrollView')).swipe('down');
await element(by.id('scrollView')).swipe('down', 'fast');
await element(by.id('scrollView')).swipe('down', 'fast', 0.5);
```
### `setColumnToValue(column,value)`
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be explicitly marked as iOS only in the documentation.


column - number of datepicker column (starts from 0)
value - string value in setted column (must be correct)

```js
await expect(element(by.type('UIPickerView'))).toBeVisible();
await element(by.type('UIPickerView')).setColumnToValue(1,"6");
await element(by.type('UIPickerView')).setColumnToValue(2,"34");
```
2 changes: 1 addition & 1 deletion generation/core/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ module.exports = function({
t.identifier("value"),
addArgumentContentSanitizerCall(arg, json.name)
)
])
])
: addArgumentContentSanitizerCall(arg, json.name)
);

Expand Down
97 changes: 46 additions & 51 deletions generation/package.json
Original file line number Diff line number Diff line change
@@ -1,52 +1,47 @@
{
"name": "generation",
"version": "0.0.1",
"description": "Generate wrapper code for native dependencies",
"main": "index.js",
"private": true,
"scripts": {
"build": "./index.js",
"test": "jest",
"precommit": "lint-staged",
"format": "prettier ./**/*.{js,json,css,md} --write"
},
"author": "DanielMSchmidt <danielmschmidt92@gmail.com>",
"license": "MIT",
"lint-staged": {
"*.{js,json,css,md}": [
"prettier --write",
"git add"
]
},
"devDependencies": {
"babel-generator": "^6.25.0",
"babel-types": "^6.25.0",
"download-file-sync": "^1.0.4",
"jest": "^20.0.4",
"lerna": "2.0.0-rc.4",
"lint-staged": "^6.0.0",
"objective-c-parser": "1.1.0",
"prettier": "^1.8.2",
"remove": "^0.1.5"
},
"jest": {
"coveragePathIgnorePatterns": [
"<rootDir>/index.js"
],
"resetMocks": true,
"resetModules": true,
"coverageThreshold": {
"global": {
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100
}
}
},
"dependencies": {
"babel-generate-guard-clauses": "^2.0.0",
"babel-template": "^6.26.0",
"java-method-parser": "^0.4.5"
}
}
"name": "generation",
Copy link
Contributor

Choose a reason for hiding this comment

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

What changed in this file? If nothing, please revert this file.

Copy link
Contributor

Choose a reason for hiding this comment

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

This still remains open. Why did the file change?

"version": "0.0.1",
"description": "Generate wrapper code for native dependencies",
"main": "index.js",
"private": true,
"scripts": {
"build": "./index.js",
"test": "jest",
"precommit": "lint-staged",
"format": "prettier ./**/*.{js,json,css,md} --write"
},
"author": "DanielMSchmidt <danielmschmidt92@gmail.com>",
"license": "MIT",
"lint-staged": {
"*.{js,json,css,md}": ["prettier --write", "git add"]
},
"devDependencies": {
"babel-generator": "^6.25.0",
"babel-types": "^6.25.0",
"download-file-sync": "^1.0.4",
"jest": "^20.0.4",
"lerna": "2.0.0-rc.4",
"lint-staged": "^6.0.0",
"objective-c-parser": "1.1.0",
"prettier": "^1.8.2",
"remove": "^0.1.5"
},
"jest": {
"coveragePathIgnorePatterns": ["<rootDir>/index.js"],
"resetMocks": true,
"resetModules": true,
"coverageThreshold": {
"global": {
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100
}
}
},
"dependencies": {
"babel-generate-guard-clauses": "^2.0.0",
"babel-template": "^6.26.0",
"java-method-parser": "^0.4.5"
}
}