import { promises as fs } from "fs" ; import * as path from "path" ; import { filesSymbol , freezeSymbol } from "../lib/Bundle" ; import FieldsArray from "../lib/FieldsArray" ; import { PassProps } from "../lib/schemas" ; import * as Messages from "../lib/messages" ; import { default as PKPass , localizationSymbol , certificatesSymbol , propsSymbol , passTypeSymbol , importMetadataSymbol , closePassSymbol , createManifestSymbol , } from "../lib/PKPass" ; describe ( "PKPass" , ( ) => { let pass ; const baseCerts = { signerCert : "" , signerKey : "" , wwdr : "" , signerKeyPassphrase : "p477w0rb" , } ; beforeEach ( ( ) => { pass = new PKPass ( { } ) ; console . warn = jasmine . createSpy ( "warn_logging" ) ; } ) ; describe ( "constructor" , ( ) => { it ( "should warn about a non-object buffer parameter" , ( ) => { pass = new PKPass ( undefined , baseCerts ) ; expect ( console . warn ) . toHaveBeenCalledWith ( Messages . INIT . INVALID_BUFFERS . replace ( "%s" , "undefined" ) ) ; } ) ; } ) ; describe ( "setBeacons" , ( ) => { it ( "should reset instance.props['beacons'] if 'null' is passed as value" , ( ) => { pass . setBeacons ( { proximityUUID : "0000000000-00000000" , major : 4 , minor : 3 , relevantText : "This is not the Kevin you are looking for." , } ) ; expect ( pass . props [ "beacons" ] . length ) . toBe ( 1 ) ; pass . setBeacons ( null ) ; expect ( pass . props [ "beacons" ] ) . toBeUndefined ( ) ; } ) ; it ( "should filter out invalid beacons objects" , ( ) => { /** This is invalid, major should be greater than minor */ pass . setBeacons ( { proximityUUID : "0000000000-00000000" , major : 2 , minor : 3 , relevantText : "This is not the Kevin you are looking for." , } , { major : 2 , minor : 3 , } , { proximityUUID : "0000000000-00000" , major : 2 , minor : 1 , } ) ; expect ( pass . props [ "beacons" ] . length ) . toBe ( 1 ) ; } ) ; it ( "should always return undefined" , ( ) => { expect ( pass . setBeacons ( null ) ) . toBeUndefined ( ) ; expect ( pass . setBeacons ( { proximityUUID : "0000000000-00000000" , major : 2 , minor : 3 , relevantText : "This is not the Kevin you are looking for." , } ) ) . toBeUndefined ( ) ; } ) ; } ) ; describe ( "setLocations" , ( ) => { it ( "should reset instance.props['locations'] if 'null' is passed as value" , ( ) => { pass . setLocations ( { longitude : 0.25456342344 , latitude : 0.26665773234 , } ) ; expect ( pass . props [ "locations" ] . length ) . toBe ( 1 ) ; pass . setLocations ( null ) ; expect ( pass . props [ "locations" ] ) . toBeUndefined ( ) ; } ) ; it ( "should filter out invalid beacons objects" , ( ) => { pass . setLocations ( { longitude : "unknown" , latitude : "unknown" , } , { altitude : "say hello from here" , longitude : 0.25456342344 , } , { longitude : 0.25456342344 , latitude : 0.26665773234 , altitude : 12552.31233321 , relevantText : "Ciao mamma, guarda come volooo!" , } ) ; expect ( pass . props [ "locations" ] . length ) . toBe ( 1 ) ; expect ( pass . props [ "locations" ] [ 0 ] . longitude ) . toBe ( 0.25456342344 ) ; expect ( pass . props [ "locations" ] [ 0 ] . latitude ) . toBe ( 0.26665773234 ) ; expect ( pass . props [ "locations" ] [ 0 ] . altitude ) . toBe ( 12552.31233321 ) ; expect ( pass . props [ "locations" ] [ 0 ] . relevantText ) . toBe ( "Ciao mamma, guarda come volooo!" ) ; } ) ; it ( "should always return undefined" , ( ) => { expect ( pass . setLocations ( null ) ) . toBeUndefined ( ) ; expect ( pass . setLocations ( { longitude : 0.25456342344 , latitude : 0.26665773234 , altitude : 12552.31233321 , } ) ) . toBeUndefined ( ) ; } ) ; } ) ; describe ( "setNFC" , ( ) => { it ( "should reset instance.props['nfc'] if 'null' is passed as value" , ( ) => { pass . setNFC ( { encryptionPublicKey : "mimmo" , message : "No message for you here" , } ) ; expect ( pass . props [ "nfc" ] ) . toEqual ( { encryptionPublicKey : "mimmo" , message : "No message for you here" , } ) ; pass . setNFC ( null ) ; expect ( pass . props [ "nfc" ] ) . toBeUndefined ( ) ; } ) ; it ( "should throw on invalid objects received" , ( ) => { expect ( ( ) => pass . setNFC ( { requiresAuth : false , encryptionPublicKey : "Nope" , } ) ) . toThrow ( ) ; } ) ; it ( "should always return undefined" , ( ) => { expect ( pass . setNFC ( null ) ) . toBeUndefined ( ) ; expect ( pass . setNFC ( { encryptionPublicKey : "mimmo" , message : "No message for you here" , } ) ) . toBeUndefined ( ) ; } ) ; } ) ; describe ( "setExpirationDate" , ( ) => { it ( "should reset instance.props['expirationDate'] if 'null' is passed as value" , ( ) => { pass . setExpirationDate ( new Date ( 2020 , 6 , 1 , 0 , 0 , 0 , 0 ) ) ; expect ( pass . props [ "expirationDate" ] ) . toBe ( "2020-07-01T00:00:00Z" ) ; pass . setExpirationDate ( null ) ; expect ( pass . props [ "expirationDate" ] ) . toBeUndefined ( ) ; } ) ; it ( "expects a Date object as the only argument" , ( ) => { pass . setExpirationDate ( new Date ( 2020 , 6 , 1 , 0 , 0 , 0 , 0 ) ) ; expect ( pass . props [ "expirationDate" ] ) . toBe ( "2020-07-01T00:00:00Z" ) ; } ) ; it ( "should throw if an invalid date is received" , ( ) => { expect ( ( ) => pass . setExpirationDate ( "32/18/228317" ) ) . toThrowError ( TypeError , "Cannot set expirationDate. Invalid date 32/18/228317" ) ; expect ( ( ) => pass . setExpirationDate ( undefined ) ) . toThrowError ( TypeError , "Cannot set expirationDate. Invalid date undefined" ) ; expect ( ( ) => pass . setExpirationDate ( 5 ) ) . toThrowError ( TypeError , "Cannot set expirationDate. Invalid date 5" ) ; expect ( ( ) => pass . setExpirationDate ( { } ) ) . toThrowError ( TypeError , "Cannot set expirationDate. Invalid date [object Object]" ) ; } ) ; it ( "should always return undefined" , ( ) => { expect ( pass . setExpirationDate ( null ) ) . toBeUndefined ( ) ; expect ( pass . setExpirationDate ( new Date ( 2020 , 6 , 1 , 0 , 0 , 0 , 0 ) ) ) . toBeUndefined ( ) ; } ) ; } ) ; describe ( "setRelevantDate" , ( ) => { it ( "should reset instance.props['relevantDate'] if 'null' is passed as value" , ( ) => { pass . setRelevantDate ( new Date ( 2020 , 6 , 1 , 0 , 0 , 0 , 0 ) ) ; expect ( pass . props [ "relevantDate" ] ) . toBe ( "2020-07-01T00:00:00Z" ) ; pass . setRelevantDate ( null ) ; expect ( pass . props [ "relevantDate" ] ) . toBeUndefined ( ) ; } ) ; it ( "expects a Date object as the only argument" , ( ) => { pass . setRelevantDate ( new Date ( "10-04-2021" ) ) ; expect ( pass . props [ "relevantDate" ] ) . toBe ( "2021-10-04T00:00:00Z" ) ; } ) ; it ( "should throw if an invalid date is received" , ( ) => { expect ( ( ) => pass . setRelevantDate ( "32/18/228317" ) ) . toThrowError ( TypeError , "Cannot set relevantDate. Invalid date 32/18/228317" ) ; expect ( ( ) => pass . setRelevantDate ( undefined ) ) . toThrowError ( TypeError , "Cannot set relevantDate. Invalid date undefined" ) ; expect ( ( ) => pass . setRelevantDate ( 5 ) ) . toThrowError ( TypeError , "Cannot set relevantDate. Invalid date 5" ) ; expect ( ( ) => pass . setRelevantDate ( { } ) ) . toThrowError ( TypeError , "Cannot set relevantDate. Invalid date [object Object]" ) ; } ) ; it ( "should always return undefined" , ( ) => { expect ( pass . setRelevantDate ( null ) ) . toBeUndefined ( ) ; expect ( pass . setRelevantDate ( new Date ( 2020 , 6 , 1 , 0 , 0 , 0 , 0 ) ) ) . toBeUndefined ( ) ; } ) ; } ) ; describe ( "setBarcodes" , ( ) => { it ( "shouldn't apply changes if no data is passed" , ( ) => { const props = pass . props [ "barcodes" ] || [ ] ; const oldAmountOfBarcodes = props ?. length ?? 0 ; pass . setBarcodes ( ) ; expect ( pass . props [ "barcodes" ] ?. length || 0 ) . toBe ( oldAmountOfBarcodes ) ; } ) ; it ( "should autogenerate all the barcodes objects if a string is provided as message" , ( ) => { pass . setBarcodes ( "28363516282" ) ; expect ( pass . props [ "barcodes" ] . length ) . toBe ( 4 ) ; } ) ; it ( "should save changes if object conforming to Schemas.Barcode are provided" , ( ) => { pass . setBarcodes ( { message : "28363516282" , format : "PKBarcodeFormatPDF417" , messageEncoding : "utf8" , } ) ; expect ( pass . props [ "barcodes" ] . length ) . toBe ( 1 ) ; } ) ; it ( "should add 'messageEncoding' if missing in valid Schema.Barcode parameters" , ( ) => { pass . setBarcodes ( { message : "28363516282" , format : "PKBarcodeFormatPDF417" , } ) ; expect ( pass . props [ "barcodes" ] [ 0 ] . messageEncoding ) . toBe ( "iso-8859-1" ) ; } ) ; it ( "should ignore objects without 'message' property in Schema.Barcode" , ( ) => { pass . setBarcodes ( { format : "PKBarcodeFormatCode128" , message : "No one can validate meeee" , } , { format : "PKBarcodeFormatPDF417" , } ) ; expect ( pass . props [ "barcodes" ] . length ) . toBe ( 1 ) ; } ) ; it ( "should ignore objects and values that not comply with Schema.Barcodes" , ( ) => { const setBarcodesArguments = [ 5 , 10 , 15 , { message : "28363516282" , format : "PKBarcodeFormatPDF417" , } , 7 , 1 , ] ; pass . setBarcodes ( ... setBarcodesArguments ) ; expect ( pass . props [ "barcodes" ] . length ) . toBe ( 1 ) ; } ) ; it ( "should reset barcodes content if parameter is null" , ( ) => { pass . setBarcodes ( { message : "28363516282" , format : "PKBarcodeFormatPDF417" , messageEncoding : "utf8" , } ) ; expect ( pass . props [ "barcodes" ] . length ) . toBe ( 1 ) ; pass . setBarcodes ( null ) ; expect ( pass . props [ "barcodes" ] ) . toBe ( undefined ) ; } ) ; it ( "should always return undefined" , ( ) => { expect ( pass . setBarcodes ( null ) ) . toBeUndefined ( ) ; expect ( pass . setBarcodes ( { message : "28363516282" , format : "PKBarcodeFormatPDF417" , messageEncoding : "utf8" , } ) ) . toBeUndefined ( ) ; } ) ; } ) ; describe ( "transitType" , ( ) => { it ( "should accept a new value only if the pass is a boarding pass" , ( ) => { const passBP = new PKPass ( { "pass.json" : Buffer . from ( JSON . stringify ( { boardingPass : { } , } ) ) , } , baseCerts , { } ) ; const passCP = new PKPass ( { "pass.json" : Buffer . from ( JSON . stringify ( { coupon : { } , } ) ) , } , baseCerts , { } ) ; passBP . transitType = "PKTransitTypeAir" ; expect ( passBP . transitType ) . toBe ( "PKTransitTypeAir" ) ; expect ( ( ) => ( passCP . transitType = "PKTransitTypeAir" ) ) . toThrowError ( TypeError , Messages . TRANSIT_TYPE . UNEXPECTED_PASS_TYPE ) ; /** boardingPass property doesn't exists, so it throws */ expect ( ( ) => passCP . transitType ) . toThrow ( ) ; } ) ; } ) ; describe ( "certificates" , ( ) => { it ( "should throw an error if certificates provided are not complete or invalid" , ( ) => { expect ( ( ) => { pass . certificates = { signerCert : "" , } ; } ) . toThrow ( ) ; expect ( ( ) => { pass . certificates = { signerCert : 5 , signerKey : 3 , wwdr : "" , } ; } ) . toThrow ( ) ; expect ( ( ) => { pass . certificates = { signerCert : undefined , signerKey : null , wwdr : "" , } ; } ) . toThrow ( ) ; } ) ; it ( "should accept complete object" , ( ) => { pass . certificates = baseCerts ; expect ( pass [ certificatesSymbol ] ) . toEqual ( baseCerts ) ; pass = new PKPass ( { } , baseCerts ) ; expect ( pass [ certificatesSymbol ] ) . toEqual ( baseCerts ) ; } ) ; } ) ; describe ( "fields getters" , ( ) => { it ( "should throw error if a type has not been defined" , ( ) => { expect ( ( ) => pass . primaryFields ) . toThrowError ( TypeError ) ; expect ( ( ) => pass . secondaryFields ) . toThrowError ( TypeError ) ; expect ( ( ) => pass . auxiliaryFields ) . toThrowError ( TypeError ) ; expect ( ( ) => pass . headerFields ) . toThrowError ( TypeError ) ; expect ( ( ) => pass . backFields ) . toThrowError ( TypeError ) ; } ) ; it ( "should return an instance of FieldsArray if a type have been set" , ( ) => { pass . type = "boardingPass" ; expect ( pass . primaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . secondaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . auxiliaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . headerFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . backFields ) . toBeInstanceOf ( FieldsArray ) ; /** Resetting Fields, when setting type */ pass . type = "coupon" ; expect ( pass . primaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . secondaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . auxiliaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . headerFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . backFields ) . toBeInstanceOf ( FieldsArray ) ; /** Resetting Fields, when setting type */ pass . type = "storeCard" ; expect ( pass . primaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . secondaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . auxiliaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . headerFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . backFields ) . toBeInstanceOf ( FieldsArray ) ; /** Resetting Fields, when setting type */ pass . type = "eventTicket" ; expect ( pass . primaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . secondaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . auxiliaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . headerFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . backFields ) . toBeInstanceOf ( FieldsArray ) ; /** Resetting Fields, when setting type */ pass . type = "generic" ; expect ( pass . primaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . secondaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . auxiliaryFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . headerFields ) . toBeInstanceOf ( FieldsArray ) ; expect ( pass . backFields ) . toBeInstanceOf ( FieldsArray ) ; } ) ; } ) ; describe ( "type" , ( ) => { describe ( "getter" , ( ) => { it ( "should return undefined if no type have been setted" , ( ) => { expect ( pass . type ) . toBeUndefined ( ) ; } ) ; it ( "should return a type if set through pass.json" , ( ) => { pass . addBuffer ( "pass.json" , Buffer . from ( JSON . stringify ( { boardingPass : { } , } ) ) ) ; expect ( pass . type ) . toBe ( "boardingPass" ) ; } ) ; } ) ; describe ( "setter" , ( ) => { it ( "should throw error if a non recognized type is assigned" , ( ) => { expect ( ( ) => ( pass . type = "asfdg" ) ) . toThrow ( ) ; } ) ; it ( "should save the new type under a Symbol in class instance" , ( ) => { pass . type = "boardingPass" ; expect ( pass [ passTypeSymbol ] ) . toBe ( "boardingPass" ) ; } ) ; it ( "should reset fields if they have been previously set" , ( ) => { pass . type = "boardingPass" ; const { primaryFields , secondaryFields , auxiliaryFields , headerFields , backFields , } = pass ; pass . type = "coupon" ; expect ( pass . primaryFields ) . not . toBe ( primaryFields ) ; expect ( pass . secondaryFields ) . not . toBe ( secondaryFields ) ; expect ( pass . auxiliaryFields ) . not . toBe ( auxiliaryFields ) ; expect ( pass . headerFields ) . not . toBe ( headerFields ) ; expect ( pass . backFields ) . not . toBe ( backFields ) ; } ) ; it ( "should delete the previous type if previously setted" , ( ) => { pass . type = "boardingPass" ; pass . type = "coupon" ; expect ( pass [ "boardingPass" ] ) . toBeUndefined ( ) ; } ) ; } ) ; } ) ; describe ( "languages" , ( ) => { it ( "should get updated when translations gets added through localize" , ( ) => { expect ( pass . languages . length ) . toBe ( 0 ) ; expect ( pass . languages ) . toEqual ( [ ] ) ; pass . localize ( "en" , { buon_giorno : "Good Morning" , buona_sera : "Good Evening" , } ) ; expect ( pass . languages . length ) . toBe ( 1 ) ; expect ( pass . languages ) . toEqual ( [ "en" ] ) ; } ) ; it ( "should get updated when translations are added through .addBuffer" , ( ) => { const validTranslationStringsEN = `
/* Insert Element menu item */
"Insert Element" = "Insert Element";
/* Error string used for unknown error types. */
"ErrorString_1" = "An unknown error occurred.";
			` ; pass . addBuffer ( "en.lproj/pass.strings" , Buffer . from ( validTranslationStringsEN ) ) ; const validTranslationStringsIT = `
"Insert Element" = "Inserisci elemento";
"ErrorString_1" = "Un errore sconosciuto è accaduto";
			` ; pass . addBuffer ( "it.lproj/pass.strings" , Buffer . from ( validTranslationStringsIT ) ) ; expect ( pass . languages ) . toEqual ( [ "en" , "it" ] ) ; } ) ; } ) ; describe ( "localize" , ( ) => { it ( "should fail throw if lang is not a string" , ( ) => { expect ( ( ) => pass . localize ( null ) ) . toThrowError ( TypeError , Messages . LANGUAGES . INVALID_LANG . replace ( "%s" , "object" ) ) ; expect ( ( ) => pass . localize ( undefined ) ) . toThrowError ( TypeError , Messages . LANGUAGES . INVALID_LANG . replace ( "%s" , "undefined" ) ) ; expect ( ( ) => pass . localize ( 5 ) ) . toThrowError ( TypeError , Messages . LANGUAGES . INVALID_LANG . replace ( "%s" , "number" ) ) ; expect ( ( ) => pass . localize ( true ) ) . toThrowError ( TypeError , Messages . LANGUAGES . INVALID_LANG . replace ( "%s" , "boolean" ) ) ; expect ( ( ) => pass . localize ( { } ) ) . toThrowError ( TypeError , Messages . LANGUAGES . INVALID_LANG . replace ( "%s" , "object" ) ) ; } ) ; it ( "should warn developer if no translations have been passed" , ( ) => { pass . localize ( "en" ) ; pass . localize ( "en" , { } ) ; expect ( console . warn ) . toHaveBeenCalledWith ( Messages . LANGUAGES . NO_TRANSLATIONS . replace ( "%s" , "en" ) ) ; expect ( console . warn ) . toHaveBeenCalledTimes ( 2 ) ; } ) ; it ( "should create a new language record if some translations are specifies" , ( ) => { pass . localize ( "en" , { buon_giorno : "Good Morning" , buona_sera : "Good Evening" , } ) ; expect ( pass [ localizationSymbol ] [ "en" ] ) . toEqual ( { buon_giorno : "Good Morning" , buona_sera : "Good Evening" , } ) ; } ) ; it ( "should accept later translations and merge them with existing ones" , ( ) => { pass . localize ( "it" , { say_hi : "ciao" , say_gb : "arrivederci" , } ) ; pass . localize ( "it" , { say_good_morning : "buongiorno" , say_good_evening : "buonasera" , } ) ; expect ( pass [ localizationSymbol ] [ "it" ] ) . toEqual ( { say_hi : "ciao" , say_gb : "arrivederci" , say_good_morning : "buongiorno" , say_good_evening : "buonasera" , } ) ; } ) ; it ( "should delete a language, all of its translations and all of its files, when null is passed as parameter" , ( ) => { pass . addBuffer ( "it.lproj/icon@3x.png" , Buffer . alloc ( 0 ) ) ; pass . addBuffer ( "en.lproj/icon@3x.png" , Buffer . alloc ( 0 ) ) ; pass . localize ( "it" , null ) ; pass . localize ( "en" , null ) ; expect ( pass [ localizationSymbol ] [ "it" ] ) . toBeUndefined ( ) ; expect ( pass [ localizationSymbol ] [ "en" ] ) . toBeUndefined ( ) ; expect ( pass [ filesSymbol ] [ "it.lproj/icon@3x.png" ] ) . toBeUndefined ( ) ; expect ( pass [ filesSymbol ] [ "en.lproj/icon@3x.png" ] ) . toBeUndefined ( ) ; } ) ; it ( "should always return undefined" , ( ) => { expect ( pass . localize ( "it" , null ) ) . toBeUndefined ( ) ; expect ( pass . localize ( "it" , { say_good_morning : "buongiorno" , say_good_evening : "buonasera" , } ) ) . toBeUndefined ( ) ; } ) ; } ) ; describe ( "addBuffer" , ( ) => { it ( "should filter out silently manifest and signature files" , ( ) => { pass . addBuffer ( "manifest.json" , Buffer . alloc ( 0 ) ) ; pass . addBuffer ( "signature" , Buffer . alloc ( 0 ) ) ; expect ( Object . keys ( pass [ filesSymbol ] ) . length ) . toBe ( 0 ) ; } ) ; it ( "should accept a pass.json only if not yet imported" , ( ) => { pass . addBuffer ( "pass.json" , Buffer . from ( JSON . stringify ( { boardingPass : { } , serialNumber : "555555" , } ) ) ) ; expect ( Object . keys ( pass [ filesSymbol ] ) . length ) . toBe ( 1 ) ; /** Adding it again */ pass . addBuffer ( "pass.json" , Buffer . from ( JSON . stringify ( { boardingPass : { } , serialNumber : "555555" , } ) ) ) ; /** Expecting it to get ignored */ expect ( Object . keys ( pass [ filesSymbol ] ) . length ) . toBe ( 1 ) ; } ) ; it ( "should accept personalization.json only if it is a valid JSON" , ( ) => { pass . addBuffer ( "personalization.json" , Buffer . from ( JSON . stringify ( { description : "A test description for a test personalization" , requiredPersonalizationFields : [ "PKPassPersonalizationFieldName" , "PKPassPersonalizationFieldPostalCode" , "PKPassPersonalizationFieldEmailAddress" , ] , } ) ) ) ; expect ( pass [ filesSymbol ] [ "personalization.json" ] ) . toBeInstanceOf ( Buffer ) ; } ) ; it ( "should reject invalid personalization.json" , ( ) => { pass . addBuffer ( "personalization.json" , Buffer . from ( JSON . stringify ( { requiredPersonalizationFields : [ "PKPassPersonalizationFieldName" , "PKPassPersonalizationFieldEmailAddressaworng" , ] , } ) ) ) ; expect ( pass [ filesSymbol ] [ "personalization.json" ] ) . toBeUndefined ( Buffer ) ; } ) ; it ( "should redirect .strings files to localization" , ( ) => { const validTranslationStrings = `
/* Insert Element menu item */
"Insert Element" = "Insert Element";
/* Error string used for unknown error types. */
"ErrorString_1" = "An unknown error occurred.";
			` ; pass . addBuffer ( "en.lproj/pass.strings" , Buffer . from ( validTranslationStrings ) ) ; expect ( pass [ filesSymbol ] [ "en.lproj/pass.string" ] ) . toBeUndefined ( ) ; expect ( pass [ localizationSymbol ] [ "en" ] ) . toEqual ( { "Insert Element" : "Insert Element" , ErrorString_1 : "An unknown error occurred." , } ) ; } ) ; it ( "should ignore invalid .strings files" , ( ) => { const invalidTranslationStrings = `
"Insert Element"="Insert Element
"ErrorString_1= "An unknown error occurred."
			` ; pass . addBuffer ( "en.lproj/pass.strings" , Buffer . from ( invalidTranslationStrings ) ) ; expect ( pass [ filesSymbol ] [ "en.lproj/pass.string" ] ) . toBeUndefined ( ) ; expect ( pass [ localizationSymbol ] [ "en" ] ) . toBeUndefined ( ) ; } ) ; it ( "should convert Windows paths to single UNIX slash" , ( ) => { if ( path . sep === "\\" ) { pass . addBuffer ( "en.lproj\\icon@2x.png" , Buffer . alloc ( 0 ) ) ; expect ( pass [ filesSymbol ] [ "en.lproj/icon@2x.png" ] ) . toBeDefined ( ) ; expect ( pass [ filesSymbol ] [ "en.lproj\\icon@2x.png" ] ) . toBeUndefined ( ) ; } } ) ; } ) ; describe ( "[importMetadataSymbol]" , ( ) => { it ( "should read data and set type" , ( ) => { pass [ importMetadataSymbol ] ( { boardingPass : { } , } ) ; expect ( pass . type ) . toBe ( "boardingPass" ) ; } ) ; it ( "should push fields to their own fields if a type is found" , ( ) => { const baseField = { key : "0" , value : "n/a" , label : "n/d" , } ; pass [ importMetadataSymbol ] ( { boardingPass : { primaryFields : [ { ... baseField , key : "pf0" } ] , secondaryFields : [ { ... baseField , key : "sf0" } ] , auxiliaryFields : [ { ... baseField , key : "af0" } ] , headerFields : [ { ... baseField , key : "hf0" } ] , backFields : [ { ... baseField , key : "bf0" } ] , } , } as PassProps ) ; expect ( pass . primaryFields [ 0 ] ) . toEqual ( { ... baseField , key : "pf0" } ) ; expect ( pass . secondaryFields [ 0 ] ) . toEqual ( { ... baseField , key : "sf0" , } ) ; expect ( pass . auxiliaryFields [ 0 ] ) . toEqual ( { ... baseField , key : "af0" , } ) ; expect ( pass . headerFields [ 0 ] ) . toEqual ( { ... baseField , key : "hf0" } ) ; expect ( pass . backFields [ 0 ] ) . toEqual ( { ... baseField , key : "bf0" } ) ; } ) ; } ) ; describe ( "[closePassSymbol]" , ( ) => { beforeEach ( ( ) => { pass . addBuffer ( "pass.json" , Buffer . from ( JSON . stringify ( { coupon : { headerFields : [ ] , primaryFields : [ ] , auxiliaryFields : [ ] , secondaryFields : [ ] , backFields : [ ] , } , serialNumber : "h12kj5b12k3331" , } as PassProps ) ) ) ; } ) ; it ( "should add props to pass.json" , ( ) => { pass . setBarcodes ( { format : "PKBarcodeFormatQR" , message : "meh a test barcode" , } ) ; pass . addBuffer ( "icon@2x.png" , Buffer . alloc ( 0 ) ) ; pass [ closePassSymbol ] ( true ) ; expect ( JSON . parse ( pass [ filesSymbol ] [ "pass.json" ] . toString ( "utf-8" ) ) ) . toEqual ( { formatVersion : 1 , coupon : { headerFields : [ ] , primaryFields : [ ] , auxiliaryFields : [ ] , secondaryFields : [ ] , backFields : [ ] , } , serialNumber : "h12kj5b12k3331" , barcodes : [ { format : "PKBarcodeFormatQR" , message : "meh a test barcode" , messageEncoding : "iso-8859-1" , } , ] , } ) ; } ) ; it ( "Should warn user if no icons have been added to bundle" , ( ) => { pass [ closePassSymbol ] ( true ) ; expect ( console . warn ) . toHaveBeenCalledWith ( "At least one icon file is missing in your bundle. Your pass won't be openable by any Apple Device." ) ; } ) ; it ( "should create back again pass.strings files" , ( ) => { pass . localize ( "it" , { home : "casa" , ciao : "hello" , cosa : "thing" , } ) ; pass [ closePassSymbol ] ( true ) ; expect ( pass [ filesSymbol ] [ "it.lproj/pass.strings" ] . length ) . not . toBe ( 0 ) ; } ) ; it ( "should remove all personalisation if requirements are not met" , ( ) => { pass . addBuffer ( "personalization.json" , Buffer . from ( JSON . stringify ( { description : "A test description for a test personalization" , requiredPersonalizationFields : [ "PKPassPersonalizationFieldName" , "PKPassPersonalizationFieldPostalCode" , "PKPassPersonalizationFieldEmailAddress" , ] , } ) ) ) ; pass . addBuffer ( "personalizationLogo@2x.png" , Buffer . alloc ( 0 ) ) ; pass [ closePassSymbol ] ( true ) ; /** Pass is missing nfc data. */ expect ( pass [ filesSymbol ] [ "personalization.json" ] ) . toBeUndefined ( ) ; expect ( pass [ filesSymbol ] [ "personalizationLogo@2x.png" ] ) . toBeUndefined ( ) ; /** Next: pass will miss personalizationLogo */ pass . addBuffer ( "personalization.json" , Buffer . from ( JSON . stringify ( { description : "A test description for a test personalization" , requiredPersonalizationFields : [ "PKPassPersonalizationFieldName" , "PKPassPersonalizationFieldPostalCode" , "PKPassPersonalizationFieldEmailAddress" , ] , } ) ) ) ; pass . setNFC ( { message : "nfc-encrypted-message" , encryptionPublicKey : "none" , } ) ; pass [ closePassSymbol ] ( true ) ; expect ( pass [ filesSymbol ] [ "personalization.json" ] ) . toBeUndefined ( ) ; expect ( pass [ filesSymbol ] [ "personalizationLogo@2x.png" ] ) . toBeUndefined ( ) ; } ) ; it ( "should throw if no pass type have specified" , ( ) => { pass . type = undefined ; expect ( ( ) => pass [ closePassSymbol ] ( true ) ) . toThrowError ( TypeError , Messages . CLOSE . MISSING_TYPE ) ; } ) ; it ( "should throw if a boarding pass is exported without a transitType" , ( ) => { pass . type = "boardingPass" ; expect ( ( ) => pass [ closePassSymbol ] ( true ) ) . toThrowError ( TypeError , Messages . CLOSE . MISSING_TRANSIT_TYPE ) ; } ) ; } ) ; describe ( "[createManifestSymbol]" , ( ) => { it ( "should create a list of SHA-1s" , ( ) => { pass . addBuffer ( "icon.png" , Buffer . alloc ( 0 ) ) ; pass . addBuffer ( "icon@2x.png" , Buffer . alloc ( 0 ) ) ; pass . addBuffer ( "icon@3x.png" , Buffer . alloc ( 0 ) ) ; expect ( JSON . parse ( pass [ createManifestSymbol ] ( ) . toString ( "utf-8" ) ) ) . toEqual ( { "icon.png" : "da39a3ee5e6b4b0d3255bfef95601890afd80709" , "icon@2x.png" : "da39a3ee5e6b4b0d3255bfef95601890afd80709" , "icon@3x.png" : "da39a3ee5e6b4b0d3255bfef95601890afd80709" , } ) ; } ) ; it ( "List of Sha-1 of localized files should not contain Windows '\\' slash" , ( ) => { if ( path . sep === "\\" ) { pass . addBuffer ( "en.lproj\\icon.png" , Buffer . alloc ( 0 ) ) ; pass . addBuffer ( "en.lproj\\icon@2x.png" , Buffer . alloc ( 0 ) ) ; pass . addBuffer ( "en.lproj\\icon@3x.png" , Buffer . alloc ( 0 ) ) ; const parsedResult = Object . keys ( JSON . parse ( pass [ createManifestSymbol ] ( ) . toString ( "utf-8" ) ) ) ; expect ( parsedResult [ 0 ] ) . toMatch ( /en\.lproj\/icon\.png/ ) ; expect ( parsedResult [ 1 ] ) . toMatch ( /en\.lproj\/icon@2x\.png/ ) ; expect ( parsedResult [ 2 ] ) . toMatch ( /en\.lproj\/icon@3x\.png/ ) ; } } ) ; } ) ; describe ( "[static] from" , ( ) => { it ( "should throw if source is unavailable" , async ( ) => { await expectAsync ( PKPass . from ( ) ) . toBeRejectedWithError ( TypeError , Messages . FROM . MISSING_SOURCE . replace ( "%s" , "undefined" ) ) ; await expectAsync ( PKPass . from ( null ) ) . toBeRejectedWithError ( TypeError , Messages . FROM . MISSING_SOURCE . replace ( "%s" , "null" ) ) ; } ) ; describe ( "Prebuilt PKPass" , ( ) => { it ( "should copy all source's buffers into current one" , async ( ) => { pass . addBuffer ( "index@2x.png" , Buffer . from ( [ 0x62 , 0x75 , 0x66 , 0x66 , 0x65 , 0x72 ] ) ) ; const newPass = await PKPass . from ( pass ) ; expect ( newPass [ filesSymbol ] [ "index@2x.png" ] . equals ( pass [ filesSymbol ] [ "index@2x.png" ] ) ) . toBe ( true ) ; expect ( newPass [ filesSymbol ] [ "index@2x.png" ] ) . not . toBe ( pass [ filesSymbol ] [ "index@2x.png" ] ) ; } ) ; it ( "should accept additional properties to be added to new buffer and ignore unknown props" , async ( ) => { const newPass = await PKPass . from ( pass , { description : "mimmoh" , serialNumber : "626621523738123" , insert_here_invalid_unknown_parameter_name : false , } ) ; expect ( newPass [ propsSymbol ] [ "description" ] ) . toBe ( "mimmoh" ) ; expect ( newPass [ propsSymbol ] [ "serialNumber" ] ) . toBe ( "626621523738123" ) ; expect ( newPass [ propsSymbol ] [ "insert_here_invalid_unknown_parameter_name" ] ) . toBeUndefined ( ) ; } ) ; } ) ; describe ( "Template" , ( ) => { it ( "should reject invalid templates" , async ( ) => { await Promise . all ( [ expectAsync ( PKPass . from ( 5 ) ) . toBeRejected ( ) , expectAsync ( PKPass . from ( { } ) ) . toBeRejected ( ) , expectAsync ( PKPass . from ( { model : "" } ) ) . toBeRejected ( ) , expectAsync ( PKPass . from ( { certificates : { } } ) ) . toBeRejected ( ) , expectAsync ( PKPass . from ( "" ) ) . toBeRejected ( ) , expectAsync ( PKPass . from ( true ) ) . toBeRejected ( ) , expectAsync ( PKPass . from ( [ ] ) ) . toBeRejected ( ) , ] ) ; } ) ; it ( "should read model from fileSystem and props" , async ( ) => { const footerFile = await fs . readFile ( path . resolve ( __dirname , "../examples/models/exampleBooking.pass/footer.png" ) ) ; const newPass = await PKPass . from ( { model : path . resolve ( __dirname , "../examples/models/exampleBooking.pass" ) , certificates : { ... baseCerts , } , } , { voided : true , } ) ; expect ( Object . keys ( newPass [ filesSymbol ] ) . length ) . toBe ( 7 ) ; expect ( newPass [ filesSymbol ] [ "footer.png" ] ) . not . toBeUndefined ( ) ; expect ( newPass [ filesSymbol ] [ "footer.png" ] . equals ( footerFile ) ) . toBe ( true ) ; expect ( newPass [ filesSymbol ] [ "footer.png" ] ) . not . toBe ( footerFile ) ; expect ( newPass [ propsSymbol ] [ "voided" ] ) . toBe ( true ) ; } ) ; } ) ; } ) ; describe ( "[static] pack" , ( ) => { beforeEach ( ( ) => { /** Bypass to avoid signature and manifest generation */ pass [ freezeSymbol ] ( ) ; } ) ; it ( "should should throw error if not all the files passed are PKPasses" , ( ) => { expect ( ( ) => PKPass . pack ( pass , "pass.json" , pass ) ) . toThrowError ( Error , Messages . PACK . INVALID ) ; } ) ; it ( "should output a frozen bundle of bundles" , ( ) => { const pkPassesBundle = PKPass . pack ( pass , pass ) ; expect ( pkPassesBundle [ filesSymbol ] [ "packed-pass-1.pkpass" ] ) . toBeInstanceOf ( Buffer ) ; expect ( pkPassesBundle [ filesSymbol ] [ "packed-pass-2.pkpass" ] ) . toBeInstanceOf ( Buffer ) ; expect ( pkPassesBundle . isFrozen ) . toBe ( true ) ; } ) ; it ( "should output a bundle with pkpasses mimetype" , ( ) => { const pkPassesBundle = PKPass . pack ( pass , pass ) ; expect ( pkPassesBundle . mimeType ) . toBe ( "application/vnd.apple.pkpasses" ) ; } ) ; } ) ; } ) ;