diff --git a/__tests__/fixtures/expected-builds.json b/__tests__/fixtures/expected-builds.json index 2e5498a6..c9ed326a 100644 --- a/__tests__/fixtures/expected-builds.json +++ b/__tests__/fixtures/expected-builds.json @@ -1,50 +1,50 @@ { "type_6_transporter": { - "Cargo": "A0p0tdFal8d8s8f4-----04040303430101.Iw1/kA==.Aw1/kA==.", - "Miner": "A0p5tdFal8d8s8f42l2l---040403451q0101.Iw1/kA==.Aw1/kA==.", - "Hopper": "A0p0tdFal8d0s8f41717---030302024300-.Iw1/kA==.Aw1/kA==." + "Cargo": "A0p0tdFal8d8s8f4-----04040303430101-.Iw18UA==.Aw18UA==.", + "Miner": "A0p5tdFal8d8s8f42l2l---040403451q0101-.Iw18UA==.Aw18UA==.", + "Hopper": "A0p0tdFal8d0s8f41717---030302024300--.Iw18UA==.Aw18UA==." }, "type_7_transport": { - "Cargo": "A0p0tiFfliddsdf5--------0505040403480101.Iw18aQ==.Aw18aQ==.", - "Miner": "A0pdtiFflid8sdf5--2l2l----0505041v03450000.Iw18aQ==.Aw18aQ==." + "Cargo": "A0p0tiFfliddsdf5--------0505040403480101--.Iw18eQ==.Aw18eQ==.", + "Miner": "A0pdtiFflid8sdf5--2l2l----0505041v03450000--.Iw18eQ==.Aw18eQ==." }, "federal_dropship": { - "Cargo": "A0pdtiFflnddsif4-1717------05040448--020201.Iw18eQ==.Aw18eQ==." + "Cargo": "A0pdtiFflnddsif4-1717------05040448--020201-.Iw18RQ==.Aw18RQ==." }, "asp": { - "Miner": "A2pftfFflidfskf50s0s24242l2l---04054a1q02022o27.Iw18WQ==.Aw18WQ==." + "Miner": "A2pftfFflidfskf50s0s24242l2l---04054a1q02022o27-.Iw18eQ==.Aw18eQ==." }, "imperial_clipper": { - "Cargo": "A0p5tiFflndisnf4--0s0s----0605450302020101.Iw18aQ==.Aw18aQ==.", - "Dream": "A2pktkFflndpskf40v0v0s0s0404040n4k5n5d2b29292o-.AwRj4yWU1I==.CwBhCYy6YRigzLIA.", - "Current": "A0patkFflndfskf4----------------.AwRj4yWU1I==.CwBhCYy6YRigzLIA." + "Cargo": "A0p5tiFflndisnf4--0s0s----0605450302020101-.Iw18WQ==.Aw18WQ==.", + "Dream": "A2pktkFflndpskf40v0v0s0s0404040n4k5n5d2b29292o--.AwRj4yWU1Yg=.CwBhCYy6YRigzPIA.", + "Current": "A0patkFflndfskf4-----------------.AwRj4yWU1Yg=.CwBhCYy6YRigzPIA." }, "type_9_heavy": { - "Current": "A0patsFklndnsif6---------0706054a0303020224.AwRj4yoo.EwBhEYy6dsg=." + "Current": "A0patsFklndnsif6---------0706054a0303020224--.AwRj4yo5iA==.EwBhEYy6d6g=." }, "python": { - "Cargo": "A0patnFflidsssf5---------050505040448020201.Iw18eQ==.Aw18eQ==.", - "Miner": "A0pktkFflidpspf50v0v0v2m2m0404--050505Ce4a1v02022o.Iw18eQ==.IwBhBYy6dkCYg===.", - "Dream": "A2pptkFfliduspf50v0v0v27270404040m5n5n4f2d2d032t0201.Iw1+gDBxA===.EwBhEYy6e0WEA===.", - "Missile": "A0pttoFjljdystf52f2g2d2ePh----04044j03---002h.Iw18eQ==.Aw18eQ==." + "Cargo": "A0patnFflidsssf5---------050505040448020201-.Iw18eAMQ.Aw18RQ==.", + "Miner": "A0pktkFflidpspf50v0v0v2m2m0404--050505Ce4a1v02022o-.Iw18eAMQ.IwBhBYy6dkCYRA==.", + "Dream": "A2pptkFfliduspf50v0v0v27270404040m5n5n4f2d2d032t0201-.Iw1+gDByUA==.EwBhEYy6e0VEA===.", + "Missile": "A0pttoFjljdystf52f2g2d2ePh----04044j03---00--.Iw18eAMQ.Aw18RQ==." }, "anaconda": { - "Dream": "A4putpFklndzsuf52c0o0o0o1m1m0q0q0404040l0b0100004k5n5n112d2d04-0303326b.AwRj4yo5dyg=.MwBhCYy6duvARiA=.", - "Cargo": "A0patnFklndnsxf5----------------06050505040404-45030301.Iw18ZVA=.Aw18ZVA=.", - "Current": "A0patnFklndksxf5----------------06050505040404-03034524.Iw18ZVA=.Aw18ZVA=.", - "Explorer": "A0patnFklndksxf5--------0202------f7050505040s37-2f2i4524.AwRj4yVKJ9hA.AwhMIyumQRhEA===.", - "Test": "A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b.Iw18ZVA=.Aw18ZVA=." + "Dream": "A4putpFklndzsuf52c0o0o0o1m1m0q0q0404040l0b0100004k5n5n112d2d04-0303326b-.AwRj4yo5dzhA.MwBhCYy6duvARhEA.", + "Cargo": "A0patnFklndnsxf5----------------06050505040404-45030301-.Iw18ZUAxA===.Aw18ZXEA.", + "Current": "A0patnFklndksxf5----------------06050505040404-03034524-.Iw18ZUAxA===.Aw18ZXEA.", + "Explorer": "A0patnFklndksxf5--------0202------f7050505040s37--2i4524-.AwRj4yVKJ9jCA===.AwhMIyumQRgkA===.", + "Test": "A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b-.Iw18ZUAxA===.Aw18ZXEA." }, "diamondback_explorer": { - "Explorer": "A0p0tdFfldddsdf5---0202--320p432i2f-.AwRj4zTYg===.AwiMIyoo." + "Explorer": "A0p0tdFfldddsdf5---0202--320p432i----.AwRj4zTZaA==.AwiMIyqo." }, "vulture": { - "Bounty Hunter": "A3patcFalddksff31e1e0404-0l4a-5d27662j.AwRj4z2I.MwBhBYy6oJmAjLIA." + "Bounty Hunter": "A3patcFalddksff31e1e0404-0l4a-5d27662j--.AwRj4z2Gg===.MwBhBYy6oJmAjLMQ." }, "fer_de_lance": { - "Attack": "A2pfthFalidpsff31r0s0s0s0s000404-04-4a-5d27-.Iw18aQ==.CwBhrSu8EZyA." + "Attack": "A2pfthFalidpsff31r0s0s0s0s000404-04-4a-5d27--.Iw18aAMQ.CwBhrSu8EZxEA===." }, "eagle": { - "Figther": "A4p0t5F5l3d5s5f20p0p24-4053-2j-.Iw18kA==.Aw18kA==." + "Figther": "A4p0t5F5l3d5s5f20p0p24-4053-2j---.Iw18gDJQ.Aw19kA==." } } diff --git a/__tests__/fixtures/slef-multiple-builds.json b/__tests__/fixtures/slef-multiple-builds.json new file mode 100644 index 00000000..d6b95126 --- /dev/null +++ b/__tests__/fixtures/slef-multiple-builds.json @@ -0,0 +1,366 @@ +[ + { + "header": { + "appName": "Inara", + "appVersion": "1.0", + "appURL": "https:\/\/inara.cz\/cmdr-fleet\/123\/123\/", + "appCustomProperties": { + "inaraCommanderID": 123, + "inaraShipID": 123 + } + }, + "data": { + "Ship": "krait_mkii", + "ShipID": 7, + "ShipName": "pancake hammer", + "ShipIdent": "PH-01", + "HullValue": 44160710, + "ModulesValue": 111274094, + "Rebuy": 7771743, + "Modules": [ + { + "Slot": "largehardpoint1", + "Item": "hpt_mininglaser_fixed_small", + "On": true + }, + { + "Slot": "largehardpoint2", + "Item": "hpt_cannon_gimbal_large", + "On": true, + "Engineering": { + "BlueprintName": "weapon_overcharged", + "Level": 2, + "Quality": 1, + "ExperimentalEffect": "special_auto_loader" + } + }, + { + "Slot": "largehardpoint3", + "Item": "hpt_cannon_gimbal_large", + "On": true, + "Engineering": { + "BlueprintName": "weapon_overcharged", + "Level": 2, + "Quality": 1, + "ExperimentalEffect": "special_auto_loader" + } + }, + { + "Slot": "mediumhardpoint1", + "Item": "hpt_basicmissilerack_fixed_medium", + "On": true, + "Engineering": { + "BlueprintName": "weapon_highcapacity", + "Level": 5, + "Quality": 1 + } + }, + { + "Slot": "mediumhardpoint2", + "Item": "hpt_basicmissilerack_fixed_medium", + "On": true + }, + { + "Slot": "tinyhardpoint1", + "Item": "hpt_heatsinklauncher_turret_tiny", + "On": true + }, + { + "Slot": "tinyhardpoint2", + "Item": "hpt_cloudscanner_size0_class3", + "On": true + }, + { + "Slot": "tinyhardpoint3", + "Item": "hpt_shieldbooster_size0_class5", + "On": true + }, + { + "Slot": "tinyhardpoint4", + "Item": "hpt_shieldbooster_size0_class5", + "On": true, + "Priority": 1 + }, + { + "Slot": "slot01_size6", + "Item": "int_cargorack_size6_class1", + "On": true, + "Priority": 1 + }, + { + "Slot": "slot02_size6", + "Item": "int_cargorack_size6_class1", + "On": true, + "Priority": 1 + }, + { + "Slot": "slot03_size5", + "Item": "int_guardianfsdbooster_size5", + "On": true + }, + { + "Slot": "slot04_size5", + "Item": "int_fighterbay_size5_class1", + "On": true + }, + { + "Slot": "slot05_size4", + "Item": "int_shieldgenerator_size4_class5", + "On": true + }, + { + "Slot": "slot06_size3", + "Item": "int_dronecontrol_collection_size3_class4", + "On": true + }, + { + "Slot": "slot07_size3", + "Item": "int_dronecontrol_collection_size3_class4", + "On": true + }, + { + "Slot": "slot08_size2", + "Item": "int_refinery_size2_class2", + "On": true + }, + { + "Slot": "slot09_size1", + "Item": "int_dronecontrol_prospector_size1_class4", + "On": true + }, + { + "Slot": "powerplant", + "Item": "int_powerplant_size7_class5", + "On": true, + "Priority": 1 + }, + { + "Slot": "mainengines", + "Item": "int_engine_size6_class5", + "On": true + }, + { + "Slot": "frameshiftdrive", + "Item": "int_hyperdrive_size5_class5", + "On": true, + "Engineering": { + "BlueprintName": "fsd_longrange", + "Level": 2, + "Quality": 0.861 + } + }, + { + "Slot": "lifesupport", + "Item": "int_lifesupport_size4_class2", + "On": true, + "Priority": 3 + }, + { + "Slot": "powerdistributor", + "Item": "int_powerdistributor_size7_class5", + "On": true + }, + { + "Slot": "radar", + "Item": "int_sensors_size6_class2", + "On": true + }, + { + "Slot": "fueltank", + "Item": "int_fueltank_size5_class3", + "On": true, + "Priority": 1 + }, + { + "Slot": "armour", + "Item": "krait_mkii_armour_grade3", + "On": true, + "Priority": 1, + "Engineering": { + "BlueprintName": "armour_heavyduty", + "Level": 5, + "Quality": 1 + } + } + ] + } + }, + { + "header": { + "appName": "Inara", + "appVersion": "1.0", + "appURL": "https:\/\/inara.cz\/cmdr-fleet\/123\/123\/", + "appCustomProperties": { + "inaraCommanderID": 123, + "inaraShipID": 123 + } + }, + "data": { + "Ship": "diamondbackxl", + "ShipID": 11, + "ShipName": "star Hopper", + "ShipIdent": "PH-02", + "HullValue": 1615649, + "ModulesValue": 16981039, + "Rebuy": 929837, + "Modules": [ + { + "Slot": "tinyhardpoint1", + "Item": "hpt_heatsinklauncher_turret_tiny", + "On": true, + "Value": 3072 + }, + { + "Slot": "slot01_size4", + "Item": "int_fuelscoop_size4_class5", + "On": true, + "Priority": 3, + "Value": 2862364 + }, + { + "Slot": "slot02_size4", + "Item": "int_guardianfsdbooster_size4", + "On": true, + "Value": 2847499 + }, + { + "Slot": "slot03_size3", + "Item": "int_shieldgenerator_size3_class2", + "On": true, + "Value": 18812, + "Engineering": { + "BlueprintName": "shieldgenerator_thermic", + "Level": 3, + "Quality": 1, + "ExperimentalEffect": "special_shield_health" + } + }, + { + "Slot": "slot04_size3", + "Item": "int_repairer_size3_class5", + "On": true, + "Value": 2302911 + }, + { + "Slot": "slot05_size2", + "Item": "int_buggybay_size2_class2", + "On": true, + "Priority": 3, + "Value": 21600 + }, + { + "Slot": "slot06_size2", + "Item": "int_cargorack_size2_class1", + "On": true, + "Priority": 1, + "Value": 2852 + }, + { + "Slot": "slot07_size1", + "Item": "int_supercruiseassist", + "On": true, + "Priority": 3, + "Value": 9121 + }, + { + "Slot": "slot08_size1", + "Item": "int_detailedsurfacescanner_tiny", + "On": true, + "Value": 250000, + "Engineering": { + "BlueprintName": "sensor_expanded", + "Level": 5, + "Quality": 1 + } + }, + { + "Slot": "powerplant", + "Item": "int_powerplant_size4_class5", + "On": true, + "Priority": 1, + "Value": 1441233, + "Engineering": { + "BlueprintName": "powerplant_boosted", + "Level": 1, + "Quality": 1 + } + }, + { + "Slot": "mainengines", + "Item": "int_engine_size4_class5", + "On": true, + "Value": 1610080, + "Engineering": { + "BlueprintName": "engine_dirty", + "Level": 5, + "Quality": 1, + "ExperimentalEffect": "special_engine_lightweight" + } + }, + { + "Slot": "frameshiftdrive", + "Item": "int_hyperdrive_size5_class5", + "On": true, + "Value": 5103953, + "Engineering": { + "BlueprintName": "fsd_longrange", + "Level": 5, + "Quality": 1, + "ExperimentalEffect": "special_fsd_lightweight" + } + }, + { + "Slot": "lifesupport", + "Item": "int_lifesupport_size3_class2", + "On": true, + "Value": 10133, + "Engineering": { + "BlueprintName": "misc_lightweight", + "Level": 3, + "Quality": 1 + } + }, + { + "Slot": "powerdistributor", + "Item": "int_powerdistributor_size4_class5", + "On": true, + "Value": 389022, + "Engineering": { + "BlueprintName": "powerdistributor_highfrequency", + "Level": 4, + "Quality": 1 + } + }, + { + "Slot": "radar", + "Item": "int_sensors_size3_class2", + "On": true, + "Value": 10133, + "Engineering": { + "BlueprintName": "sensor_lightweight", + "Level": 5, + "Quality": 1 + } + }, + { + "Slot": "fueltank", + "Item": "int_fueltank_size5_class3", + "On": true, + "Priority": 1, + "Value": 97754 + }, + { + "Slot": "armour", + "Item": "diamondbackxl_armour_grade1", + "On": true, + "Priority": 1, + "Engineering": { + "BlueprintName": "armour_heavyduty", + "Level": 5, + "Quality": 1 + } + } + ] + } + } +] diff --git a/__tests__/fixtures/slef-multiple-expected-builds.json b/__tests__/fixtures/slef-multiple-expected-builds.json new file mode 100644 index 00000000..19c2bd7f --- /dev/null +++ b/__tests__/fixtures/slef-multiple-expected-builds.json @@ -0,0 +1,8 @@ +{ + "krait_mkii": { + "Imported pancake hammer": "A2pptkFflidussf52l1o1o2g2g020g040405051Ofr45C9C91oP3.Iw18eQ==.AwRgzKIkA===." + }, + "diamondback_explorer": { + "Imported star Hopper": "A0pataFflddfsdf5---02---321P430iv6013w2i.Iw18SQ==.AwRm44GYpKg=." + } +} diff --git a/__tests__/fixtures/slef-single-build.json b/__tests__/fixtures/slef-single-build.json new file mode 100644 index 00000000..1b578b83 --- /dev/null +++ b/__tests__/fixtures/slef-single-build.json @@ -0,0 +1,188 @@ +[ + { + "header": { + "appName": "Inara", + "appVersion": "1.0", + "appURL": "https:\/\/inara.cz\/cmdr-fleet\/123\/123\/", + "appCustomProperties": { + "inaraCommanderID": 123, + "inaraShipID": 123 + } + }, + "data": { + "Ship": "krait_mkii", + "ShipID": 7, + "ShipName": "pancake hammer", + "ShipIdent": "PH-01", + "HullValue": 44160710, + "ModulesValue": 111274094, + "Rebuy": 7771743, + "Modules": [ + { + "Slot": "largehardpoint1", + "Item": "hpt_mininglaser_fixed_small", + "On": true + }, + { + "Slot": "largehardpoint2", + "Item": "hpt_cannon_gimbal_large", + "On": true, + "Engineering": { + "BlueprintName": "weapon_overcharged", + "Level": 2, + "Quality": 1, + "ExperimentalEffect": "special_auto_loader" + } + }, + { + "Slot": "largehardpoint3", + "Item": "hpt_cannon_gimbal_large", + "On": true, + "Engineering": { + "BlueprintName": "weapon_overcharged", + "Level": 2, + "Quality": 1, + "ExperimentalEffect": "special_auto_loader" + } + }, + { + "Slot": "mediumhardpoint1", + "Item": "hpt_basicmissilerack_fixed_medium", + "On": true, + "Engineering": { + "BlueprintName": "weapon_highcapacity", + "Level": 5, + "Quality": 1 + } + }, + { + "Slot": "mediumhardpoint2", + "Item": "hpt_basicmissilerack_fixed_medium", + "On": true + }, + { + "Slot": "tinyhardpoint1", + "Item": "hpt_heatsinklauncher_turret_tiny", + "On": true + }, + { + "Slot": "tinyhardpoint2", + "Item": "hpt_cloudscanner_size0_class3", + "On": true + }, + { + "Slot": "tinyhardpoint3", + "Item": "hpt_shieldbooster_size0_class5", + "On": true + }, + { + "Slot": "tinyhardpoint4", + "Item": "hpt_shieldbooster_size0_class5", + "On": true, + "Priority": 1 + }, + { + "Slot": "slot01_size6", + "Item": "int_cargorack_size6_class1", + "On": true, + "Priority": 1 + }, + { + "Slot": "slot02_size6", + "Item": "int_cargorack_size6_class1", + "On": true, + "Priority": 1 + }, + { + "Slot": "slot03_size5", + "Item": "int_guardianfsdbooster_size5", + "On": true + }, + { + "Slot": "slot04_size5", + "Item": "int_fighterbay_size5_class1", + "On": true + }, + { + "Slot": "slot05_size4", + "Item": "int_shieldgenerator_size4_class5", + "On": true + }, + { + "Slot": "slot06_size3", + "Item": "int_dronecontrol_collection_size3_class4", + "On": true + }, + { + "Slot": "slot07_size3", + "Item": "int_dronecontrol_collection_size3_class4", + "On": true + }, + { + "Slot": "slot08_size2", + "Item": "int_refinery_size2_class2", + "On": true + }, + { + "Slot": "slot09_size1", + "Item": "int_dronecontrol_prospector_size1_class4", + "On": true + }, + { + "Slot": "powerplant", + "Item": "int_powerplant_size7_class5", + "On": true, + "Priority": 1 + }, + { + "Slot": "mainengines", + "Item": "int_engine_size6_class5", + "On": true + }, + { + "Slot": "frameshiftdrive", + "Item": "int_hyperdrive_size5_class5", + "On": true, + "Engineering": { + "BlueprintName": "fsd_longrange", + "Level": 2, + "Quality": 0.861 + } + }, + { + "Slot": "lifesupport", + "Item": "int_lifesupport_size4_class2", + "On": true, + "Priority": 3 + }, + { + "Slot": "powerdistributor", + "Item": "int_powerdistributor_size7_class5", + "On": true + }, + { + "Slot": "radar", + "Item": "int_sensors_size6_class2", + "On": true + }, + { + "Slot": "fueltank", + "Item": "int_fueltank_size5_class3", + "On": true, + "Priority": 1 + }, + { + "Slot": "armour", + "Item": "krait_mkii_armour_grade3", + "On": true, + "Priority": 1, + "Engineering": { + "BlueprintName": "armour_heavyduty", + "Level": 5, + "Quality": 1 + } + } + ] + } + } +] diff --git a/__tests__/test-import.js b/__tests__/test-import.js index 2bcd2c22..c7c484cc 100644 --- a/__tests__/test-import.js +++ b/__tests__/test-import.js @@ -18,13 +18,13 @@ describe('Import Modal', function() { const mockContext = { language: getLanguage('en'), sizeRatio: 1, - openMenu: jest.genMockFunction(), - closeMenu: jest.genMockFunction(), - showModal: jest.genMockFunction(), - hideModal: jest.genMockFunction(), - tooltip: jest.genMockFunction(), - termtip: jest.genMockFunction(), - onWindowResize: jest.genMockFunction() + openMenu: jest.fn(), + closeMenu: jest.fn(), + showModal: jest.fn(), + hideModal: jest.fn(), + tooltip: jest.fn(), + termtip: jest.fn(), + onWindowResize: jest.fn() }; let modal, render, ContextProvider = Utils.createContextProvider(mockContext); @@ -110,21 +110,25 @@ describe('Import Modal', function() { it('catches an invalid backup', function() { const importData = require('./fixtures/valid-backup'); let invalidImportData = Object.assign({}, importData); - //invalidImportData.builds.asp = null; // Remove Asp Miner build used in comparison + // Remove Asp Miner build used in comparison delete(invalidImportData.builds.asp); pasteText('"this is not valid"'); expect(modal.state.importValid).toBeFalsy(); expect(modal.state.errorMsg).toEqual('Must be an object or array!'); + pasteText('{ "builds": "Should not be a string" }'); expect(modal.state.importValid).toBeFalsy(); expect(modal.state.errorMsg).toEqual('builds must be an object!'); - pasteText(JSON.stringify(importData).replace('anaconda', 'invalid_ship')); + + pasteText(JSON.stringify(importData).replace(/anaconda/g, 'invalid_ship')); expect(modal.state.importValid).toBeFalsy(); - expect(modal.state.errorMsg).toEqual('"invalid_ship" is not a valid Ship Id!'); + expect(Object.keys(modal.state.builds)).not.toContain('anaconda'); + pasteText(JSON.stringify(importData).replace('Dream', '')); expect(modal.state.importValid).toBeFalsy(); - expect(modal.state.errorMsg).toEqual('Imperial Clipper build "" must be a string at least 1 character long!'); + expect(Object.keys(modal.state.builds.imperial_clipper).length).toEqual(3); + pasteText(JSON.stringify(invalidImportData)); expect(modal.state.importValid).toBeFalsy(); expect(modal.state.errorMsg).toEqual('asp build "Miner" data is missing!'); @@ -144,7 +148,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b.AwRj4zNLaA%3D%3D.CwBhCYzBGW9qCTSqq5xA.&bn=Test%20My%20Ship'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b-.AwRj4zNLeI%3D%3D.CwBhCYzBGW9qCTSqq5JA.&bn=Test%20My%20Ship'); }); it('catches an invalid build', function() { @@ -169,7 +173,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b.AwRj4zNLaA%3D%3D.CwBhCYzBGW9qCTSqq5xA.H4sIAAAAAAAAA2MUe8HMwPD%2FPwMAAGvB0AkAAAA%3D&bn=Test%20My%20Ship'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b-.AwRj4zNLeI%3D%3D.CwBhCYzBGW9qCTSqq5JA.H4sIAAAAAAAAE2MUe8HMwPD%2FPwMAAGvB0AkAAAA%3D&bn=Test%20My%20Ship'); }); }); @@ -186,7 +190,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/asp?code=A0pftiFflfddsnf5------020202033c044002v62f2i.AwRj4yvI.CwRgDBldHnJA.H4sIAAAAAAAAA2P858DAwPCXEUhwHPvx%2F78YG5AltB7I%2F8%2F0TwImJboDSPJ%2F%2B%2Ff%2Fv%2FKlX%2F%2F%2Fi3AwMTBIfARK%2FGf%2BJwVSxArStVAYqOjvz%2F%2F%2FJVo5GRhE2IBc4SKQSSz%2FDGEmCa398P8%2F%2F2%2BgTf%2F%2FA7kMAExxqlSAAAAA&bn=Multi-purpose%20Asp%20Explorer'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/asp?code=A0pftiFflfddsnf5------020202033c044002v6-2i-.AwRj4yvYg%3D%3D%3D.CwRgDBldHn5A.H4sIAAAAAAAAE2P858DAwPCXEUhwHPvx%2F78YG5AltB7I%2F8%2F0TwImJboDSPJ%2F%2B%2Ff%2Fv%2FKlX%2F%2F%2Fi3AwMTBIfARK%2FGf%2BJwVSxArStVAYqOjvz%2F%2F%2FJVo5GRhE2IBc4SKQSSz%2FDGEmCa398P8%2F%2F2%2BgTf%2F%2FA7kMAExxqlSAAAAA&bn=Multi-purpose%20Asp%20Explorer'); }); it('imports a valid v4 build with modifications', function() { @@ -198,11 +202,11 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/imperial_courier?code=A0patzF5l0das8f31a1a270202000e402t0101-2f.AwRj4zKA.CwRgDBldLiQ%3D.H4sIAAAAAAAAA12OPUvDYBSFT1OTfkRJjUkbbC3Yj8mlODgUISAtdOlety5ODv0Vgji7O7kJ%2FgzBQX%2BEY7Gg0NKhfY%2FnHQLFDBdynufe9%2BRMCmCb06g29oCgacjiRx6gY6oWKUT8UgLaszqQfHmSnpVFN1uSeXNsJVcj%2FA2EHlZkspIUpUc6UjTXGT85qwHuSEuVc%2F16r99kDQeSSjvSbSjpyUpNK10uJJ3aYqk6smwm1lQ9bOxw71TMm8VanEqq9JW1r3Qo%2BREOLnQHvbWmb7rZIu5VLIyGQGOukPv%2F0WQk5LeEAjPOUDwtAP6bShy2HKAz0HPO%2B5KsP25I79O2I7LvD%2Bz4Il1XAQAA&bn=Multi-purpose%20Imperial%20Courier'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/imperial_courier?code=A0patzF5l0das8f31a1a270202000e402t0101----.AwRj4zOYg%3D%3D%3D.CwRgDBldLuZA.H4sIAAAAAAAAE12OPUvDYBSFT1OTfkRJjUkbbC3Yj8mlODgUISAtdOlety5ODv0Vgji7O7kJ%2FgzBQX%2BEY7Gg0NKhfY%2FnHQLFDBdynufe9%2BRMCmCb06g29oCgacjiRx6gY6oWKUT8UgLaszqQfHmSnpVFN1uSeXNsJVcj%2FA2EHlZkspIUpUc6UjTXGT85qwHuSEuVc%2F16r99kDQeSSjvSbSjpyUpNK10uJJ3aYqk6smwm1lQ9bOxw71TMm8VanEqq9JW1r3Qo%2BREOLnQHvbWmb7rZIu5VLIyGQGOukPv%2F0WQk5LeEAjPOUDwtAP6bShy2HKAz0HPO%2B5KsP25I79O2I7LvD%2Bz4Il1XAQAA&bn=Multi-purpose%20Imperial%20Courier'); }); }); - describe('Import Detaild Builds Array', function() { + describe('Import Detailed Builds Array', function() { beforeEach(reset); @@ -240,7 +244,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g2f.AwRj4zNaqA%3D%3D.CwRgDBldUExuBiIlUA%3D%3D.H4sIAAAAAAAAA12STy8DURTFb1szU53Ga8dg2qqqDmJDIoKFxJImumYjVrVqfAALC4lNbcUnkLCoDbEQu0bSlQVhI8JHsJBIQ73rXMkwMYuT9%2Bb87nl%2F7ovoRSL6ikD6TYNINZg5XsWUo7pfrBikr2USlRyXyDuLAhr6ZHanNLOzD5tjOiskysk5dOBvfTB7bjeRW0MNG3ohSBq1bKKxKwyLLUAjmwjpPu4wJx4xVbNI57heDfbUKUAy2xaRUQZpllHoHMHxKqjhhF4LgjtJiFHDmqbrEeVnUJOax7%2FSdRfRwBNotv9wo5kAuZMD2egKyDYcdYl1OBki6z%2BZQjaFnBPyFCM1LefF%2BcgrY0es9FKwbW8ZYj9gmBbxRVRdglMh6BNqnwsk4ouoO4HSIehNoBuBRHwR1QOmsBvHmk6IfMbd2fdCEka%2BjNSexPWGoEkcyX6CnxbxRZQtd%2BPpym%2B31xFtn0iSFPkf%2BBkttZlzB9KDFyBuFRfAGV0Ogoff8SSsCfjjD5hGWtLIwZB%2FgX5Zt%2BLHMI9My7sp6nzgZzekswTxVvCOkq%2FSXqb%2F3zfLxh6HrwIAAA%3D%3D&bn=Imported%20Federal%20Corvette'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g--.AwRj4zNapI%3D%3D.CwRgDBldUExuBiIlWIA%3D.&bn=Imported%20Federal%20Corvette'); }); it('imports a valid companion API build', function() { @@ -252,7 +256,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/beluga?code=A0pktsFplCdpsnf70t0t2727270004040404043c4fmimlmm04mc0iv62i2f.AwRj4yukg%3D%3D%3D.CwRgDBldHi8IUA%3D%3D.H4sIAAAAAAAAA2P8Z8%2FAwPCXEUiIKTMxMPCv%2F%2Ff%2FP8cFIPGf6Z8YTEr0GjMDg%2FJWICERBOTzn%2Fn7%2F7%2FIO5Ai5n9SIEWsQEIoSxAolfbt%2F3%2BJPk4GBhE7YQYGYVmgcuVnf4Aq%2FwOVAAAyiFctbgAAAA%3D%3D&bn=Imported%20Beluga%20Liner'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/beluga?code=A0pktsFplCdpsnf70t0t2727270004040404043c4fmimlmm04mc0iv62i--.AwRj4yusg%3D%3D%3D.CwRgDBldHi8IWIA%3D.&bn=Imported%20Beluga%20Liner'); }); it('imports a valid companion API build', function() { @@ -264,7 +268,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/type_7_transport?code=A0patfFflidasdf5----0404040005050504044d2402.AwRj4yrI.CwRgDBlVK7EiA%3D%3D%3D.&bn=Imported%20Type-7%20Transporter'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/type_7_transport?code=A0patfFflidasdf5----0404040005050504044d2402--.AwRj4yoo.CwRgDBlVK7HjEA%3D%3D.&bn=Imported%20Type-7%20Transporter'); }); it('imports a valid companion API build', function() { @@ -276,7 +280,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/cobra_mk_iii?code=A0p0tdFaldd3sdf4------34---2f2i.AwRj4yKA.CwRgDMYExrezBUg%3D.&bn=Imported%20Cobra%20Mk%20III'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/cobra_mk_iii?code=A0p0tdFaldd3sdf4------34----2i--.AwRj4yqA.CwRgDMYExrezBig%3D.&bn=Imported%20Cobra%20Mk%20III'); }); }); @@ -324,4 +328,41 @@ describe('Import Modal', function() { }); }); + describe('Imports SLEF data', () => { + beforeEach(reset); + + it('imports a single valid SLEF build', () => { + const importData = require('./fixtures/slef-single-build.json'); + pasteText(JSON.stringify(importData)); + + expect(modal.state.importValid).toBeTruthy(); + expect(modal.state.errorMsg).toEqual(null); + expect(modal.state.singleBuild).toBe(true); + clickProceed(); + expect(MockRouter.go.mock.calls.length).toBe(1); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/krait_mkii?code=A2pptkFflidussf52l1o1o2g2g020g040405051Ofr45C9C91oP3.Iw18eQ%3D%3D.AwRgzKIkA%3D%3D%3D.&bn=Imported%20pancake%20hammer'); + }); + + it('imports multiple SLEF builds', () => { + const importData = require('./fixtures/slef-multiple-builds.json'); + const expectedBuilds = require('./fixtures/slef-multiple-expected-builds.json'); + pasteText(JSON.stringify(importData)); + + expect(modal.state.importValid).toBeTruthy(); + expect(modal.state.errorMsg).toEqual(null); + expect(modal.state.singleBuild).toBe(false); + clickProceed(); + expect(modal.state.processed).toBeTruthy(); + clickImport(); + + const builds = Persist.getBuilds(); + + for (const shipModel in builds) { + for (const buildName in builds[shipModel]) { + expect(builds[shipModel][buildName]) + .toEqual(expectedBuilds[shipModel][buildName]); + } + } + }); + }); }); diff --git a/src/app/components/ModalImport.jsx b/src/app/components/ModalImport.jsx index cf48e138..4dc34b7c 100644 --- a/src/app/components/ModalImport.jsx +++ b/src/app/components/ModalImport.jsx @@ -11,7 +11,8 @@ import * as ModuleUtils from '../shipyard/ModuleUtils'; import { fromDetailedBuild } from '../shipyard/Serializer'; import { Download } from './SvgIcons'; import { outfitURL } from '../utils/UrlGenerators'; -import * as CompanionApiUtils from '../utils/CompanionApiUtils'; +import { shipFromJson, shipModelFromJson } from '../utils/CompanionApiUtils'; +import { shipFromLoadoutJSON } from '../utils/JournalUtils'; const zlib = require('pako'); @@ -214,8 +215,8 @@ export default class ModalImport extends TranslatedComponent { * @throws {string} if parse/import fails */ _importCompanionApiBuild(build) { - const shipModel = CompanionApiUtils.shipModelFromJson(build); - const ship = CompanionApiUtils.shipFromJson(build); + const shipModel = shipModelFromJson(build); + const ship = shipFromJson(build); let builds = {}; builds[shipModel] = {}; @@ -321,6 +322,30 @@ export default class ModalImport extends TranslatedComponent { this.setState({ builds, singleBuild: true }); } + /** + * Import SLEF formatted builds. Sets state to a map of the builds on success + * and flags if there was only a single build. + * + * @param {string} importData - Array of the list of builds. + * @throws {string} If parse / import fails + */ + _importSlefBuilds(importData) { + const builds = importData.reduce((memo, { data }) => { + const shipModel = shipModelFromJson(data); + const ship = shipFromLoadoutJSON(data); + const shipTemplate = Ships[shipModel]; + const shipName = data.ShipName || shipTemplate.properties.name; + + const key = `Imported ${shipName}`; + memo[shipModel] = {}; + memo[shipModel][key] = ship.toString(); + + return memo; + }, {}); + + this.setState({ builds, singleBuild: Object.keys(builds).length === 1 }); + } + /** * Validate the import string / text box contents * @param {SyntheticEvent} event Event @@ -355,8 +380,10 @@ export default class ModalImport extends TranslatedComponent { throw 'Must be an object or array!'; } - if (importData.modules != null && importData.modules.Armour != null) { // Only the companion API has this information - this._importCompanionApiBuild(importData); // Single sihp definition + if (importData?.[0]?.header?.appName) { // has SLEF envelope? + this._importSlefBuilds(importData); + } else if (importData.modules != null && importData.modules.Armour != null) { // Only the companion API has this information + this._importCompanionApiBuild(importData); // Single ship definition } else if (importData.ship != null && importData.ship.modules != null && importData.ship.modules.Armour != null) { // Only the companion API has this information this._importCompanionApiBuild(importData.ship); // Complete API dump } else if (importData instanceof Array) { // Must be detailed export json @@ -542,7 +569,7 @@ export default class ModalImport extends TranslatedComponent { {comparisonRows} - ); + ); } if(this.state.canEdit) {