Repository: kiwicom/mobile
Pull request #1045 (2018-08-30 08:38:33)

MMB: Refactor boarding pass storage to use bookingId/flightNumber.pdf
I was trying to re-add sharing functionality (which somehow has disappeared 🙈 ), and it seems the share extension has some problems with url encoded characters. So a little refactor of the filenames was needed. 

We will now store it like `/boardingPasses/bookingId/flightNumber.pdf`


Patch:
diff --git a/app/MMB/src/scenes/tickets/TicketDeleteButton.js b/app/MMB/src/scenes/tickets/TicketDeleteButton.js
index 5c1dc890..eeeb7f27 100644
--- a/app/MMB/src/scenes/tickets/TicketDeleteButton.js
+++ b/app/MMB/src/scenes/tickets/TicketDeleteButton.js
@@ -65,7 +65,7 @@ export class TicketDeleteButton extends React.Component<
   deleteFilesPromise = async () => {
     try {
       await RNFetchBlob.fs.unlink(this.getEticketPath());
-      await this.deleteBoardingPasses();
+      await RNFetchBlob.fs.unlink(this.getBoardingPassPath());
       this.setState({ hasLocalFiles: false });
     } catch (error) {
       Alert.translatedAlert(null, {
@@ -75,34 +75,12 @@ export class TicketDeleteButton extends React.Component<
     }
   };
 
-  deleteBoardingPasses = async () => {
-    try {
-      const boardingPasses = await RNFetchBlob.fs.ls(
-        this.getBoardingPassPath(),
-      );
-      boardingPasses.forEach(async boardingPass => {
-        if (boardingPass.includes(`-bookingId:${this.props.bookingId}`)) {
-          await RNFetchBlob.fs.unlink(
-            `${this.getBoardingPassPath()}/${boardingPass}`,
-          );
-        }
-      });
-    } catch (error) {
-      throw error;
-    }
-  };
-
   hasLocalFiles = async () => {
     const existsEticket = await RNFetchBlob.fs.exists(this.getEticketPath());
-    const existsBoardingPasses = await this.hasLocalBoardingPasses();
-    this.setState({ hasLocalFiles: existsEticket || existsBoardingPasses });
-  };
-
-  hasLocalBoardingPasses = async () => {
-    const boardingPasses = await RNFetchBlob.fs.ls(this.getBoardingPassPath());
-    return boardingPasses.some(file =>
-      file.includes(`-bookingId:${this.props.bookingId}`),
+    const existsBoardingPasses = await RNFetchBlob.fs.exists(
+      this.getBoardingPassPath(),
     );
+    this.setState({ hasLocalFiles: existsEticket || existsBoardingPasses });
   };
 
   getEticketPath = () => {
@@ -114,7 +92,7 @@ export class TicketDeleteButton extends React.Component<
 
   getBoardingPassPath = () => {
     const { DocumentDir } = RNFetchBlob.fs.dirs;
-    return `${DocumentDir}/boardingPasses`;
+    return `${DocumentDir}/boardingPasses/${this.props.bookingId}`;
   };
 
   render = () => {
diff --git a/app/MMB/src/scenes/tickets/__generated__/TicketRefetchQuery.graphql.js b/app/MMB/src/scenes/tickets/__generated__/TicketRefetchQuery.graphql.js
index 95b45271..c1ce2834 100644
--- a/app/MMB/src/scenes/tickets/__generated__/TicketRefetchQuery.graphql.js
+++ b/app/MMB/src/scenes/tickets/__generated__/TicketRefetchQuery.graphql.js
@@ -1,6 +1,6 @@
 /**
  * @flow
- * @relayHash 4863ae16b1d47d7a471ba914acce5401
+ * @relayHash a55f1532ef590edf9a3d2e0c43241894
  */
 
 /* eslint-disable */
@@ -128,6 +128,7 @@ fragment FlightFromTo on Leg {
 }
 
 fragment DownloadButton on BoardingPass {
+  flightNumber
   boardingPassUrl
   ...BoardingPassInformation
 }
@@ -282,6 +283,13 @@ v5 = {
       "concreteType": "BoardingPass",
       "plural": false,
       "selections": [
+        {
+          "kind": "ScalarField",
+          "alias": null,
+          "name": "flightNumber",
+          "args": null,
+          "storageKey": null
+        },
         {
           "kind": "ScalarField",
           "alias": null,
@@ -351,7 +359,7 @@ return {
   "operationKind": "query",
   "name": "TicketRefetchQuery",
   "id": null,
-  "text": "query TicketRefetchQuery(\n  $id: ID!\n) {\n  node(id: $id) {\n    __typename\n    ... on BookingInterface {\n      ...TicketRefetch\n    }\n    id\n  }\n}\n\nfragment TicketRefetch on BookingInterface {\n  id\n  ...BoardingPasses\n  assets {\n    ...ETicket\n  }\n}\n\nfragment BoardingPasses on Node {\n  __typename\n  ... on BookingReturn {\n    ...BoardingPassReturn\n  }\n  ... on BookingOneWay {\n    ...BoardingPassOneWay\n  }\n  ... on BookingMulticity {\n    ...BoardingPassMultiCity\n  }\n}\n\nfragment ETicket on BookingAssets {\n  ticketUrl\n}\n\nfragment BoardingPassReturn on BookingReturn {\n  outbound {\n    ...FlightSegments\n  }\n  inbound {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassOneWay on BookingOneWay {\n  trip {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassMultiCity on BookingMulticity {\n  trips {\n    arrival {\n      airport {\n        city {\n          name\n        }\n        id\n      }\n    }\n    ...FlightSegments\n  }\n}\n\nfragment FlightSegments on Trip {\n  legs {\n    id\n    ...FlightFromTo\n  }\n}\n\nfragment FlightFromTo on Leg {\n  id\n  airline {\n    logoUrl\n  }\n  departure {\n    localTime\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  arrival {\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  boardingPass {\n    ...DownloadButton\n    ...AppleWallet\n  }\n}\n\nfragment DownloadButton on BoardingPass {\n  boardingPassUrl\n  ...BoardingPassInformation\n}\n\nfragment AppleWallet on BoardingPass {\n  pkpasses {\n    ...AppleWalletPassenger\n    passenger {\n      databaseId\n    }\n  }\n}\n\nfragment AppleWalletPassenger on Pkpass {\n  url\n  passenger {\n    fullName\n  }\n}\n\nfragment BoardingPassInformation on BoardingPass {\n  availableAt\n  boardingPassUrl\n  ...FutureBookingInformation\n}\n\nfragment FutureBookingInformation on BoardingPass {\n  boardingPassUrl\n}\n",
+  "text": "query TicketRefetchQuery(\n  $id: ID!\n) {\n  node(id: $id) {\n    __typename\n    ... on BookingInterface {\n      ...TicketRefetch\n    }\n    id\n  }\n}\n\nfragment TicketRefetch on BookingInterface {\n  id\n  ...BoardingPasses\n  assets {\n    ...ETicket\n  }\n}\n\nfragment BoardingPasses on Node {\n  __typename\n  ... on BookingReturn {\n    ...BoardingPassReturn\n  }\n  ... on BookingOneWay {\n    ...BoardingPassOneWay\n  }\n  ... on BookingMulticity {\n    ...BoardingPassMultiCity\n  }\n}\n\nfragment ETicket on BookingAssets {\n  ticketUrl\n}\n\nfragment BoardingPassReturn on BookingReturn {\n  outbound {\n    ...FlightSegments\n  }\n  inbound {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassOneWay on BookingOneWay {\n  trip {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassMultiCity on BookingMulticity {\n  trips {\n    arrival {\n      airport {\n        city {\n          name\n        }\n        id\n      }\n    }\n    ...FlightSegments\n  }\n}\n\nfragment FlightSegments on Trip {\n  legs {\n    id\n    ...FlightFromTo\n  }\n}\n\nfragment FlightFromTo on Leg {\n  id\n  airline {\n    logoUrl\n  }\n  departure {\n    localTime\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  arrival {\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  boardingPass {\n    ...DownloadButton\n    ...AppleWallet\n  }\n}\n\nfragment DownloadButton on BoardingPass {\n  flightNumber\n  boardingPassUrl\n  ...BoardingPassInformation\n}\n\nfragment AppleWallet on BoardingPass {\n  pkpasses {\n    ...AppleWalletPassenger\n    passenger {\n      databaseId\n    }\n  }\n}\n\nfragment AppleWalletPassenger on Pkpass {\n  url\n  passenger {\n    fullName\n  }\n}\n\nfragment BoardingPassInformation on BoardingPass {\n  availableAt\n  boardingPassUrl\n  ...FutureBookingInformation\n}\n\nfragment FutureBookingInformation on BoardingPass {\n  boardingPassUrl\n}\n",
   "metadata": {},
   "fragment": {
     "kind": "Fragment",
diff --git a/app/MMB/src/scenes/tickets/__generated__/TicketSceneQuery.graphql.js b/app/MMB/src/scenes/tickets/__generated__/TicketSceneQuery.graphql.js
index e69a4dc6..ddcfa572 100644
--- a/app/MMB/src/scenes/tickets/__generated__/TicketSceneQuery.graphql.js
+++ b/app/MMB/src/scenes/tickets/__generated__/TicketSceneQuery.graphql.js
@@ -1,6 +1,6 @@
 /**
  * @flow
- * @relayHash f6f71a6bb47819ddb1448373ab2c2611
+ * @relayHash c81a8202223402b6ccca75459ebd17db
  */
 
 /* eslint-disable */
@@ -128,6 +128,7 @@ fragment FlightFromTo on Leg {
 }
 
 fragment DownloadButton on BoardingPass {
+  flightNumber
   boardingPassUrl
   ...BoardingPassInformation
 }
@@ -294,6 +295,13 @@ v5 = {
       "concreteType": "BoardingPass",
       "plural": false,
       "selections": [
+        {
+          "kind": "ScalarField",
+          "alias": null,
+          "name": "flightNumber",
+          "args": null,
+          "storageKey": null
+        },
         {
           "kind": "ScalarField",
           "alias": null,
@@ -363,7 +371,7 @@ return {
   "operationKind": "query",
   "name": "TicketSceneQuery",
   "id": null,
-  "text": "query TicketSceneQuery(\n  $bookingId: Int!\n  $authToken: String!\n) {\n  singleBooking(id: $bookingId, authToken: $authToken) {\n    __typename\n    ...TicketRefetch\n    id\n  }\n}\n\nfragment TicketRefetch on BookingInterface {\n  id\n  ...BoardingPasses\n  assets {\n    ...ETicket\n  }\n}\n\nfragment BoardingPasses on Node {\n  __typename\n  ... on BookingReturn {\n    ...BoardingPassReturn\n  }\n  ... on BookingOneWay {\n    ...BoardingPassOneWay\n  }\n  ... on BookingMulticity {\n    ...BoardingPassMultiCity\n  }\n}\n\nfragment ETicket on BookingAssets {\n  ticketUrl\n}\n\nfragment BoardingPassReturn on BookingReturn {\n  outbound {\n    ...FlightSegments\n  }\n  inbound {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassOneWay on BookingOneWay {\n  trip {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassMultiCity on BookingMulticity {\n  trips {\n    arrival {\n      airport {\n        city {\n          name\n        }\n        id\n      }\n    }\n    ...FlightSegments\n  }\n}\n\nfragment FlightSegments on Trip {\n  legs {\n    id\n    ...FlightFromTo\n  }\n}\n\nfragment FlightFromTo on Leg {\n  id\n  airline {\n    logoUrl\n  }\n  departure {\n    localTime\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  arrival {\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  boardingPass {\n    ...DownloadButton\n    ...AppleWallet\n  }\n}\n\nfragment DownloadButton on BoardingPass {\n  boardingPassUrl\n  ...BoardingPassInformation\n}\n\nfragment AppleWallet on BoardingPass {\n  pkpasses {\n    ...AppleWalletPassenger\n    passenger {\n      databaseId\n    }\n  }\n}\n\nfragment AppleWalletPassenger on Pkpass {\n  url\n  passenger {\n    fullName\n  }\n}\n\nfragment BoardingPassInformation on BoardingPass {\n  availableAt\n  boardingPassUrl\n  ...FutureBookingInformation\n}\n\nfragment FutureBookingInformation on BoardingPass {\n  boardingPassUrl\n}\n",
+  "text": "query TicketSceneQuery(\n  $bookingId: Int!\n  $authToken: String!\n) {\n  singleBooking(id: $bookingId, authToken: $authToken) {\n    __typename\n    ...TicketRefetch\n    id\n  }\n}\n\nfragment TicketRefetch on BookingInterface {\n  id\n  ...BoardingPasses\n  assets {\n    ...ETicket\n  }\n}\n\nfragment BoardingPasses on Node {\n  __typename\n  ... on BookingReturn {\n    ...BoardingPassReturn\n  }\n  ... on BookingOneWay {\n    ...BoardingPassOneWay\n  }\n  ... on BookingMulticity {\n    ...BoardingPassMultiCity\n  }\n}\n\nfragment ETicket on BookingAssets {\n  ticketUrl\n}\n\nfragment BoardingPassReturn on BookingReturn {\n  outbound {\n    ...FlightSegments\n  }\n  inbound {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassOneWay on BookingOneWay {\n  trip {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassMultiCity on BookingMulticity {\n  trips {\n    arrival {\n      airport {\n        city {\n          name\n        }\n        id\n      }\n    }\n    ...FlightSegments\n  }\n}\n\nfragment FlightSegments on Trip {\n  legs {\n    id\n    ...FlightFromTo\n  }\n}\n\nfragment FlightFromTo on Leg {\n  id\n  airline {\n    logoUrl\n  }\n  departure {\n    localTime\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  arrival {\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  boardingPass {\n    ...DownloadButton\n    ...AppleWallet\n  }\n}\n\nfragment DownloadButton on BoardingPass {\n  flightNumber\n  boardingPassUrl\n  ...BoardingPassInformation\n}\n\nfragment AppleWallet on BoardingPass {\n  pkpasses {\n    ...AppleWalletPassenger\n    passenger {\n      databaseId\n    }\n  }\n}\n\nfragment AppleWalletPassenger on Pkpass {\n  url\n  passenger {\n    fullName\n  }\n}\n\nfragment BoardingPassInformation on BoardingPass {\n  availableAt\n  boardingPassUrl\n  ...FutureBookingInformation\n}\n\nfragment FutureBookingInformation on BoardingPass {\n  boardingPassUrl\n}\n",
   "metadata": {},
   "fragment": {
     "kind": "Fragment",
diff --git a/app/MMB/src/scenes/tickets/boardingPasses/DownloadButton.js b/app/MMB/src/scenes/tickets/boardingPasses/DownloadButton.js
index a7b78755..6114c740 100644
--- a/app/MMB/src/scenes/tickets/boardingPasses/DownloadButton.js
+++ b/app/MMB/src/scenes/tickets/boardingPasses/DownloadButton.js
@@ -23,6 +23,7 @@ class DownloadButton extends React.Component<Props> {
   navigateToBoardingPass = () => {
     this.props.navigation.navigate('mmb.tickets.boarding_pass', {
       boardingPassUrl: idx(this.props, _ => _.data.boardingPassUrl),
+      flightNumber: idx(this.props, _ => _.data.flightNumber),
     });
   };
 
@@ -49,6 +50,7 @@ export default createFragmentContainer(
   withNavigation(DownloadButton),
   graphql`
     fragment DownloadButton on BoardingPass {
+      flightNumber
       boardingPassUrl
       ...BoardingPassInformation
     }
diff --git a/app/MMB/src/scenes/tickets/boardingPasses/__generated__/DownloadButton.graphql.js b/app/MMB/src/scenes/tickets/boardingPasses/__generated__/DownloadButton.graphql.js
index 1281a933..a33025ab 100644
--- a/app/MMB/src/scenes/tickets/boardingPasses/__generated__/DownloadButton.graphql.js
+++ b/app/MMB/src/scenes/tickets/boardingPasses/__generated__/DownloadButton.graphql.js
@@ -12,6 +12,7 @@ type BoardingPassInformation$ref = any;
 import type { FragmentReference } from "relay-runtime";
 declare export opaque type DownloadButton$ref: FragmentReference;
 export type DownloadButton = {|
+  +flightNumber: ?string,
   +boardingPassUrl: ?string,
   +$fragmentRefs: BoardingPassInformation$ref,
   +$refType: DownloadButton$ref,
@@ -26,6 +27,13 @@ const node/*: ConcreteFragment*/ = {
   "metadata": null,
   "argumentDefinitions": [],
   "selections": [
+    {
+      "kind": "ScalarField",
+      "alias": null,
+      "name": "flightNumber",
+      "args": null,
+      "storageKey": null
+    },
     {
       "kind": "ScalarField",
       "alias": null,
@@ -41,5 +49,5 @@ const node/*: ConcreteFragment*/ = {
   ]
 };
 // prettier-ignore
-(node/*: any*/).hash = '2083b291900c2bf503115ebe519df49f';
+(node/*: any*/).hash = '377dd4859b8f63343575db0175eb213c';
 module.exports = node;
diff --git a/app/MMB/src/scenes/tickets/boardingPassesPdf/BoardingPassPdf.js b/app/MMB/src/scenes/tickets/boardingPassesPdf/BoardingPassPdf.js
index e655747f..f2d774b7 100644
--- a/app/MMB/src/scenes/tickets/boardingPassesPdf/BoardingPassPdf.js
+++ b/app/MMB/src/scenes/tickets/boardingPassesPdf/BoardingPassPdf.js
@@ -7,18 +7,6 @@ import { PdfViewAndStore } from '@kiwicom/mobile-pdf';
 
 import BookingDetailContext from '../../../context/BookingDetailContext';
 
-export const getPdfFilenameFromUrl = (url: string, bookingId: number) => {
-  const filename = url.slice(url.lastIndexOf('/') + 1);
-  const isPdf = filename.includes('.pdf');
-  if (!isPdf) {
-    return null;
-  }
-  return `${filename.slice(
-    0,
-    filename.indexOf('.pdf'),
-  )}-bookingId:${bookingId}`;
-};
-
 type PropsWithContext = {|
   ...Props,
   +bookingId: number,
@@ -27,19 +15,17 @@ type PropsWithContext = {|
 export const BoardingPassPdf = ({
   boardingPassUrl,
   bookingId,
+  flightNumber,
 }: PropsWithContext) => {
-  if (boardingPassUrl) {
-    const filename = getPdfFilenameFromUrl(boardingPassUrl, bookingId);
-
-    if (filename) {
-      return (
-        <PdfViewAndStore
-          fileName={`boardingPasses/${filename}.pdf`}
-          url={boardingPassUrl}
-        />
-      );
-    }
+  if (bookingId && flightNumber && boardingPassUrl) {
+    return (
+      <PdfViewAndStore
+        fileName={`boardingPasses/${bookingId}/${flightNumber}.pdf`}
+        url={boardingPassUrl}
+      />
+    );
   }
+
   return (
     <GeneralError
       errorMessage={<Translation id="mmb.boarding_passes.not_available" />}
@@ -49,6 +35,7 @@ export const BoardingPassPdf = ({
 
 type Props = {|
   +boardingPassUrl: ?string,
+  +flightNumber: string,
 |};
 
 export default function BoardingPassPdfWithContext(props: Props) {
diff --git a/app/MMB/src/scenes/tickets/boardingPassesPdf/BoardingPassPdfScreen.js b/app/MMB/src/scenes/tickets/boardingPassesPdf/BoardingPassPdfScreen.js
index d65561d6..57b07930 100644
--- a/app/MMB/src/scenes/tickets/boardingPassesPdf/BoardingPassPdfScreen.js
+++ b/app/MMB/src/scenes/tickets/boardingPassesPdf/BoardingPassPdfScreen.js
@@ -6,10 +6,14 @@ import BoardingPassesPdf from './BoardingPassPdf';
 
 type Props = {|
   +boardingPassUrl: ?string,
+  +flightNumber: string,
 |};
 
-const BoardingPassesPdfScreen = ({ boardingPassUrl }: Props) => (
-  <BoardingPassesPdf boardingPassUrl={boardingPassUrl} />
+const BoardingPassesPdfScreen = ({ boardingPassUrl, flightNumber }: Props) => (
+  <BoardingPassesPdf
+    boardingPassUrl={boardingPassUrl}
+    flightNumber={flightNumber}
+  />
 );
 
 export default BoardingPassesPdfScreen;
diff --git a/app/MMB/src/scenes/timeline/events/DownloadBoardingPassTimelineEvent.js b/app/MMB/src/scenes/timeline/events/DownloadBoardingPassTimelineEvent.js
index 9816fde8..b54e1cbf 100644
--- a/app/MMB/src/scenes/timeline/events/DownloadBoardingPassTimelineEvent.js
+++ b/app/MMB/src/scenes/timeline/events/DownloadBoardingPassTimelineEvent.js
@@ -34,6 +34,7 @@ class DownloadBoardingPassTimelineEvent extends React.Component<Props> {
         this.props,
         _ => _.data.leg.boardingPass.boardingPassUrl,
       ),
+      flightNumber: idx(this.props, _ => _.data.leg.boardingPass.flightNumber),
     });
   };
 


Test patch:
diff --git a/app/MMB/src/scenes/tickets/__tests__/TicketDeleteButton.test.js b/app/MMB/src/scenes/tickets/__tests__/TicketDeleteButton.test.js
index 73e771cc..49ec589e 100644
--- a/app/MMB/src/scenes/tickets/__tests__/TicketDeleteButton.test.js
+++ b/app/MMB/src/scenes/tickets/__tests__/TicketDeleteButton.test.js
@@ -2,16 +2,11 @@
 
 import * as React from 'react';
 import renderer from 'react-test-renderer';
-import RNFetchBlob from 'react-native-fetch-blob';
 
 import { TicketDeleteButton } from '../TicketDeleteButton';
 
 jest.mock('react-native-fetch-blob', () => {
-  let lsReturn = [];
   return {
-    setLsReturn: input => {
-      lsReturn = input;
-    },
     config: () => ({
       fetch: async () => ({
         path: () => {},
@@ -24,7 +19,7 @@ jest.mock('react-native-fetch-blob', () => {
       },
       exists: async () => true,
       unlink: async () => true,
-      ls: async () => lsReturn,
+      ls: async () => true,
     },
   };
 });
@@ -80,37 +75,4 @@ describe('TicketDeleteButton', () => {
     Component.componentDidUpdate({ isFocused: true, bookingId: 123456 });
     expect(spy).not.toHaveBeenCalled();
   });
-
-  describe('hasLocalBoardingPasses', () => {
-    it('should return false if no files has bookingId in filename', async () => {
-      const Component = new TicketDeleteButton({
-        bookingId: 123456,
-        isFocused: true,
-      });
-
-      RNFetchBlob.setLsReturn([
-        'test-bookingId:123.pdf',
-        'lol-bookingId:321.pdf',
-      ]);
-
-      const hasLocalBoardingPasses = await Component.hasLocalBoardingPasses();
-      expect(hasLocalBoardingPasses).toEqual(false);
-    });
-
-    it('should return true if any file has bookingId in filename', async () => {
-      const Component = new TicketDeleteButton({
-        bookingId: 123456,
-        isFocused: true,
-      });
-
-      RNFetchBlob.setLsReturn([
-        'test-bookingId:123.pdf',
-        'lol-bookingId:321.pdf',
-        'lol-bookingId:123456.pdf',
-      ]);
-
-      const hasLocalBoardingPasses = await Component.hasLocalBoardingPasses();
-      expect(hasLocalBoardingPasses).toEqual(true);
-    });
-  });
 });
diff --git a/app/MMB/src/scenes/tickets/boardingPassesPdf/__tests__/BoardingPassPdf.test.js b/app/MMB/src/scenes/tickets/boardingPassesPdf/__tests__/BoardingPassPdf.test.js
index f96785d5..43dcf062 100644
--- a/app/MMB/src/scenes/tickets/boardingPassesPdf/__tests__/BoardingPassPdf.test.js
+++ b/app/MMB/src/scenes/tickets/boardingPassesPdf/__tests__/BoardingPassPdf.test.js
@@ -5,7 +5,7 @@ import ShallowRenderer from 'react-test-renderer/shallow';
 
 const renderer = new ShallowRenderer();
 
-import { getPdfFilenameFromUrl, BoardingPassPdf } from '../BoardingPassPdf';
+import { BoardingPassPdf } from '../BoardingPassPdf';
 
 jest.mock('react-native-fetch-blob', () => {
   return {
@@ -24,43 +24,71 @@ jest.mock('react-native-fetch-blob', () => {
   };
 });
 
-const bookingId = 123456;
+const getWrapper = (
+  bookingId: number = 123456,
+  BoardingPassUrl: string = 'https://somedomain.com/folder/subfolder/file.pdf',
+  flightNumber: string = '123_321',
+) =>
+  renderer.render(
+    <BoardingPassPdf
+      bookingId={bookingId}
+      boardingPassUrl={BoardingPassUrl}
+      flightNumber={flightNumber}
+    />,
+  );
 
 describe('BoardingPassPdf', () => {
   it('renders', () => {
-    const wrapper = renderer.render(
-      <BoardingPassPdf
-        bookingId={bookingId}
-        boardingPassUrl="https://somedomain.com/folder/subfolder/file.pdf"
-      />,
-    );
+    const wrapper = getWrapper();
 
-    expect(wrapper.props.fileName).toBe(
-      'boardingPasses/file-bookingId:123456.pdf',
-    );
+    expect(wrapper).toMatchInlineSnapshot(`
+<PdfViewAndStore
+  fileName="boardingPasses/123456/123_321.pdf"
+  overwriteExisting={false}
+  url="https://somedomain.com/folder/subfolder/file.pdf"
+/>
+`);
   });
-});
-
-describe('getPdfFilenameFromUrl', () => {
-  it('should return correct filename given the URL of a pdf', () => {
-    const url =
-      'https://somedomainname.com/numbers1234/Vienna-Palma%2CMajorca_1234567890_5bafa3bd88fbf8e8c90a0a.pdf?v=12345676';
 
-    expect(getPdfFilenameFromUrl(url, bookingId)).toBe(
-      'Vienna-Palma%2CMajorca_1234567890_5bafa3bd88fbf8e8c90a0a-bookingId:123456',
-    );
-    const pdf = 'somePdf.pdf';
-    expect(getPdfFilenameFromUrl(pdf, bookingId)).toBe(
-      'somePdf-bookingId:123456',
-    );
+  it('show error if bookingId is missing', () => {
+    // $FlowExpectedError: Intentionally testing what happens with null value
+    const wrapper = getWrapper(null);
+    expect(wrapper).toMatchInlineSnapshot(`
+<GeneralError
+  errorMessage={
+    <Translation
+      id="mmb.boarding_passes.not_available"
+    />
+  }
+/>
+`);
   });
 
-  it('should return null if given a URL not containing .pdf', () => {
-    const url =
-      'https://somedomainname.com/numbers1234/Vienna-Palma%2CMajorca_1234567890_5bafa3bd88fbf8e8c90a0a.doc?v=12345676';
+  it('show error if boardingPassUrl is missing', () => {
+    // $FlowExpectedError: Intentionally testing what happens with null value
+    const wrapper = getWrapper(123, null);
+    expect(wrapper).toMatchInlineSnapshot(`
+<GeneralError
+  errorMessage={
+    <Translation
+      id="mmb.boarding_passes.not_available"
+    />
+  }
+/>
+`);
+  });
 
-    expect(getPdfFilenameFromUrl(url, bookingId)).toBe(null);
-    const pdf = 'someNonPdf.xls';
-    expect(getPdfFilenameFromUrl(pdf, bookingId)).toBe(null);
+  it('show error if flightNumber is missing', () => {
+    // $FlowExpectedError: Intentionally testing what happens with null value
+    const wrapper = getWrapper(123, 'test', null);
+    expect(wrapper).toMatchInlineSnapshot(`
+<GeneralError
+  errorMessage={
+    <Translation
+      id="mmb.boarding_passes.not_available"
+    />
+  }
+/>
+`);
   });
 });