Repository: kiwicom/mobile
Pull request #983 (2018-08-13 15:38:34)

Adding tests for InsuranceRow


Patch:
diff --git a/app/MMB/src/scenes/tripServices/insurance/insuranceOverviewScene/orderSummary/InsuranceRow.js b/app/MMB/src/scenes/tripServices/insurance/insuranceOverviewScene/orderSummary/InsuranceRow.js
index d05d261b..3c2c824b 100644
--- a/app/MMB/src/scenes/tripServices/insurance/insuranceOverviewScene/orderSummary/InsuranceRow.js
+++ b/app/MMB/src/scenes/tripServices/insurance/insuranceOverviewScene/orderSummary/InsuranceRow.js
@@ -21,7 +21,7 @@ type InsurancePrice = {|
   +price: {|
     +amount: number,
     +currency: string,
-  |},
+  |} | null,
 |};
 
 type Props = {|
@@ -30,7 +30,7 @@ type Props = {|
   +changes: Change[],
 |};
 
-function InsuranceRow(props: Props) {
+export function InsuranceRow(props: Props) {
   let translationId = '';
   switch (props.insuranceType) {
     case 'TRAVEL_PLUS': {
diff --git a/app/hotels/src/HotelsContext.js b/app/hotels/src/HotelsContext.js
index 23c350d7..c78f262e 100644
--- a/app/hotels/src/HotelsContext.js
+++ b/app/hotels/src/HotelsContext.js
@@ -10,6 +10,10 @@ const defaultState = {
   roomsConfiguration: null,
   currency: '',
   cityName: null,
+  isNew: false,
+  actions: {
+    setIsNew: () => {},
+  },
 };
 
 const { Consumer, Provider: ContextProvider } = React.createContext({
@@ -42,6 +46,10 @@ type State = {|
   +checkout: Date | null,
   +roomsConfiguration: RoomConfigurationType | null,
   +currency: string,
+  isNew: boolean,
+  +actions: {|
+    +setIsNew: (isNew: boolean) => void,
+  |},
 |};
 
 const validateDate = (input: string): boolean => {
@@ -69,8 +77,17 @@ class Provider extends React.Component<Props, State> {
       roomsConfiguration: props.roomsConfiguration || null,
       currency: props.currency,
       cityName: props.cityName || null,
+      isNew: false,
+      actions: {
+        setIsNew: this.setIsNew,
+      },
     };
   }
+
+  setIsNew = (isNew: boolean) => {
+    this.setState({ isNew });
+  };
+
   render = () => (
     <ContextProvider value={this.state}>{this.props.children}</ContextProvider>
   );
diff --git a/app/hotels/src/filter/FilterButton.js b/app/hotels/src/filter/FilterButton.js
index 8719fe80..a76fe383 100644
--- a/app/hotels/src/filter/FilterButton.js
+++ b/app/hotels/src/filter/FilterButton.js
@@ -1,5 +1,9 @@
 // @flow
 
+/* eslint-disable react-native/no-unused-styles */
+// We need to deactivate this rule for now, doing this -> const styleSheet = isNew ? newStyles : styles;
+// Will confuse the linter, but all styles are being used
+
 import * as React from 'react';
 import { View } from 'react-native';
 import {
@@ -11,20 +15,23 @@ import {
 } from '@kiwicom/mobile-shared';
 import type { TranslationType } from '@kiwicom/mobile-localization';
 
-type Props = {|
-  +title: TranslationType,
-  +isActive: boolean,
-  +onPress: () => void,
-  +icon?: React.Element<typeof Icon>,
+import HotelsContext from '../HotelsContext';
+
+type PropsWithContext = {|
+  ...Props,
+  isNew: boolean,
 |};
 
-export default function FilterButton(props: Props) {
+const FilterButton = (props: PropsWithContext) => {
   let icon = props.icon;
-  const { title, isActive, onPress } = props;
+  const { title, isActive, onPress, isNew } = props;
+  const styleSheet = isNew ? newStyles : styles;
+  const iconColor = isNew ? Color.ink.normal : Color.brandDark;
+  const iconColorActive = isNew ? Color.inputBackground : Color.white;
 
   if (icon) {
     icon = React.cloneElement(icon, {
-      color: isActive ? Color.white : Color.brandDark,
+      color: isActive ? iconColorActive : iconColor,
     });
   }
 
@@ -45,9 +52,24 @@ export default function FilterButton(props: Props) {
       </View>
     </Button>
   );
+};
+
+type Props = {|
+  +title: TranslationType,
+  +isActive: boolean,
+  +onPress: () => void,
+  +icon?: React.Element<typeof Icon>,
+|};
+
+export default function FilterButtonWithContext(props: Props) {
+  return (
+    <HotelsContext.Consumer>
+      {({ isNew }) => <FilterButton {...props} isNew={isNew} />}
+    </HotelsContext.Consumer>
+  );
 }
 
-const styleSheet = StyleSheet.create({
+const styles = StyleSheet.create({
   activeButtonGroup: {
     backgroundColor: Color.brand,
   },
@@ -73,3 +95,35 @@ const styleSheet = StyleSheet.create({
     alignItems: 'center',
   },
 });
+
+/**
+ * Used for new design
+ */
+const newStyles = StyleSheet.create({
+  activeButtonGroup: {
+    backgroundColor: Color.ink.normal,
+  },
+  buttonGroup: {
+    backgroundColor: Color.backgroundBody,
+    marginEnd: 5,
+    borderColor: Color.inputBackground,
+    borderWidth: StyleSheet.hairlineWidth,
+    ios: {
+      height: 36,
+      borderRadius: 2,
+    },
+  },
+  activeButtonText: {
+    color: Color.inputBackground,
+  },
+  buttonText: {
+    color: Color.ink.normal,
+  },
+  icon: {
+    paddingEnd: 5,
+  },
+  row: {
+    flexDirection: 'row',
+    alignItems: 'center',
+  },
+});
diff --git a/app/hotels/src/filter/FilterStripe.js b/app/hotels/src/filter/FilterStripe.js
index 6aca9428..e6d1a5ff 100644
--- a/app/hotels/src/filter/FilterStripe.js
+++ b/app/hotels/src/filter/FilterStripe.js
@@ -1,8 +1,8 @@
-// @flow
+// @flow strict
 
 import * as React from 'react';
 import { ScrollView, View } from 'react-native';
-import { StyleSheet } from '@kiwicom/mobile-shared';
+import { StyleSheet, Color } from '@kiwicom/mobile-shared';
 
 import HotelsContext from '../HotelsContext';
 import StarsFilter from './stars/StarsFilter';
@@ -23,6 +23,7 @@ type PropsWithContext = {|
   +activeFilters: ActiveFilters,
   +onChange: OnChangeFilterParams => void,
   +filter: FilterParams,
+  +isNew: boolean,
 |};
 
 /**
@@ -48,11 +49,12 @@ class FilterStripe extends React.Component<PropsWithContext> {
   storeScrollViewRef = ref => (this.scrollViewRef = ref);
 
   render = () => {
+    const newStyle = this.props.isNew ? styles.backgroundNew : null;
     return (
       <View style={styles.view}>
         <ScrollView
           ref={this.storeScrollViewRef}
-          contentContainerStyle={styles.scrollView}
+          contentContainerStyle={[styles.scrollView, newStyle]}
           horizontal={true}
           showsHorizontalScrollIndicator={false}
         >
@@ -103,12 +105,15 @@ const styles = StyleSheet.create({
       paddingHorizontal: 10,
     },
   },
+  backgroundNew: {
+    backgroundColor: Color.white,
+  },
 });
 
 export default function FilterStripeWithContext() {
   return (
     <HotelsContext.Consumer>
-      {({ currency }) => (
+      {({ currency, isNew }) => (
         <HotelsFilterContext.Consumer>
           {({ activeFilters, filterParams, actions: { setFilter } }) => (
             <FilterStripe
@@ -116,6 +121,7 @@ export default function FilterStripeWithContext() {
               onChange={setFilter}
               filter={filterParams}
               activeFilters={activeFilters}
+              isNew={isNew}
             />
           )}
         </HotelsFilterContext.Consumer>
diff --git a/app/hotels/src/navigation/allHotels/SearchResultsScreen.js b/app/hotels/src/navigation/allHotels/SearchResultsScreen.js
index 9cb7acd0..19cfad3e 100644
--- a/app/hotels/src/navigation/allHotels/SearchResultsScreen.js
+++ b/app/hotels/src/navigation/allHotels/SearchResultsScreen.js
@@ -15,21 +15,16 @@ import {
 import NewAllHotels from '../../allHotels/NewAllHotels';
 import NewAllHotelsMap from '../../map/allHotels/NewAllHotelsMap';
 import SearchResultsHeader from './SearchResultsHeader';
+import HotelsContext from '../../HotelsContext';
 
-type Props = {|
-  +navigation: NavigationType,
-  +onBackClicked: () => void,
+type PropsWithContext = {|
+  ...Props,
+  setIsNew: (isNew: boolean) => void,
 |};
 
-export default class SearchResultsScreen extends React.Component<Props> {
-  static navigationOptions = (props: Props) => {
-    function goToAllHotelsMap() {
-      props.navigation.navigate('AllHotelsMap');
-    }
-
-    return {
-      header: <SearchResultsHeader goToMap={goToAllHotelsMap} />,
-    };
+class SearchResultsScreen extends React.Component<PropsWithContext> {
+  componentDidMount = () => {
+    this.props.setIsNew(true);
   };
 
   render = () => (
@@ -65,3 +60,28 @@ const styles = StyleSheet.create({
     fontSize: 16,
   },
 });
+
+type Props = {|
+  +navigation: NavigationType,
+  +onBackClicked: () => void,
+|};
+
+export default function SearchResultsScreenWithContext(props: Props) {
+  return (
+    <HotelsContext.Consumer>
+      {({ actions: { setIsNew } }) => (
+        <SearchResultsScreen {...props} setIsNew={setIsNew} />
+      )}
+    </HotelsContext.Consumer>
+  );
+}
+
+SearchResultsScreenWithContext.navigationOptions = (props: Props) => {
+  function goToAllHotelsMap() {
+    props.navigation.navigate('AllHotelsMap');
+  }
+
+  return {
+    header: <SearchResultsHeader goToMap={goToAllHotelsMap} />,
+  };
+};
diff --git a/packages/shared/src/Color.js b/packages/shared/src/Color.js
index d45d3100..7c7ab3c1 100644
--- a/packages/shared/src/Color.js
+++ b/packages/shared/src/Color.js
@@ -113,6 +113,7 @@ export default {
   disabled: '#b8c1cc',
   disabledInput: '#fafbfc',
   labelDisabled: '#dfe4ea',
+  backgroundBody: '#f5f7f9',
 
   border: '#e8edf1',
 


Test patch:
diff --git a/app/MMB/src/scenes/tripServices/insurance/insuranceOverviewScene/__tests__/InsuranceOverviewSceneContext.test.js b/app/MMB/src/scenes/tripServices/insurance/insuranceOverviewScene/__tests__/InsuranceOverviewSceneContext.test.js
index 7a3c51d0..0c49f3ff 100644
--- a/app/MMB/src/scenes/tripServices/insurance/insuranceOverviewScene/__tests__/InsuranceOverviewSceneContext.test.js
+++ b/app/MMB/src/scenes/tripServices/insurance/insuranceOverviewScene/__tests__/InsuranceOverviewSceneContext.test.js
@@ -33,6 +33,7 @@ describe('InsuranceOverviewSceneContext', () => {
     expect(instance.props.insurancePrices).toEqual([]);
     expect(instance.props.changes).toEqual([]);
     expect(instance.props.initialised).toBe(false);
+    expect(instance.props.amount).toBe(0);
     expect(typeof instance.props.initState).toBe('function');
     expect(typeof instance.props.updatePassengerInsurance).toBe('function');
   });
@@ -82,6 +83,7 @@ describe('InsuranceOverviewSceneContext', () => {
       },
     ]);
     expect(instance.props.initialised).toBe(true);
+    expect(instance.props.amount).toBe(0);
   });
 
   it("updates a passenger's insurance", () => {
@@ -110,6 +112,13 @@ describe('InsuranceOverviewSceneContext', () => {
           insuranceType: 'NONE',
           price: null,
         },
+        {
+          insuranceType: 'TRAVEL_PLUS',
+          price: {
+            amount: 24.32,
+            currency: 'EUR',
+          },
+        },
       ],
     });
 
@@ -134,5 +143,6 @@ describe('InsuranceOverviewSceneContext', () => {
       },
     ]);
     expect(instance.props.initialised).toBe(true);
+    expect(instance.props.amount).toBe(24.32);
   });
 });
diff --git a/app/MMB/src/scenes/tripServices/insurance/insuranceOverviewScene/orderSummary/__tests__/InsuranceRow.test.js b/app/MMB/src/scenes/tripServices/insurance/insuranceOverviewScene/orderSummary/__tests__/InsuranceRow.test.js
new file mode 100644
index 00000000..6dc1739d
--- /dev/null
+++ b/app/MMB/src/scenes/tripServices/insurance/insuranceOverviewScene/orderSummary/__tests__/InsuranceRow.test.js
@@ -0,0 +1,205 @@
+// @flow
+
+import * as React from 'react';
+import renderer from 'react-test-renderer';
+import { Translation } from '@kiwicom/mobile-localization';
+import { Price } from '@kiwicom/mobile-shared';
+
+import { InsuranceRow } from '../InsuranceRow';
+
+const insurancePrices = [
+  {
+    insuranceType: 'NONE',
+    price: null,
+  },
+  {
+    insuranceType: 'TRAVEL_BASIC',
+    price: {
+      amount: 12.32,
+      currency: 'EUR',
+    },
+  },
+  {
+    insuranceType: 'TRAVEL_PLUS',
+    price: {
+      amount: 30.64,
+      currency: 'EUR',
+    },
+  },
+];
+
+describe('InsuranceRow', () => {
+  it('displays correct amount and quantity for travel plus', () => {
+    const changes = [
+      {
+        databaseId: 123,
+        from: 'NONE',
+        to: 'TRAVEL_PLUS',
+      },
+      {
+        databaseId: 1234,
+        from: 'TRAVEL_BASIC',
+        to: 'TRAVEL_PLUS',
+      },
+    ];
+
+    const travelPlus = renderer.create(
+      <InsuranceRow
+        changes={changes}
+        insurancePrices={insurancePrices}
+        insuranceType="TRAVEL_PLUS"
+      />,
+    );
+    const price = travelPlus.root.findByType(Price);
+    expect(price.props.amount).toBe(48.96);
+    expect(price.props.currency).toBe('EUR');
+
+    const translations = travelPlus.root.findAllByType(Translation);
+    expect(translations[0].props.values.quantity).toBe(2);
+  });
+
+  it('displays correct amount and quantity for travel basic', () => {
+    const changes = [
+      {
+        databaseId: 123,
+        from: 'TRAVEL_PLUS',
+        to: 'TRAVEL_BASIC',
+      },
+      {
+        databaseId: 1234,
+        from: 'NONE',
+        to: 'TRAVEL_PLUS',
+      },
+    ];
+
+    const travelBasic = renderer.create(
+      <InsuranceRow
+        changes={changes}
+        insurancePrices={insurancePrices}
+        insuranceType="TRAVEL_BASIC"
+      />,
+    );
+    const price = travelBasic.root.findByType(Price);
+    expect(price.props.amount).toBe(-18.32);
+    expect(price.props.currency).toBe('EUR');
+
+    const translations = travelBasic.root.findAllByType(Translation);
+    expect(translations[0].props.values.quantity).toBe(1);
+  });
+
+  it('displays correct amount and quantity for no insurance', () => {
+    const changes = [
+      {
+        databaseId: 123,
+        from: 'TRAVEL_PLUS',
+        to: 'NONE',
+      },
+      {
+        databaseId: 1234,
+        from: 'NONE',
+        to: 'TRAVEL_PLUS',
+      },
+      {
+        databaseId: 12345,
+        from: 'TRAVEL_PLUS',
+        to: 'NONE',
+      },
+    ];
+
+    const none = renderer.create(
+      <InsuranceRow
+        changes={changes}
+        insurancePrices={insurancePrices}
+        insuranceType="NONE"
+      />,
+    );
+    const price = none.root.findByType(Price);
+    expect(price.props.amount).toBe(-61.28);
+    expect(price.props.currency).toBe('EUR');
+
+    const translations = none.root.findAllByType(Translation);
+    expect(translations[0].props.values.quantity).toBe(2);
+  });
+
+  it('renders null if no changes for selected type or to type is different from selected type', () => {
+    const changesNone = [
+      {
+        databaseId: 123,
+        from: 'NONE',
+        to: 'NONE',
+      },
+      {
+        databaseId: 1234,
+        from: 'NONE',
+        to: 'TRAVEL_BASIC',
+      },
+      {
+        databaseId: 12345,
+        from: 'NONE',
+        to: 'TRAVEL_PLUS',
+      },
+    ];
+    const changesTravelBasic = [
+      {
+        databaseId: 123,
+        from: 'TRAVEL_BASIC',
+        to: 'TRAVEL_BASIC',
+      },
+      {
+        databaseId: 1234,
+        from: 'TRAVEL_BASIC',
+        to: 'NONE',
+      },
+      {
+        databaseId: 12345,
+        from: 'NONE',
+        to: 'TRAVEL_PLUS',
+      },
+    ];
+    const changesTravelPlus = [
+      {
+        databaseId: 123,
+        from: 'TRAVEL_PLUS',
+        to: 'TRAVEL_PLUS',
+      },
+      {
+        databaseId: 1234,
+        from: 'TRAVEL_BASIC',
+        to: 'NONE',
+      },
+      {
+        databaseId: 12345,
+        from: 'TRAVEL_PLUS',
+        to: 'TRAVEL_BASIC',
+      },
+    ];
+
+    const none = renderer.create(
+      <InsuranceRow
+        changes={changesNone}
+        insurancePrices={insurancePrices}
+        insuranceType="NONE"
+      />,
+    );
+    const travelBasic = renderer.create(
+      <InsuranceRow
+        changes={changesTravelBasic}
+        insurancePrices={insurancePrices}
+        insuranceType="TRAVEL_BASIC"
+      />,
+    );
+    const travelPlus = renderer.create(
+      <InsuranceRow
+        changes={changesTravelPlus}
+        insurancePrices={insurancePrices}
+        insuranceType="TRAVEL_PLUS"
+      />,
+    );
+    const instanceNone = none.getInstance();
+    expect(instanceNone).toBe(null);
+    const instanceTravelBasic = travelBasic.getInstance();
+    expect(instanceTravelBasic).toBe(null);
+    const instanceTravelPlus = travelPlus.getInstance();
+    expect(instanceTravelPlus).toBe(null);
+  });
+});
diff --git a/app/hotels/src/filter/stars/__tests__/__snapshots__/StarsFilter.test.js.snap b/app/hotels/src/filter/stars/__tests__/__snapshots__/StarsFilter.test.js.snap
index 8ad4d738..c5ec989d 100644
--- a/app/hotels/src/filter/stars/__tests__/__snapshots__/StarsFilter.test.js.snap
+++ b/app/hotels/src/filter/stars/__tests__/__snapshots__/StarsFilter.test.js.snap
@@ -2,7 +2,7 @@
 
 exports[`StarsFilter renders 1`] = `
 <React.Fragment>
-  <FilterButton
+  <FilterButtonWithContext
     icon={
       <Icon
         color="#7f91a8"