diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 4893b1d1..191d281f 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -175,6 +175,7 @@ 583335632BF6509C001D90D7 /* UAD_page_model.json in Resources */ = {isa = PBXBuildFile; fileRef = 583335622BF6509C001D90D7 /* UAD_page_model.json */; }; 583335652BF6A5C3001D90D7 /* TestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 583335642BF6A5C3001D90D7 /* TestUtils.swift */; }; 583335672BF6DCD0001D90D7 /* UAD_page_model_2.json in Resources */ = {isa = PBXBuildFile; fileRef = 583335662BF6DCD0001D90D7 /* UAD_page_model_2.json */; }; + 5833356D2BFBF51C001D90D7 /* UAD_page_model_3.json in Resources */ = {isa = PBXBuildFile; fileRef = 5833356C2BFBF51C001D90D7 /* UAD_page_model_3.json */; }; 5846ABF62B4762A600FA6C76 /* PollingBehaviorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846ABF52B4762A600FA6C76 /* PollingBehaviorModel.swift */; }; 58A9DD7D2AC2103300F5E0B0 /* ReplaceableMoleculeBehaviorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A9DD7C2AC2103300F5E0B0 /* ReplaceableMoleculeBehaviorModel.swift */; }; 58E7561D2BE04C320088BB5D /* MoleculeComparisonProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E7561C2BE04C320088BB5D /* MoleculeComparisonProtocol.swift */; }; @@ -797,6 +798,7 @@ 583335622BF6509C001D90D7 /* UAD_page_model.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = UAD_page_model.json; sourceTree = ""; }; 583335642BF6A5C3001D90D7 /* TestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestUtils.swift; sourceTree = ""; }; 583335662BF6DCD0001D90D7 /* UAD_page_model_2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = UAD_page_model_2.json; sourceTree = ""; }; + 5833356C2BFBF51C001D90D7 /* UAD_page_model_3.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = UAD_page_model_3.json; sourceTree = ""; }; 5846ABF52B4762A600FA6C76 /* PollingBehaviorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PollingBehaviorModel.swift; sourceTree = ""; }; 5878F0A42BD7E68800ADE23D /* mvmcoreui.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcoreui.xcconfig; sourceTree = ""; }; 5878F0A52BD7E6BE00ADE23D /* mvmcoreui_dev.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcoreui_dev.xcconfig; sourceTree = ""; }; @@ -1558,6 +1560,7 @@ children = ( 583335662BF6DCD0001D90D7 /* UAD_page_model_2.json */, 583335622BF6509C001D90D7 /* UAD_page_model.json */, + 5833356C2BFBF51C001D90D7 /* UAD_page_model_3.json */, ); path = Modelling; sourceTree = ""; @@ -2740,6 +2743,7 @@ buildActionMask = 2147483647; files = ( 583335672BF6DCD0001D90D7 /* UAD_page_model_2.json in Resources */, + 5833356D2BFBF51C001D90D7 /* UAD_page_model_3.json in Resources */, 583335632BF6509C001D90D7 /* UAD_page_model.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 50aa1df2..06e3b0f0 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -256,18 +256,14 @@ import MVMCore var behaviorUpdatedModels = [MoleculeModelProtocol]() if var newTemplateModel = newPageModel as? TemplateModelProtocol { executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in - if let updatedMolecules = behavior.onPageNew(rootMolecules: newTemplateModel.rootMolecules, delegateObjectIVar) { + var changes = [any MoleculeModelProtocol]() + if let updatedMolecules = behavior.onPageNew(rootMolecules: newTemplateModel.rootMolecules, delegateObjectIVar, changes: &changes) { updatedMolecules.forEach { molecule in + // Replace again in case there is a template level child. if let replaced = try? newTemplateModel.replaceChildMolecule(with: molecule) { // Only recognize the molecules that actually changed. - if let replaced = replaced as? ParentMoleculeModelProtocol, let molecule = molecule as? ParentMoleculeModelProtocol { - let diffs: [MoleculeModelProtocol] = replaced.findAllTheirsNotEqual(against: molecule) - debugLog("Behavior updated \(diffs) in template model.") - behaviorUpdatedModels.append(contentsOf: diffs) - } else if !replaced.isEqual(to: molecule) { - debugLog("Behavior updated \(molecule) in template model.") - behaviorUpdatedModels.append(molecule) // Need to specifically trace molecule updates here as replacements are modifying the original tree. (We don't have a deep copy.) - } + debugLog("Behavior updated \(changes) in template model.") + behaviorUpdatedModels.append(contentsOf: changes) } else { debugLog("Failed to replace \(molecule) in the template model.") } diff --git a/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift b/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift index 6cc30e95..39c72661 100644 --- a/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift +++ b/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift @@ -31,6 +31,7 @@ public extension PageBehaviorProtocol { public protocol PageMoleculeTransformationBehavior: PageBehaviorProtocol { func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?) -> [MoleculeModelProtocol]? + func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?, changes: inout [MoleculeModelProtocol]) -> [MoleculeModelProtocol]? func willSetupMolecule(with model: MoleculeModelProtocol, updating view: MoleculeViewProtocol?) func didSetupMolecule(view: MoleculeViewProtocol, withModel: MoleculeModelProtocol) func willSetupNavigationBar(with model: NavigationItemModelProtocol, updating view: UINavigationBar) @@ -41,7 +42,11 @@ public protocol PageMoleculeTransformationBehavior: PageBehaviorProtocol { public extension PageMoleculeTransformationBehavior { // All optional. - func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?) -> [MoleculeModelProtocol]? { return nil } + func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?) -> [MoleculeModelProtocol]? { + var changes = [any MoleculeModelProtocol]() + return onPageNew(rootMolecules: rootMolecules, delegateObject, changes: &changes) + } + func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?, changes: inout [MoleculeModelProtocol]) -> [MoleculeModelProtocol]? { return nil } func willSetupMolecule(with model: MoleculeModelProtocol, updating view: MoleculeViewProtocol?) {} func didSetupMolecule(view: MoleculeViewProtocol, withModel: MoleculeModelProtocol) {} func willSetupNavigationBar(with model: NavigationItemModelProtocol, updating view: UINavigationBar) {} diff --git a/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift b/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift index 698162f6..42f1aea5 100644 --- a/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift +++ b/MVMCoreUI/Behaviors/ReplaceableMoleculeBehaviorModel.swift @@ -44,11 +44,10 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co Self.debugLog("Initializing for \((model as! ReplaceableMoleculeBehaviorModel).moleculeIds)") } - public func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?) -> [MoleculeModelProtocol]? { + public func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?, changes: inout [MoleculeModelProtocol]) -> [MoleculeModelProtocol]? { self.delegateObject = delegateObject - modulesToListenFor = moleculeIds - let moleculeModels = moleculeIds.compactMap { moleculeId in + let moleculeModels = moleculeIds.compactMap { moleculeId in do { return try delegateObject?.moleculeDelegate?.getModuleWithName(moleculeId) } catch { @@ -61,23 +60,23 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co } } - return findAndReplace(moleculeModels, in: rootMolecules) + return findAndReplace(moleculeModels, in: rootMolecules, changes: &changes) } - fileprivate func findAndReplace(_ moleculeModels: [any MoleculeModelProtocol], in rootMolecules: [any MoleculeModelProtocol]) -> [any MoleculeModelProtocol]? { + fileprivate func findAndReplace(_ moleculeModels: [any MoleculeModelProtocol], in rootMolecules: [any MoleculeModelProtocol], changes: inout [MoleculeModelProtocol]) -> [any MoleculeModelProtocol]? { debugLog("attempting to replace \(moleculeModels.map { $0.id }) in \(rootMolecules)") - var hasReplacement = false + var changeList = [any MoleculeModelProtocol]() let updatedRootMolecules = rootMolecules.map { rootMolecule in // Top level check to return a new root molecule. if let updatedMolecule = moleculeModels.first(where: { rootMolecule.id == $0.id }) { guard !updatedMolecule.isEqual(to: rootMolecule) else { - debugLog("molecule \(updatedMolecule) is the same as \(rootMolecule). skipping...") + debugLog("top molecule \(updatedMolecule) is the same as \(rootMolecule). skipping...") return rootMolecule } - debugLog("replacing \(rootMolecule) with \(updatedMolecule)") + debugLog("top replacing \(rootMolecule) with \(updatedMolecule)") logUpdated(molecule: updatedMolecule) - hasReplacement = true + changeList.append(updatedMolecule) return updatedMolecule } @@ -89,12 +88,12 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co if let replacedMolecule = try parentMolecule.replaceChildMolecule(with: newMolecule) { guard !replacedMolecule.isEqual(to: newMolecule) else { // Note: Slight risk here of replacing the something in the original tree and misreporting that is it not replaced based on equality. - debugLog("molecule \(newMolecule) is the same as \(replacedMolecule). skipping...") + debugLog("deep molecule \(newMolecule) is the same as \(replacedMolecule). skipping...") return } - debugLog("replacing \(replacedMolecule) with \(newMolecule)") + debugLog("deep replacing \(replacedMolecule) with \(newMolecule)") logUpdated(molecule: newMolecule) - hasReplacement = true + changeList.append(newMolecule) } } catch { let coreError = MVMCoreErrorObject.createErrorObject(for: error, location: String(describing: type(of: self)))! @@ -106,6 +105,8 @@ public class ReplaceableMoleculeBehavior: PageMoleculeTransformationBehavior, Co } return parentMolecule } + let hasReplacement = !changeList.isEmpty + changes.append(contentsOf: changeList) debugLog("replacing \(hasReplacement ? updatedRootMolecules.count : 0) molecules") return hasReplacement ? updatedRootMolecules : nil } diff --git a/MVMCoreUITests/JSON/Modelling/UAD_page_model_3.json b/MVMCoreUITests/JSON/Modelling/UAD_page_model_3.json new file mode 100644 index 00000000..6d082ac0 --- /dev/null +++ b/MVMCoreUITests/JSON/Modelling/UAD_page_model_3.json @@ -0,0 +1,1243 @@ +{ + "template": "list", + "analyticsData": { + "vzdl.user.customerBusiness": "joint_cust", + "vzdl.target.engagement.intent": "account management", + "vzdl.page.feedCardImpression": "L1|P1|greetingSection|Edit profile & settings^L1|P1|mobileAccountSection|BillsTile^L1|P2|mobileAccountSection|UsageTile^L1|P3|mobileAccountSection|OrdersTile^L1|P4|mobileAccountSection|PlansTile^L1|P5|mobileAccountSection|Services_perksTile^L1|P6|mobileAccountSection|Account_activityTile^L1|P1|fivegHomeAccountSection|BillsTile^L1|P2|fivegHomeAccountSection|OrdersTile^L1|P3|fivegHomeAccountSection|PlansTile^L1|P4|fivegHomeAccountSection|Account_activityTile^L1|P5|fivegHomeAccountSection|Services_perksTile^L1|P1|fiosAccountSection|BillsTile^L1|P2|fiosAccountSection|PlansTile^L1|P3|fiosAccountSection|SupportTile^L1|P4|fiosAccountSection|Account_activityTile^L1|P5|fiosAccountSection|Home_offersTile", + "vzdl.user.id": "a3b00d5af5c7b5d26d017023f12dfa791dba533a33a3ed264c8c98237ae5902f", + "vzdl.user.account": "c0d793b51b000cce8d6ec062a71a224d0faaf8e50c36ebd31240539b31aca001", + "vzdl.user.accountType": "postpaid", + "vzdl.events.uadcardserved": "1", + "vzdl.page.channelSession": "4154e060-85ae-4e8f-a371-fb00c618797a", + "vzdl.page.siteSection": "mva_atomic", + "vzdl.page.sourceChannel": "mva", + "vzdl.page.flow": "account overview", + "vzdl.env.businessUnit": "wireless", + "vzdl.page.displayChannel": "mva", + "vzdl.page.name": "atomicAccountLanding", + "vzdl.page.id": "atomicAccountLanding" + }, + "molecules": [ + { + "useVerticalMargins": false, + "backgroundColor": "black", + "moleculeName": "tabsListItem", + "tabs": { + "borderLine": false, + "moleculeName": "tabs", + "tabs": [ + { + "label": { + "fontStyle": "BoldTitleSmall", + "textColor": "white", + "moleculeName": "label", + "text": "Mobile" + } + }, + { + "label": { + "fontStyle": "BoldTitleSmall", + "textColor": "white", + "moleculeName": "label", + "text": "5G Home" + } + }, + { + "label": { + "fontStyle": "BoldTitleSmall", + "textColor": "white", + "moleculeName": "label", + "text": "Fios" + } + } + ], + "style": "dark", + "selectedIndex": 1 + }, + "molecules": [ + [ + { + "analyticsData": { + "vzdl.utils.locationRefId": "500014388|PID506|^500014372|PID505|^500009322|PID1026|", + "vzdl.page.id": "atomicAccountLanding", + "vzdl.page.feedCardImpression": "L1|P1|quickUpdates|Updates Tile|500014388|LUO_263|10|PID506^L1|P2|quickUpdates||500014372|LUO_262|10|PID505^L1|P3|quickUpdates||500009322|LUO_123|10|PID1026", + "vzwi.mvmapp.pegaFeedSecTwoSession": "6853540150263850930", + "vzdl.events.uadcardserved": "1", + "vzdl.page.name": "atomicAccountLanding" + }, + "moleculeName": "listItem", + "ResponseInfo": { + "errorCode": "00", + "topAlertTime": 0, + "type": "Success", + "errorMessage": "SUCCESS" + }, + "id": "priorityTiles", + "gone": false, + "line": { + "type": "none" + }, + "backgroundColor": "black", + "molecule": { + "moleculeName": "carousel", + "height": 168, + "molecules": [ + { + "moleculeName": "carouselItem", + "molecule": { + "axis": "vertical", + "topPadding": 0, + "moleculeName": "stack", + "molecules": [ + { + "moleculeName": "stackItem", + "molecule": { + "molecules": [ + { + "useHorizontalMargins": false, + "moleculeName": "stackItem", + "molecule": { + "fontStyle": "RegularBodyLarge", + "textColor": "#000000", + "moleculeName": "label", + "text": "Make sure important updates reach you. Verify your email is HERMAN.MUNSTER@VERIZON.COM" + }, + "horizontalAlignment": "leading" + } + ], + "axis": "vertical", + "moleculeName": "stack", + "spacing": 0 + } + }, + { + "moleculeName": "stackItem", + "molecule": { + "moleculeName": "stack", + "axis": "horizontal", + "molecules": [ + { + "moleculeName": "stackItem", + "molecule": { + "size": "small", + "title": "Verify Email ", + "moleculeName": "button", + "enabledTextColor": "#000000", + "action": { + "actions": [ + { + "hideCloseButton": false, + "openOauthWebView": false, + "requestURL": "https://vzwqa3.verizonwireless.com/digital/nsa/secure/gw/udb/mvaFeedback", + "extraParameters": { + "soiEngagementId": "500014388", + "strategyId ": "support/customer service", + "category": "AccountOverview", + "dispositionOptionId": "81", + "propositionName": "LUO_263", + "templateId": "ct_pod6", + "tacticLocation": "Account_Overview", + "dispositionListId": "10", + "locationRefId": "", + "pegaSessionId": "6853540150263850930", + "rank": "2", + "subStrategyId": "Email address not verified", + "tileName": "Updates Tile", + "cardId": "PID506", + "cardWeight": "500", + "propositionId": "LUO_263" + }, + "disableNativeAction": false, + "checkCameraPermission": false, + "showNativeNavigation": false, + "disableAction": false, + "tryToReplaceFirst": false, + "openInWebview": true, + "disableOfflineDevice": false, + "hideUrl": false, + "length": 0, + "actionType": "openPage", + "pageType": "mvaFeedback", + "background": true, + "isSelected": false, + "hideWebNavigation": false, + "location": 0 + }, + { + "appContext": "mobileFirstSS", + "analyticsData": { + "vzdl.page.sourceChannel": "mva", + "vzdl.page.feedCardClicked": "L1|P1|quickUpdates|Updates Tile|500014388|LUO_263|10|PID506", + "vzdl.page.linkName": "PID506_LUO_263|Verify Email ", + "vzdl.page.displayChannel": "mva", + "vzdl.page.id": "atomicAccountLanding", + "vzdl.events.uadcardclicked": "1", + "vzdl.page.name": "atomicAccountLanding" + }, + "extraParameters": { + "requestFrom": "UAD", + "feedCardClicked": "L1|P1|quickUpdates|Updates Tile|500014388|LUO_263|10|PID506", + "headline_content": "Make sure important updates reach you. Verify your email is HERMAN.MUNSTER@VERIZON.COM", + "uniqueID": "PID506", + "overlay_type": "verify-email" + }, + "actionType": "openPage", + "requestURL": "https://vzwqa3.verizonwireless.com/digital/nsa/secure/gw/udb/verifyEmailMVA", + "pageType": "verifyEmail" + } + ], + "actionType": "actions" + } + }, + "verticalAlignment": "trailing", + "horizontalAlignment": "leading" + }, + { + "moleculeName": "stackItem", + "molecule": { + "size": "small", + "title": "Modify Email", + "moleculeName": "link", + "enabledTextColor": "#000000", + "enabledColor": "#000000", + "action": { + "actions": [ + { + "hideCloseButton": false, + "requestURL": "https://vzwqa3.verizonwireless.com/digital/nsa/secure/gw/udb/mvaFeedback", + "extraParameters": { + "soiEngagementId": "500014388", + "strategyId ": "support/customer service", + "category": "AccountOverview", + "dispositionOptionId": "81", + "propositionName": "LUO_263", + "templateId": "ct_pod6", + "tacticLocation": "Account_Overview", + "dispositionListId": "10", + "locationRefId": "", + "pegaSessionId": "6853540150263850930", + "rank": "2", + "subStrategyId": "Email address not verified", + "tileName": "Updates Tile", + "cardId": "PID506", + "cardWeight": "500", + "propositionId": "LUO_263" + }, + "disableNativeAction": false, + "checkCameraPermission": false, + "showNativeNavigation": false, + "length": 0, + "tryToReplaceFirst": false, + "openInWebview": true, + "disableOfflineDevice": false, + "hideUrl": false, + "actionType": "openPage", + "pageType": "mvaFeedback", + "background": true, + "isSelected": false, + "location": 0, + "hideWebNavigation": false, + "openOauthWebView": false + }, + { + "analyticsData": { + "vzdl.page.sourceChannel": "mva", + "vzdl.page.feedCardClicked": "L1|P1|quickUpdates|Updates Tile|500014388|LUO_263|10|PID506", + "vzdl.page.linkName": "PID506_LUO_263", + "vzdl.page.displayChannel": "mva", + "vzdl.page.id": "atomicAccountLanding", + "vzdl.events.uadcardclicked": "1", + "vzdl.page.name": "atomicAccountLanding" + }, + "extraParameters": { + "requestFrom": "UAD", + "feedCardClicked": "L1|P1|quickUpdates|Updates Tile|500014388|LUO_263|10|PID506", + "headline_content": "Make sure important updates reach you. Verify your email is HERMAN.MUNSTER@VERIZON.COM", + "uniqueID": "PID506", + "overlay_type": "verify-email" + }, + "actionType": "openPage", + "appContext": "mobileFirstSS", + "pageType": "mngProfile" + } + ], + "actionType": "actions" + } + }, + "verticalAlignment": "center", + "horizontalAlignment": "center" + } + ] + }, + "verticalAlignment": "trailing", + "horizontalAlignment": "leading" + } + ] + }, + "topPadding": 16, + "useHorizontalMargins": true, + "cornerRadius": 8, + "useVerticalMargins": true, + "backgroundColor": "white", + "bottomPadding": 16 + }, + { + "moleculeName": "carouselItem", + "molecule": { + "axis": "vertical", + "topPadding": 0, + "moleculeName": "stack", + "molecules": [ + { + "moleculeName": "stackItem", + "molecule": { + "molecules": [ + { + "useHorizontalMargins": false, + "moleculeName": "stackItem", + "molecule": { + "fontStyle": "RegularBodyLarge", + "textColor": "#000000", + "moleculeName": "label", + "text": "Let's make sure you get important account updates." + }, + "horizontalAlignment": "leading" + } + ], + "axis": "vertical", + "moleculeName": "stack", + "spacing": 0 + } + }, + { + "moleculeName": "stackItem", + "molecule": { + "moleculeName": "stack", + "axis": "horizontal", + "molecules": [ + { + "moleculeName": "stackItem", + "molecule": { + "size": "small", + "title": "Add email", + "moleculeName": "button", + "enabledTextColor": "#000000", + "action": { + "actions": [ + { + "hideCloseButton": false, + "requestURL": "https://vzwqa3.verizonwireless.com/digital/nsa/secure/gw/udb/mvaFeedback", + "extraParameters": { + "soiEngagementId": "500014372", + "strategyId ": "", + "category": "AccountOverview", + "dispositionOptionId": "81", + "propositionName": "LUO_262", + "templateId": "", + "tacticLocation": "Account_Overview", + "dispositionListId": "10", + "locationRefId": "", + "pegaSessionId": "6853540150263850930", + "rank": "3", + "subStrategyId": "Missing SubStrategyid", + "tileName": "", + "cardId": "PID505", + "cardWeight": "500", + "propositionId": "LUO_262" + }, + "disableNativeAction": false, + "checkCameraPermission": false, + "showNativeNavigation": false, + "length": 0, + "tryToReplaceFirst": false, + "openInWebview": true, + "disableOfflineDevice": false, + "hideUrl": false, + "actionType": "openPage", + "pageType": "mvaFeedback", + "background": true, + "isSelected": false, + "location": 0, + "hideWebNavigation": false, + "openOauthWebView": false + }, + { + "analyticsData": { + "vzdl.page.sourceChannel": "mva", + "vzdl.page.feedCardClicked": "L1|P2|quickUpdates||500014372|LUO_262|10|PID505", + "vzdl.page.linkName": "PID505_LUO_262|Add email", + "vzdl.page.displayChannel": "mva", + "vzdl.page.id": "atomicAccountLanding", + "vzdl.events.uadcardclicked": "1", + "vzdl.page.name": "atomicAccountLanding" + }, + "extraParameters": { + "requestFrom": "UAD" + }, + "actionType": "openPage", + "appContext": "mobileFirstSS", + "pageType": "mngProfile" + } + ], + "actionType": "actions" + } + }, + "verticalAlignment": "trailing", + "horizontalAlignment": "leading" + } + ] + }, + "verticalAlignment": "trailing", + "horizontalAlignment": "leading" + } + ] + }, + "topPadding": 16, + "useHorizontalMargins": true, + "cornerRadius": 8, + "useVerticalMargins": true, + "backgroundColor": "white", + "bottomPadding": 16 + }, + { + "moleculeName": "carouselItem", + "molecule": { + "axis": "vertical", + "topPadding": 0, + "moleculeName": "stack", + "molecules": [ + { + "moleculeName": "stackItem", + "molecule": { + "molecules": [ + { + "useHorizontalMargins": false, + "moleculeName": "stackItem", + "molecule": { + "fontStyle": "RegularBodyLarge", + "textColor": "#000000", + "moleculeName": "label", + "text": "Take a peek at next month’s bill." + }, + "horizontalAlignment": "leading" + } + ], + "axis": "vertical", + "moleculeName": "stack", + "spacing": 0 + } + }, + { + "moleculeName": "stackItem", + "molecule": { + "moleculeName": "stack", + "axis": "horizontal", + "molecules": [ + { + "moleculeName": "stackItem", + "molecule": { + "size": "small", + "title": "Review details", + "moleculeName": "button", + "enabledTextColor": "#000000", + "action": { + "actions": [ + { + "hideCloseButton": false, + "requestURL": "https://vzwqa3.verizonwireless.com/digital/nsa/secure/gw/udb/mvaFeedback", + "extraParameters": { + "soiEngagementId": "500009322", + "strategyId ": "Bill", + "category": "AccountOverview", + "dispositionOptionId": "81", + "propositionName": "LUO_123", + "templateId": "", + "tacticLocation": "Account_Overview", + "dispositionListId": "10", + "locationRefId": "", + "pegaSessionId": "6853540150263850930", + "rank": "4", + "subStrategyId": "Next bill estimate", + "tileName": "", + "cardId": "PID1026", + "cardWeight": "300", + "propositionId": "LUO_123" + }, + "disableNativeAction": false, + "checkCameraPermission": false, + "showNativeNavigation": false, + "length": 0, + "tryToReplaceFirst": false, + "openInWebview": true, + "disableOfflineDevice": false, + "hideUrl": false, + "actionType": "openPage", + "pageType": "mvaFeedback", + "background": true, + "isSelected": false, + "location": 0, + "hideWebNavigation": false, + "openOauthWebView": false + }, + { + "analyticsData": { + "vzdl.page.sourceChannel": "mva", + "vzdl.page.feedCardClicked": "L1|P3|quickUpdates||500009322|LUO_123|10|PID1026", + "vzdl.page.linkName": "PID1026_LUO_123|Review details", + "vzdl.page.displayChannel": "mva", + "vzdl.page.id": "atomicAccountLanding", + "vzdl.events.uadcardclicked": "1", + "vzdl.page.name": "atomicAccountLanding" + }, + "extraParameters": { + "browserUrl": "https://vzwqa3.verizonwireless.com/digital/nsa/secure/ui/bill/nbs/#/", + "requestFrom": "UAD" + }, + "actionType": "openPage", + "appContext": "mobile/nsa/nos/gw/launchapp/l2", + "pageType": "webview" + } + ], + "actionType": "actions" + } + }, + "verticalAlignment": "trailing", + "horizontalAlignment": "leading" + } + ] + }, + "verticalAlignment": "trailing", + "horizontalAlignment": "leading" + } + ] + }, + "topPadding": 16, + "useHorizontalMargins": true, + "cornerRadius": 8, + "useVerticalMargins": true, + "backgroundColor": "white", + "bottomPadding": 16 + } + ], + "itemWidthPercent": 72, + "accessibilityText": "carousel", + "spacing": 12, + "pagingMolecule": { + "moleculeName": "barsCarouselIndicator", + "position": -20, + "inverted": true + }, + "rightPadding": 16, + "leftPadding": 16 + } + }, + { + "headlineBody": { + "moleculeName": "headlineBody", + "headline": { + "moleculeName": "label", + "text": "Bills", + "textColor": "#000000" + } + }, + "backgroundColor": "#FFFFFF", + "moleculeName": "list1CFWBdy", + "action": { + "actions": [ + { + "analyticsData": { + "vzdl.page.sourceChannel": "mva", + "vzdl.page.feedCardClicked": "L1|P1|mobileAccountSection|BillsTile", + "vzdl.page.linkName": "Mobile|Bills", + "vzdl.page.displayChannel": "mva", + "vzdl.page.id": "atomicAccountLanding", + "vzdl.events.uadcardclicked": "1", + "vzdl.page.name": "atomicAccountLanding" + }, + "extraParameters": { + "browserUrl": "https://vzwqa2.verizonwireless.com/digital/nsa/secure/ui/bill/overview/", + "requestFrom": "UAD" + }, + "actionType": "openPage", + "appContext": "mobile/nsa/nos/gw/launchapp/l2", + "pageType": "webview" + } + ], + "actionType": "actions" + } + }, + { + "headlineBody": { + "moleculeName": "headlineBody", + "headline": { + "moleculeName": "label", + "text": "Usage", + "textColor": "#000000" + } + }, + "backgroundColor": "#FFFFFF", + "moleculeName": "list1CFWBdy", + "action": { + "actions": [ + { + "analyticsData": { + "vzdl.page.sourceChannel": "mva", + "vzdl.page.feedCardClicked": "L1|P2|mobileAccountSection|UsageTile", + "vzdl.page.linkName": "Mobile|Usage", + "vzdl.page.displayChannel": "mva", + "vzdl.page.id": "atomicAccountLanding", + "vzdl.events.uadcardclicked": "1", + "vzdl.page.name": "atomicAccountLanding" + }, + "extraParameters": { + "sourcePage": "plansAndDeviceLanding", + "requestFrom": "UAD" + }, + "actionType": "openPage", + "appContext": "mobileFirstSS", + "pageType": "dataUsageDetails" + } + ], + "actionType": "actions" + } + }, + { + "headlineBody": { + "moleculeName": "headlineBody", + "headline": { + "moleculeName": "label", + "text": "Orders", + "textColor": "#000000" + } + }, + "backgroundColor": "#FFFFFF", + "moleculeName": "list1CFWBdy", + "action": { + "actions": [ + { + "analyticsData": { + "vzdl.page.sourceChannel": "mva", + "vzdl.page.feedCardClicked": "L1|P3|mobileAccountSection|OrdersTile", + "vzdl.page.linkName": "Mobile|Orders", + "vzdl.page.displayChannel": "mva", + "vzdl.page.id": "atomicAccountLanding", + "vzdl.events.uadcardclicked": "1", + "vzdl.page.name": "atomicAccountLanding" + }, + "extraParameters": { + "browserUrl": "https://vzwqa2.verizonwireless.com/digital/nsa/secure/ui/orders/", + "requestFrom": "UAD" + }, + "actionType": "openPage", + "appContext": "mobile/nsa/nos/gw/launchapp/l2", + "pageType": "webview" + } + ], + "actionType": "actions" + } + }, + { + "headlineBody": { + "moleculeName": "headlineBody", + "headline": { + "moleculeName": "label", + "text": "Plans", + "textColor": "#000000" + } + }, + "backgroundColor": "#FFFFFF", + "moleculeName": "list1CFWBdy", + "action": { + "actions": [ + { + "analyticsData": { + "vzdl.page.sourceChannel": "mva", + "vzdl.page.feedCardClicked": "L1|P4|mobileAccountSection|PlansTile", + "vzdl.page.linkName": "Mobile|Plans", + "vzdl.page.displayChannel": "mva", + "vzdl.page.id": "atomicAccountLanding", + "vzdl.events.uadcardclicked": "1", + "vzdl.page.name": "atomicAccountLanding" + }, + "extraParameters": { + "browserUrl": "https://vzwqa2.verizonwireless.com/digital/nsa/secure/ui/cpc/mvm?pmd=y&tabbar=true", + "requestFrom": "UAD" + }, + "actionType": "openPage", + "appContext": "mobile/nsa/nos/gw/launchapp/l2", + "pageType": "webview" + } + ], + "actionType": "actions" + } + }, + { + "headlineBody": { + "moleculeName": "headlineBody", + "headline": { + "moleculeName": "label", + "text": "Services & perks", + "textColor": "#000000" + } + }, + "backgroundColor": "#FFFFFF", + "moleculeName": "list1CFWBdy", + "action": { + "actions": [ + { + "analyticsData": { + "vzdl.page.sourceChannel": "mva", + "vzdl.page.feedCardClicked": "L1|P5|mobileAccountSection|Services_perksTile", + "vzdl.page.linkName": "Mobile|Services & perks", + "vzdl.page.displayChannel": "mva", + "vzdl.page.id": "atomicAccountLanding", + "vzdl.events.uadcardclicked": "1", + "vzdl.page.name": "atomicAccountLanding" + }, + "extraParameters": { + "browserUrl": "https://vzwqa2.verizonwireless.com/digital/nsa/secure/ui/products/producthub/home", + "requestFrom": "UAD" + }, + "actionType": "openPage", + "appContext": "mobile/nsa/nos/gw/launchapp/l2", + "pageType": "webview" + } + ], + "actionType": "actions" + } + }, + { + "id": "notification_count", + "headlineBody": { + "moleculeName": "headlineBody", + "headline": { + "moleculeName": "label", + "text": "Account activity", + "textColor": "#000000" + } + }, + "backgroundColor": "#FFFFFF", + "moleculeName": "list1CFWBdy", + "action": { + "actions": [ + { + "analyticsData": { + "vzdl.page.sourceChannel": "mva", + "vzdl.page.feedCardClicked": "L1|P6|mobileAccountSection|Account_activityTile", + "vzdl.page.linkName": "Mobile|Account activity", + "vzdl.page.displayChannel": "mva", + "vzdl.page.id": "atomicAccountLanding", + "vzdl.events.uadcardclicked": "1", + "vzdl.page.name": "atomicAccountLanding" + }, + "extraParameters": { + "browserUrl": "https://vzwqa2.verizonwireless.com/digital/nsa/secure/ui/optg/", + "requestFrom": "UAD" + }, + "actionType": "openPage", + "appContext": "mobile/nsa/nos/gw/launchapp/l2", + "pageType": "webview" + } + ], + "actionType": "actions" + } + }, + { + "moleculeName": "listItem", + "line": { + "moleculeName": "line", + "type": "none" + }, + "molecule": { + "moleculeName": "stack", + "axis": "horizontal", + "molecules": [ + { + "moleculeName": "stackItem", + "molecule": { + "moleculeName": "label", + "text": "Devices", + "fontStyle": "BoldTitleMedium" + }, + "horizontalAlignment": "leading" + }, + { + "moleculeName": "stackItem", + "molecule": { + "moleculeName": "link", + "action": { + "analyticsData": { + "vzdl.page.id": "atomicAccountLanding", + "vzdl.page.name": "atomicAccountLanding", + "vzdl.page.displayChannel": "mva", + "vzdl.page.linkName": "Manage all devices", + "vzdl.page.sourceChannel": "mva" + }, + "extraParameters": { + "browserUrl": "https://vzwqa2.verizonwireless.com/digital/nsa/secure/ui/devices/landing/", + "requestFrom": "UAD" + }, + "actionType": "openPage", + "appContext": "mobile/nsa/nos/gw/launchapp/l2", + "pageType": "webview" + }, + "title": "Manage all devices" + }, + "horizontalAlignment": "trailing" + } + ] + } + }, + { + "moleculeName": "listItem", + "style": "none", + "molecule": { + "moleculeName": "carousel", + "height": 230, + "molecules": [ + { + "useHorizontalMargins": false, + "useVerticalMargins": false, + "moleculeName": "carouselItem", + "molecule": { + "molecule": { + "moleculeName": "stack", + "molecules": [ + { + "moleculeName": "stackItem", + "molecule": { + "moleculeName": "label", + "text": "Add a line and get select phones on us", + "fontStyle": "RegularMicro" + } + }, + { + "moleculeName": "stackItem", + "molecule": { + "fontStyle": "RegularMicro", + "numberOfLines": 1, + "moleculeName": "label", + "text": "\n\n\n\n\n" + } + }, + { + "moleculeName": "stackItem", + "molecule": { + "size": "small", + "title": "Shop", + "moleculeName": "button", + "action": { + "extraParameters": { + "browserUrl": "sales/next/shop.html?flow=AAL&fromAcct=true&isShopFlow=true&entrypoint=account", + "requestFrom": "UAD" + }, + "actionType": "openPage", + "appContext": "mobile/nsa/nos/gw/launchapp/l2", + "pageType": "webview" + } + }, + "verticalAlignment": "trailing", + "horizontalAlignment": "center" + }, + { + "moleculeName": "stackItem", + "molecule": { + "size": "small", + "title": "Bring my own", + "moleculeName": "link", + "action": { + "extraParameters": { + "browserUrl": "sales/digital/byod.html?flow=NSO&fromAcct=true&isShopFlow=true&entrypoint=account", + "requestFrom": "UAD" + }, + "actionType": "openPage", + "appContext": "mobile/nsa/nos/gw/launchapp/l2", + "pageType": "webview" + } + }, + "horizontalAlignment": "center" + } + ] + }, + "verticalAlignment": "fill", + "topPadding": 12, + "image": { + "image": "https://ss7.vzw.com/is/image/VerizonWireless/background-image-mobile?&scl=2", + "moleculeName": "image" + }, + "moleculeName": "bgImageContainer", + "bottomPadding": 12 + }, + "cornerRadius": 8 + } + ], + "itemWidthPercent": 48, + "accessibilityText": "carousel", + "spacing": 16, + "pagingMolecule": { + "moleculeName": "barsCarouselIndicator", + "position": -20 + } + } + }, + { + "line": { + "moleculeName": "line", + "type": "none" + }, + "moleculeName": "listItem", + "style": "shortDivider", + "molecule": { + "moleculeName": "label", + "text": "Make the most of your plans", + "fontStyle": "BoldTitleMedium" + } + }, + { + "id": "forYouTiles", + "style": "none", + "moleculeName": "listItem", + "molecule": { + "moleculeName": "carousel", + "height": 230, + "molecules": [ + { + "useHorizontalMargins": false, + "useVerticalMargins": false, + "backgroundColor": "coolGray1", + "moleculeName": "carouselItem", + "molecule": { + "contentMode": "scaleToFill", + "moleculeName": "image", + "image": "single_card_skeleton_loader", + "imageFormat": "gif" + }, + "cornerRadius": 8 + }, + { + "useHorizontalMargins": false, + "useVerticalMargins": false, + "backgroundColor": "coolGray1", + "moleculeName": "carouselItem", + "molecule": { + "contentMode": "scaleToFill", + "moleculeName": "image", + "image": "single_card_skeleton_loader", + "imageFormat": "gif" + }, + "cornerRadius": 8 + }, + { + "useHorizontalMargins": false, + "useVerticalMargins": false, + "backgroundColor": "coolGray1", + "moleculeName": "carouselItem", + "molecule": { + "contentMode": "scaleToFill", + "moleculeName": "image", + "image": "single_card_skeleton_loader", + "imageFormat": "gif" + }, + "cornerRadius": 8 + } + ], + "itemWidthPercent": 45, + "accessibilityText": "carousel", + "spacing": 16, + "pagingMolecule": { + "moleculeName": "barsCarouselIndicator", + "position": -20 + } + } + }, + { + "line": { + "moleculeName": "line", + "type": "none" + }, + "moleculeName": "listItem", + "style": "shortDivider", + "molecule": { + "moleculeName": "stack", + "axis": "horizontal", + "molecules": [ + { + "moleculeName": "stackItem", + "molecule": { + "moleculeName": "label", + "text": "Discover more", + "fontStyle": "BoldTitleMedium" + }, + "verticalAlignment": "center", + "horizontalAlignment": "leading" + }, + { + "moleculeName": "stackItem", + "molecule": { + "moleculeName": "link", + "action": { + "analyticsData": { + "vzdl.page.id": "atomicAccountLanding", + "vzdl.page.name": "atomicAccountLanding", + "vzdl.page.displayChannel": "mva", + "vzdl.page.linkName": "Mobile|Shop all", + "vzdl.page.sourceChannel": "mva" + }, + "extraParameters": { + "locale": "EN", + "browserUrl": "sales/digital/shoplanding.html?isShopFlow=true&entrypoint=tabbar", + "requestFrom": "Shop" + }, + "actionType": "openPage", + "appContext": "mobile/nsa/nos/gw/launchapp/l2", + "pageType": "webview" + }, + "title": "Shop all" + }, + "verticalAlignment": "center", + "horizontalAlignment": "trailing" + } + ] + } + }, + { + "id": "discoverTiles", + "style": "none", + "moleculeName": "listItem", + "bottomPadding": 32, + "useVerticalMargins": true, + "molecule": { + "moleculeName": "carousel", + "height": 230, + "molecules": [ + { + "useHorizontalMargins": false, + "useVerticalMargins": false, + "backgroundColor": "coolGray1", + "moleculeName": "carouselItem", + "molecule": { + "contentMode": "scaleToFill", + "moleculeName": "image", + "image": "single_card_skeleton_loader", + "imageFormat": "gif" + }, + "cornerRadius": 8 + }, + { + "useHorizontalMargins": false, + "useVerticalMargins": false, + "backgroundColor": "coolGray1", + "moleculeName": "carouselItem", + "molecule": { + "contentMode": "scaleToFill", + "moleculeName": "image", + "image": "single_card_skeleton_loader", + "imageFormat": "gif" + }, + "cornerRadius": 8 + }, + { + "useHorizontalMargins": false, + "useVerticalMargins": false, + "backgroundColor": "coolGray1", + "moleculeName": "carouselItem", + "molecule": { + "contentMode": "scaleToFill", + "moleculeName": "image", + "image": "single_card_skeleton_loader", + "imageFormat": "gif" + }, + "cornerRadius": 8 + } + ], + "itemWidthPercent": 45, + "accessibilityText": "carousel", + "spacing": 16, + "pagingMolecule": { + "moleculeName": "barsCarouselIndicator", + "position": -20 + } + } + } + ] + ] + } + ], + "backgroundColor": "black", + "hab": { + "configuration": "single", + "inverted": false + }, + "cache": true, + "header": { + "useVerticalMargins": true, + "backgroundColor": "black", + "moleculeName": "stack", + "bottomPadding": 12, + "molecules": [ + { + "moleculeName": "stackItem", + "id": "greetingSection", + "molecule": { + "fontStyle": "RegularTitleMedium", + "textColor": "#FFFFFF", + "moleculeName": "label", + "text": "Hi Lebowski." + } + }, + { + "moleculeName": "stackItem", + "molecule": { + "enabledColor": "white", + "title": "Edit profile & settings", + "moleculeName": "link", + "inverted": true, + "action": { + "actionType": "openPage", + "analyticsData": { + "vzdl.page.sourceChannel": "mva", + "vzdl.page.feedCardClicked": "L1|P1|greetingSection|Edit profile & settings", + "vzdl.page.linkName": "Edit profile & settings", + "vzdl.page.displayChannel": "mva", + "vzdl.page.id": "atomicAccountLanding", + "vzdl.events.uadcardclicked": "1", + "vzdl.page.name": "atomicAccountLanding" + }, + "pageType": "oneVzIdSettingsLanding", + "presentationStyle": "push", + "requestURL": "https://mobile-exp-qa2.vzw.com/mobile/nsa/nos/gw/launchapp/l2/webview", + "tryToReplaceFirst": false, + "extraParameters": { + "browserUrl": "https://vzwqa2.verizonwireless.com/digital/nsa/secure/ui/acct/unifiedprofile/overview" + } + } + } + } + ] + }, + "behaviors": [ + { + "moleculeIds": [ + "priorityTiles", + "forYouTiles", + "discoverTiles", + "priorityTiles5G", + "forYouTiles5G", + "discoverTiles5G", + "notification_count", + "priorityTilesFIOS", + "phoneServiceFIOS", + "internetServiceFIOS", + "tvServiceFIOS", + "forYouTilesFIOS", + "discoverTilesFIOS", + "FiosBills", + "FiosSubBills", + "FiosPlans", + "FiosSupport", + "notification_count_fios", + "greetingSection", + "FiosHomeOffers", + "priorityTilesLTE", + "forYouTilesLTE", + "discoverTilesLTE" + ], + "behaviorName": "replaceMoleculeBehavior" + }, + { + "refreshOnShown": true, + "moduleIds": [ + "priorityTiles", + "priorityTiles5G", + "priorityTilesLTE" + ], + "refreshOnFirstLoad": true, + "behaviorName": "pollingBehavior", + "runWhileHidden": false, + "refreshInterval": 10, + "refreshAction": { + "background": true, + "extraParameters": { + "category": "AccountOverview", + "channel": "VZW-MFA", + "locale": "EN", + "alwaysUseFallbackResponse": false, + "platform": "IOS", + "isLTE": false, + "requestFrom": "UAD", + "pageContext": "Account_Overview", + "isFWA": true + }, + "actionType": "openPage", + "requestURL": "https://vzwqa2.verizonwireless.com/digital/nsa/secure/gw/udb/topCardsMVA", + "pageType": "topCardsMVA" + } + }, + { + "refreshOnShown": true, + "moduleIds": [ + "priorityTiles", + "priorityTiles5G", + "priorityTilesLTE" + ], + "refreshOnFirstLoad": true, + "behaviorName": "pollingBehavior", + "runWhileHidden": false, + "refreshInterval": 10, + "refreshAction": { + "background": true, + "extraParameters": { + "category": "AccountOverview", + "channel": "VZW-MFA", + "locale": "EN", + "alwaysUseFallbackResponse": false, + "platform": "IOS", + "isLTE": false, + "requestFrom": "UAD", + "pageContext": "Account_Overview", + "isFWA": true + }, + "actionType": "openPage", + "requestURL": "https://vzwqa2.verizonwireless.com/digital/nsa/secure/gw/udb/bottomCardsMVA", + "pageType": "bottomCardsMVA" + } + } + ], + "pageType": "atomicAccountLanding", + "loggedInMdn": "2815434851", + "presentationStyle": "root", + "footerlessSpacerColor": "white", + "tabBarIndex": 1, + "navigationBar": { + "style": "dark", + "moleculeName": "navigationBar", + "additionalLeftButtons": [ + { + "accessibilityText": "Verizon logo button, tap anytime to scroll to top of page", + "moleculeName": "navigationImageButton", + "image": "nav_vz_mark", + "imageRenderingMode": "alwaysOriginal", + "action": { + "actionType": "noop" + } + } + ], + "additionalRightButtons": [ + { + "accessibilityText": "Stores", + "moleculeName": "navigationImageButton", + "image": "nav_stores_white", + "action": { + "analyticsData": { + "vzdl.page.linkName": "global tab nav:stores" + }, + "title": "Stores", + "actionType": "openPage", + "pageType": "rtlStoreJourney" + } + } + ] + }, + "footerlessSpacerHeight": 0 +} + diff --git a/MVMCoreUITests/MVMCoreUITests.swift b/MVMCoreUITests/MVMCoreUITests.swift index af631c93..5cbcb62a 100644 --- a/MVMCoreUITests/MVMCoreUITests.swift +++ b/MVMCoreUITests/MVMCoreUITests.swift @@ -189,6 +189,7 @@ final class MVMCoreUITests: XCTestCase { let listTemplateModel1 = try JSONDecoder().decode(ListPageTemplateModel.self, from: getFileData("UAD_page_model")) let listTemplateModel2 = try JSONDecoder().decode(ListPageTemplateModel.self, from: getFileData("UAD_page_model")) let listTemplateModel3 = try JSONDecoder().decode(ListPageTemplateModel.self, from: getFileData("UAD_page_model_2")) + let listTemplateModel4 = try JSONDecoder().decode(ListPageTemplateModel.self, from: getFileData("UAD_page_model_3")) let results = listTemplateModel1.findFirst(in: listTemplateModel2, failing: { $0.isEqual(to: $1) }) XCTAssertFalse(results.matched) @@ -199,6 +200,9 @@ final class MVMCoreUITests: XCTestCase { XCTAssertTrue(results2.matched) XCTAssertFalse(listTemplateModel1.deepEquals(to: listTemplateModel3)) XCTAssertTrue(listTemplateModel1.isDeeplyVisuallyEquivalent(to: listTemplateModel3)) + + let results3: [MoleculeModelProtocol] = listTemplateModel1.findAllTheirsNotEqual(against: listTemplateModel4) + XCTAssertTrue(results3.count == 2) } func testPageEqualityPerformance() throws {