Repository: kiwicom/mobile
Pull request #1231 (2018-10-17 12:23:01)

Hotels: move map a little higher to cover list view


Patch:
diff --git a/app/core/src/screens/hotelsStack/Homepage.js b/app/core/src/screens/hotelsStack/Homepage.js
index 34de65eb..3e4a90da 100644
--- a/app/core/src/screens/hotelsStack/Homepage.js
+++ b/app/core/src/screens/hotelsStack/Homepage.js
@@ -51,6 +51,7 @@ export default class Homepage extends React.Component<Props> {
         <Section>
           <TextButton
             title={<Translation passThrough="Hotels" />}
+            testID="homePage__Hotels-button"
             onPress={this.goToNewHotelsPage}
           />
         </Section>
diff --git a/app/hotels/src/allHotels/AllHotelsSearchList.js b/app/hotels/src/allHotels/AllHotelsSearchList.js
index 7997d81b..6e98d64b 100644
--- a/app/hotels/src/allHotels/AllHotelsSearchList.js
+++ b/app/hotels/src/allHotels/AllHotelsSearchList.js
@@ -29,11 +29,12 @@ export const AllHotelsSearchList = (props: Props) => {
 
   return (
     <React.Fragment>
-      {hotels.map(hotel => (
+      {hotels.map((hotel, index) => (
         <AllHotelsSearchRow
           key={idx(hotel, _ => _.node.id)}
           data={hotel.node}
           openSingleHotel={props.openSingleHotel}
+          testID={index === 0 ? 'firstHotelResult' : ''}
         />
       ))}
     </React.Fragment>
diff --git a/app/hotels/src/allHotels/AllHotelsSearchRow.js b/app/hotels/src/allHotels/AllHotelsSearchRow.js
index b142f890..7e325c41 100644
--- a/app/hotels/src/allHotels/AllHotelsSearchRow.js
+++ b/app/hotels/src/allHotels/AllHotelsSearchRow.js
@@ -67,6 +67,7 @@ class AllHotelsSearchRow extends React.Component<PropsWithContext> {
             onPress={this.onGoToSingleHotel}
             style={style.container}
             delayPressIn={100}
+            testID={this.props.testID}
           >
             {children}
           </Touchable>
@@ -76,6 +77,7 @@ class AllHotelsSearchRow extends React.Component<PropsWithContext> {
             onPress={this.setActiveHotelId}
             style={style.container}
             delayPressIn={100}
+            testID={this.props.testID}
           >
             {children}
           </Touchable>
@@ -88,6 +90,7 @@ class AllHotelsSearchRow extends React.Component<PropsWithContext> {
 type Props = {|
   +openSingleHotel: (id: string) => void,
   +data: AllHotelsSearchRowProps,
+  +testID?: string,
 |};
 
 const AllHotelsSearchRowWithContext = (props: Props) => (
diff --git a/app/hotels/src/allHotels/RenderSearchResults.js b/app/hotels/src/allHotels/RenderSearchResults.js
index 47a75a4c..f4745b68 100644
--- a/app/hotels/src/allHotels/RenderSearchResults.js
+++ b/app/hotels/src/allHotels/RenderSearchResults.js
@@ -90,7 +90,7 @@ export class RenderSearchResults extends React.Component<
   animateToMap = () => {
     Animated.parallel([
       Animated.timing(this.mapAnimation, {
-        toValue: 0,
+        toValue: -6,
         duration: transitionDuration,
         useNativeDriver: true,
       }),
diff --git a/app/hotels/src/singleHotel/HotelDetailScreen.js b/app/hotels/src/singleHotel/HotelDetailScreen.js
index 4b17d552..51a86659 100644
--- a/app/hotels/src/singleHotel/HotelDetailScreen.js
+++ b/app/hotels/src/singleHotel/HotelDetailScreen.js
@@ -174,6 +174,7 @@ export class HotelDetailScreen extends React.Component<
             contentContainerStyle={styles.container}
             onScroll={this.onScroll}
             scrollEventThrottle={500}
+            testID="hotelDetailScrollView"
           >
             <LayoutSingleColumn barStyle={this.state.barStyle}>
               <Header hotel={availableHotel.hotel} />
diff --git a/app/hotels/src/singleHotel/PaymentScreen.js b/app/hotels/src/singleHotel/PaymentScreen.js
index 5a335293..5184ab6b 100644
--- a/app/hotels/src/singleHotel/PaymentScreen.js
+++ b/app/hotels/src/singleHotel/PaymentScreen.js
@@ -1,7 +1,7 @@
 // @flow
 
 import * as React from 'react';
-import { Platform, StatusBar } from 'react-native';
+import { Platform, StatusBar, View } from 'react-native';
 import {
   WebView,
   Logger,
@@ -76,12 +76,15 @@ export class PaymentScreen extends React.Component<PaymentParameters> {
       );
     }
     return (
-      <WebView
-        source={{
-          uri: createURI(this.props, url),
-        }}
-        onNavigationStateChange={this.onNavigationStateChange}
-      />
+      <React.Fragment>
+        <View testID="paymentScreenSingleHotel" />
+        <WebView
+          source={{
+            uri: createURI(this.props, url),
+          }}
+          onNavigationStateChange={this.onNavigationStateChange}
+        />
+      </React.Fragment>
     );
   };
 
diff --git a/app/hotels/src/singleHotel/bookNow/BookNow.js b/app/hotels/src/singleHotel/bookNow/BookNow.js
index 03d126ab..acecc201 100644
--- a/app/hotels/src/singleHotel/bookNow/BookNow.js
+++ b/app/hotels/src/singleHotel/bookNow/BookNow.js
@@ -37,7 +37,7 @@ export class BookNow extends React.Component<PropsWithContext> {
 
   render() {
     return (
-      <Button onPress={this.handleGoToPayment}>
+      <Button onPress={this.handleGoToPayment} testID="bookNowButton">
         <Text style={styles.text}>
           <Translation id="single_hotel.book_now" />
         </Text>
diff --git a/app/hotels/src/singleHotel/roomList/RoomList.js b/app/hotels/src/singleHotel/roomList/RoomList.js
index d0e26289..9bee8e91 100644
--- a/app/hotels/src/singleHotel/roomList/RoomList.js
+++ b/app/hotels/src/singleHotel/roomList/RoomList.js
@@ -54,6 +54,7 @@ class RoomList extends React.Component<Props> {
               select={select}
               deselect={deselect}
               selected={selected}
+              testID={index === data.length - 1 ? 'lastAvailableRoom' : ''}
             />
           </React.Fragment>
         ))}
diff --git a/app/hotels/src/singleHotel/roomList/RoomRow.js b/app/hotels/src/singleHotel/roomList/RoomRow.js
index c23d0de3..3b6574c5 100644
--- a/app/hotels/src/singleHotel/roomList/RoomRow.js
+++ b/app/hotels/src/singleHotel/roomList/RoomRow.js
@@ -25,6 +25,7 @@ type ContainerProps = {|
   +selected: {
     +[string]: number,
   },
+  +testID?: string,
 |};
 
 type Props = {|
@@ -107,6 +108,7 @@ export class RoomRow extends React.Component<Props> {
             selectableCount={selectableCount}
             increment={this.select}
             decrement={this.deselect}
+            testID={this.props.testID}
           />
         </View>
       </View>
diff --git a/app/hotels/src/singleHotel/roomPicker/IncrementDecrement.js b/app/hotels/src/singleHotel/roomPicker/IncrementDecrement.js
index 6d181358..83f859ce 100644
--- a/app/hotels/src/singleHotel/roomPicker/IncrementDecrement.js
+++ b/app/hotels/src/singleHotel/roomPicker/IncrementDecrement.js
@@ -23,6 +23,7 @@ type Props = {|
   +selectableCount: number,
   +increment: () => void,
   +decrement: () => void,
+  +testID?: string,
 |};
 
 export default function IncrementDecrement({
diff --git a/app/hotels/src/singleHotel/roomPicker/RoomPicker.js b/app/hotels/src/singleHotel/roomPicker/RoomPicker.js
index 93e2e84e..d160a9ed 100644
--- a/app/hotels/src/singleHotel/roomPicker/RoomPicker.js
+++ b/app/hotels/src/singleHotel/roomPicker/RoomPicker.js
@@ -16,6 +16,7 @@ type Props = {|
   +selectableCount: number,
   +increment: () => void,
   +decrement: () => void,
+  +testID?: string,
 |};
 
 export default function RoomPicker(props: Props) {
@@ -24,7 +25,13 @@ export default function RoomPicker(props: Props) {
   }
 
   if (props.selectedCount === 0) {
-    return <SelectButton price={props.price} increment={props.increment} />;
+    return (
+      <SelectButton
+        price={props.price}
+        increment={props.increment}
+        testID={props.testID}
+      />
+    );
   }
 
   return <IncrementDecrement {...props} />;
diff --git a/app/hotels/src/singleHotel/roomPicker/SelectButton.js b/app/hotels/src/singleHotel/roomPicker/SelectButton.js
index 4955733c..d643193f 100644
--- a/app/hotels/src/singleHotel/roomPicker/SelectButton.js
+++ b/app/hotels/src/singleHotel/roomPicker/SelectButton.js
@@ -19,11 +19,17 @@ type PriceType = {|
 type Props = {|
   +price: PriceType,
   +increment: () => void,
+  +testID?: string,
 |};
 
-export default function SelectButton({ increment, price }: Props) {
+export default function SelectButton({ increment, price, testID }: Props) {
   return (
-    <Touchable style={styles.container} onPress={increment} delayPressIn={40}>
+    <Touchable
+      style={styles.container}
+      onPress={increment}
+      delayPressIn={40}
+      testID={testID}
+    >
       <View style={styles.row}>
         <ButtonTitle
           style={styles.text}
diff --git a/package.json b/package.json
index edc6052b..c9fc8089 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,8 @@
     "playground": "node ./scripts/activatePlayground.js",
     "flow": "flow app --include-warnings",
     "deploy-translations": "yarn babel-node packages/localization/src/Deployer.js",
-    "e2e": "yarn detox build && yarn detox test"
+    "e2e-iphone": "yarn detox build  --configuration ios.sim.debug && yarn detox test --configuration ios.sim.debug",
+    "e2e-ipad": "yarn detox build  --configuration ios.sim.tablet.debug && yarn detox test --configuration ios.sim.tablet.debug"
   },
   "dependencies": {
     "react": "16.5.0",
@@ -75,9 +76,15 @@
     "configurations": {
       "ios.sim.debug": {
         "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/reactNativeApp.app",
-        "build": "xcodebuild -workspace ios/reactNativeApp.xcworkspace -scheme reactNativeApp -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
+        "build": "xcodebuild -workspace ios/reactNativeApp.xcworkspace -UseNewBuildSystem=NO -scheme reactNativeApp -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
         "type": "ios.simulator",
         "name": "iPhone 6"
+      },
+      "ios.sim.tablet.debug": {
+        "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/reactNativeApp.app",
+        "build": "xcodebuild -workspace ios/reactNativeApp.xcworkspace -UseNewBuildSystem=NO -scheme reactNativeApp -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
+        "type": "ios.simulator",
+        "name": "iPad Air 2"
       }
     },
     "test-runner": "jest"
diff --git a/packages/shared/src/Touchable.js b/packages/shared/src/Touchable.js
index 1b3c15ba..045f6996 100644
--- a/packages/shared/src/Touchable.js
+++ b/packages/shared/src/Touchable.js
@@ -26,6 +26,7 @@ type Props = {|
   // Should the ripple render outside of the view bounds?
   +borderlessRipple?: boolean,
   +rippleColor?: string,
+  +testID?: string,
   ...AccessibilityProps,
 |};
 
diff --git a/packages/shared/src/WebView.js b/packages/shared/src/WebView.js
index 4ab94648..ad75c450 100644
--- a/packages/shared/src/WebView.js
+++ b/packages/shared/src/WebView.js
@@ -12,6 +12,7 @@ type Props = {|
     +uri: string,
   |},
   onNavigationStateChange?: (event: WebViewStateChangeEvent) => void,
+  testID?: string,
 |};
 
 export default class WebView extends React.Component<Props> {
diff --git a/packages/shared/src/buttons/Button.js b/packages/shared/src/buttons/Button.js
index c13cd11b..fd3f8dba 100644
--- a/packages/shared/src/buttons/Button.js
+++ b/packages/shared/src/buttons/Button.js
@@ -13,6 +13,7 @@ type Props = {|
   +style?: StylePropType,
   +disabled?: boolean,
   +type: 'primary' | 'secondary',
+  +testID?: string,
 |};
 
 /**
@@ -33,6 +34,7 @@ export default function Button(props: Props) {
         props.style,
       ]}
       accessibilityComponentType="button"
+      testID={props.testID}
     >
       {props.children}
     </Touchable>
diff --git a/packages/shared/src/buttons/TextButton.js b/packages/shared/src/buttons/TextButton.js
index a2cbc1bd..3f10b7f2 100644
--- a/packages/shared/src/buttons/TextButton.js
+++ b/packages/shared/src/buttons/TextButton.js
@@ -13,6 +13,7 @@ type Props = {|
   +onPress: () => void,
   +disabled: boolean,
   +type: 'primary' | 'secondary',
+  +testID?: string,
 |};
 
 /**
@@ -30,6 +31,7 @@ export default function TextButton(props: Props) {
           : styleSheet.buttonPrimaryDisabled)
       }
       type={props.type}
+      testID={props.testID}
     >
       <ButtonTitle
         style={[


Test patch:
diff --git a/app/hotels/src/allHotels/__tests__/__snapshots__/AllHotelsSearchList.test.js.snap b/app/hotels/src/allHotels/__tests__/__snapshots__/AllHotelsSearchList.test.js.snap
index 7d25a2be..7ba239fb 100644
--- a/app/hotels/src/allHotels/__tests__/__snapshots__/AllHotelsSearchList.test.js.snap
+++ b/app/hotels/src/allHotels/__tests__/__snapshots__/AllHotelsSearchList.test.js.snap
@@ -30,6 +30,7 @@ exports[`renders found hotels 1`] = `
       }
     }
     openSingleHotel={[Function]}
+    testID="firstHotelResult"
   />
   <ForwardRef(Relay(AllHotelsSearchRowWithContext))
     data={
@@ -39,6 +40,7 @@ exports[`renders found hotels 1`] = `
       }
     }
     openSingleHotel={[Function]}
+    testID=""
   />
 </React.Fragment>
 `;
diff --git a/app/hotels/src/singleHotel/bookNow/__tests__/__snapshots__/BookNow.test.js.snap b/app/hotels/src/singleHotel/bookNow/__tests__/__snapshots__/BookNow.test.js.snap
index 658a7aa4..113ade9d 100644
--- a/app/hotels/src/singleHotel/bookNow/__tests__/__snapshots__/BookNow.test.js.snap
+++ b/app/hotels/src/singleHotel/bookNow/__tests__/__snapshots__/BookNow.test.js.snap
@@ -4,6 +4,7 @@ exports[`renders without crashing 1`] = `
 <Button
   disabled={false}
   onPress={[Function]}
+  testID="bookNowButton"
   type="primary"
 >
   <Text
@@ -26,6 +27,7 @@ exports[`renders without crashing with missing data 1`] = `
 <Button
   disabled={false}
   onPress={[Function]}
+  testID="bookNowButton"
   type="primary"
 >
   <Text
diff --git a/e2e/firstTest.spec.js b/e2e/firstTest.spec.js
deleted file mode 100644
index 1289f651..00000000
--- a/e2e/firstTest.spec.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// @flow
-
-/* eslint-env detox/detox */
-
-describe('Example', () => {
-  beforeEach(async () => {
-    await device.reloadReactNative();
-  });
-
-  it('should have welcome screen', async () => {
-    await element(by.id('hotelsTab')).tap();
-    await expect(element(by.id('homePage'))).toBeVisible();
-  });
-});
diff --git a/e2e/hotels.spec.js b/e2e/hotels.spec.js
new file mode 100644
index 00000000..09a4cdfe
--- /dev/null
+++ b/e2e/hotels.spec.js
@@ -0,0 +1,33 @@
+// @flow
+
+/* eslint-env detox/detox */
+
+describe('Hotels', () => {
+  beforeEach(async () => {
+    await device.launchApp({
+      newInstance: true,
+      permissions: { location: 'always' },
+    });
+  });
+
+  it('should have welcome screen', async () => {
+    await element(by.id('hotelsTab')).tap();
+    await expect(element(by.id('homePage'))).toBeVisible();
+  });
+
+  it('should go to payment screen when booking a room', async () => {
+    await element(by.id('hotelsTab')).tap();
+    await expect(element(by.id('homePage'))).toBeVisible();
+    await element(by.id('homePage__Hotels-button')).tap();
+    await expect(element(by.id('firstHotelResult'))).toBeVisible();
+    await element(by.id('firstHotelResult')).tap();
+    await expect(element(by.id('hotelDetailScrollView'))).toExist();
+    await expect(element(by.id('lastAvailableRoom'))).toExist();
+    await element(by.id('hotelDetailScrollView')).scrollTo('bottom');
+    await expect(element(by.id('lastAvailableRoom'))).toBeVisible();
+    await element(by.id('lastAvailableRoom')).tap();
+    await expect(element(by.id('bookNowButton'))).toBeVisible();
+    await element(by.id('bookNowButton')).tap();
+    await expect(element(by.id('paymentScreenSingleHotel'))).toExist();
+  });
+});