Digital PCT265 story PCT-135: Switch to shallow equals with deep compare on parent in order to pinpoint midmatched models. Unit testing setup.
This commit is contained in:
parent
52e8ce7621
commit
f74bea64c2
@ -170,6 +170,11 @@
|
||||
52B201D324081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B201D124081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift */; };
|
||||
5822720B2B1FC55F00F75BAE /* AccessibilityHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582272092B1FC55F00F75BAE /* AccessibilityHandler.swift */; };
|
||||
5822720C2B1FC55F00F75BAE /* RotorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5822720A2B1FC55F00F75BAE /* RotorHandler.swift */; };
|
||||
583335592BF64E77001D90D7 /* MVMCoreUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 583335582BF64E77001D90D7 /* MVMCoreUITests.swift */; };
|
||||
5833355A2BF64E77001D90D7 /* MVMCoreUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29DF0CC21E404D4003B2FB9 /* MVMCoreUI.framework */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
@ -610,6 +615,16 @@
|
||||
FD99130028E21E4900542CC3 /* RuleNotEqualsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9912FF28E21E4900542CC3 /* RuleNotEqualsModel.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
5833355B2BF64E77001D90D7 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D29DF0C321E404D4003B2FB9 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = D29DF0CB21E404D4003B2FB9;
|
||||
remoteInfo = MVMCoreUI;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
01004F2F22721C3800991ECC /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = "<group>"; };
|
||||
0103B84D23D7E33A009C315C /* HeadlineBodyToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyToggleModel.swift; sourceTree = "<group>"; };
|
||||
@ -777,6 +792,11 @@
|
||||
52B201D124081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAndPaymentMethodModel.swift; sourceTree = "<group>"; };
|
||||
582272092B1FC55F00F75BAE /* AccessibilityHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessibilityHandler.swift; sourceTree = "<group>"; };
|
||||
5822720A2B1FC55F00F75BAE /* RotorHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RotorHandler.swift; sourceTree = "<group>"; };
|
||||
583335562BF64E77001D90D7 /* MVMCoreUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MVMCoreUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
583335582BF64E77001D90D7 /* MVMCoreUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUITests.swift; sourceTree = "<group>"; };
|
||||
583335622BF6509C001D90D7 /* UAD_page_model.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = UAD_page_model.json; sourceTree = "<group>"; };
|
||||
583335642BF6A5C3001D90D7 /* TestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestUtils.swift; sourceTree = "<group>"; };
|
||||
583335662BF6DCD0001D90D7 /* UAD_page_model_2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = UAD_page_model_2.json; sourceTree = "<group>"; };
|
||||
5846ABF52B4762A600FA6C76 /* PollingBehaviorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PollingBehaviorModel.swift; sourceTree = "<group>"; };
|
||||
5878F0A42BD7E68800ADE23D /* mvmcoreui.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcoreui.xcconfig; sourceTree = "<group>"; };
|
||||
5878F0A52BD7E6BE00ADE23D /* mvmcoreui_dev.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcoreui_dev.xcconfig; sourceTree = "<group>"; };
|
||||
@ -1223,6 +1243,14 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
583335532BF64E77001D90D7 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5833355A2BF64E77001D90D7 /* MVMCoreUI.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D29DF0C921E404D4003B2FB9 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -1507,6 +1535,33 @@
|
||||
path = Accessibility;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
583335572BF64E77001D90D7 /* MVMCoreUITests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
583335602BF65063001D90D7 /* JSON */,
|
||||
583335582BF64E77001D90D7 /* MVMCoreUITests.swift */,
|
||||
583335642BF6A5C3001D90D7 /* TestUtils.swift */,
|
||||
);
|
||||
path = MVMCoreUITests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
583335602BF65063001D90D7 /* JSON */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
583335612BF6506C001D90D7 /* Modelling */,
|
||||
);
|
||||
path = JSON;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
583335612BF6506C001D90D7 /* Modelling */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
583335662BF6DCD0001D90D7 /* UAD_page_model_2.json */,
|
||||
583335622BF6509C001D90D7 /* UAD_page_model.json */,
|
||||
);
|
||||
path = Modelling;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8DD1E36C243B3CD900D8F2DF /* ThreeColumn */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -2016,6 +2071,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D29DF0CE21E404D4003B2FB9 /* MVMCoreUI */,
|
||||
583335572BF64E77001D90D7 /* MVMCoreUITests */,
|
||||
D29DF0CD21E404D4003B2FB9 /* Products */,
|
||||
D29DF0E421E4F3C7003B2FB9 /* Frameworks */,
|
||||
);
|
||||
@ -2025,6 +2081,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D29DF0CC21E404D4003B2FB9 /* MVMCoreUI.framework */,
|
||||
583335562BF64E77001D90D7 /* MVMCoreUITests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@ -2601,6 +2658,24 @@
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
583335552BF64E77001D90D7 /* MVMCoreUITests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 5833355F2BF64E77001D90D7 /* Build configuration list for PBXNativeTarget "MVMCoreUITests" */;
|
||||
buildPhases = (
|
||||
583335522BF64E77001D90D7 /* Sources */,
|
||||
583335532BF64E77001D90D7 /* Frameworks */,
|
||||
583335542BF64E77001D90D7 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
5833355C2BF64E77001D90D7 /* PBXTargetDependency */,
|
||||
);
|
||||
name = MVMCoreUITests;
|
||||
productName = MVMCoreUITests;
|
||||
productReference = 583335562BF64E77001D90D7 /* MVMCoreUITests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
D29DF0CB21E404D4003B2FB9 /* MVMCoreUI */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D29DF0D421E404D4003B2FB9 /* Build configuration list for PBXNativeTarget "MVMCoreUI" */;
|
||||
@ -2625,9 +2700,13 @@
|
||||
D29DF0C321E404D4003B2FB9 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1540;
|
||||
LastUpgradeCheck = 1320;
|
||||
ORGANIZATIONNAME = "Verizon Wireless";
|
||||
TargetAttributes = {
|
||||
583335552BF64E77001D90D7 = {
|
||||
CreatedOnToolsVersion = 15.4;
|
||||
};
|
||||
D29DF0CB21E404D4003B2FB9 = {
|
||||
CreatedOnToolsVersion = 10.1;
|
||||
LastSwiftMigration = 1010;
|
||||
@ -2650,11 +2729,21 @@
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
D29DF0CB21E404D4003B2FB9 /* MVMCoreUI */,
|
||||
583335552BF64E77001D90D7 /* MVMCoreUITests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
583335542BF64E77001D90D7 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
583335672BF6DCD0001D90D7 /* UAD_page_model_2.json in Resources */,
|
||||
583335632BF6509C001D90D7 /* UAD_page_model.json in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D29DF0CA21E404D4003B2FB9 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -2673,6 +2762,15 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
583335522BF64E77001D90D7 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
583335592BF64E77001D90D7 /* MVMCoreUITests.swift in Sources */,
|
||||
583335652BF6A5C3001D90D7 /* TestUtils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D29DF0C821E404D4003B2FB9 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -3246,6 +3344,14 @@
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
5833355C2BF64E77001D90D7 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D29DF0CB21E404D4003B2FB9 /* MVMCoreUI */;
|
||||
targetProxy = 5833355B2BF64E77001D90D7 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
D29DF32821EE8736003B2FB9 /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
@ -3260,6 +3366,49 @@
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
5833355D2BF64E77001D90D7 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.5;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.vzw.MVMCoreUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
5833355E2BF64E77001D90D7 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.5;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.vzw.MVMCoreUITests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D29DF0D221E404D4003B2FB9 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 5878F0A52BD7E6BE00ADE23D /* mvmcoreui_dev.xcconfig */;
|
||||
@ -3452,6 +3601,15 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
5833355F2BF64E77001D90D7 /* Build configuration list for PBXNativeTarget "MVMCoreUITests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
5833355D2BF64E77001D90D7 /* Debug */,
|
||||
5833355E2BF64E77001D90D7 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D29DF0C621E404D4003B2FB9 /* Build configuration list for PBXProject "MVMCoreUI" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1540"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
buildArchitectures = "Automatic">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D29DF0CB21E404D4003B2FB9"
|
||||
BuildableName = "MVMCoreUI.framework"
|
||||
BlueprintName = "MVMCoreUI"
|
||||
ReferencedContainer = "container:MVMCoreUI.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D29DF0CB21E404D4003B2FB9"
|
||||
BuildableName = "MVMCoreUI.framework"
|
||||
BlueprintName = "MVMCoreUI"
|
||||
ReferencedContainer = "container:MVMCoreUI.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@ -79,4 +79,16 @@ public class ButtonGroupModel: ParentMoleculeModelProtocol {
|
||||
try container.encodeIfPresent(childWidthValue, forKey: .childWidthValue)
|
||||
try container.encodeIfPresent(childWidthPercentage, forKey: .childWidthPercentage)
|
||||
}
|
||||
|
||||
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return buttons.count == model.buttons.count
|
||||
&& surface == model.surface
|
||||
&& enabled == model.enabled
|
||||
&& alignment == model.alignment
|
||||
&& rowQuantityPhone == model.rowQuantityPhone
|
||||
&& rowQuantityTablet == model.rowQuantityTablet
|
||||
&& childWidthValue == model.childWidthValue
|
||||
&& childWidthPercentage == model.childWidthPercentage
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,7 +192,6 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
return title == model.title
|
||||
&& enabled == model.enabled
|
||||
&& inverted == model.inverted
|
||||
&& action.isEqual(to: model.action)
|
||||
&& accessibilityText == model.accessibilityText
|
||||
&& accessibilityIdentifier == model.accessibilityIdentifier
|
||||
&& accessibilityTraits == model.accessibilityTraits
|
||||
@ -201,6 +200,7 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
&& size == model.size
|
||||
&& groupName == model.groupName
|
||||
&& width == model.width
|
||||
&& action.isEqual(to: model.action)
|
||||
}
|
||||
|
||||
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
|
||||
@ -125,5 +125,19 @@ open class ArrowModel: MoleculeModelProtocol, EnableableModelProtocol {
|
||||
try container.encode(width, forKey: .width)
|
||||
try container.encode(height, forKey: .height)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(inverted, forKey: .inverted)
|
||||
}
|
||||
|
||||
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return backgroundColor == model.backgroundColor
|
||||
&& disabledColor == model.disabledColor
|
||||
&& color == model.color
|
||||
&& degrees == model.degrees
|
||||
&& lineWidth == model.lineWidth
|
||||
&& width == model.width
|
||||
&& height == model.height
|
||||
&& enabled == model.enabled
|
||||
&& inverted == model.inverted
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,4 +61,20 @@
|
||||
case shouldMaskRecordedView
|
||||
case allowServerParameters
|
||||
}
|
||||
|
||||
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return backgroundColor == model.backgroundColor
|
||||
&& image == model.image
|
||||
&& accessibilityText == model.accessibilityText
|
||||
&& fallbackImage == model.fallbackImage
|
||||
&& imageFormat == model.imageFormat
|
||||
&& width == model.width
|
||||
&& height == model.height
|
||||
&& contentMode == model.contentMode
|
||||
&& cornerRadius == model.cornerRadius
|
||||
&& clipsImage == model.clipsImage
|
||||
&& allowServerParameters == model.allowServerParameters
|
||||
&& shouldMaskRecordedView == model.shouldMaskRecordedView
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,8 +53,4 @@ open class LabelAttributeActionModel: LabelAttributeModel {
|
||||
guard super.isEqual(to: model), let model = model as? Self else { return false }
|
||||
return action.isEqual(to: model.action)
|
||||
}
|
||||
|
||||
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
return super.isEqual(to: model)
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,4 +81,10 @@
|
||||
return location == model.location
|
||||
&& length == model.length
|
||||
}
|
||||
|
||||
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return location == model.location
|
||||
&& length == model.length
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,20 +137,20 @@ import VDS
|
||||
guard let model = model as? Self else { return false }
|
||||
return backgroundColor == model.backgroundColor
|
||||
&& text == model.text
|
||||
&& accessibilityText == model.accessibilityText
|
||||
&& textColor == model.textColor
|
||||
&& fontStyle == model.fontStyle
|
||||
&& fontName == model.fontName
|
||||
&& fontSize == model.fontSize
|
||||
&& textAlignment == model.textAlignment
|
||||
&& attributes.isEqual(to: model.attributes)
|
||||
&& html == model.html
|
||||
&& hero == model.hero
|
||||
&& makeWholeViewClickable == model.makeWholeViewClickable
|
||||
&& numberOfLines == model.numberOfLines
|
||||
&& accessibilityText == model.accessibilityText
|
||||
&& accessibilityTraits == model.accessibilityTraits
|
||||
&& inverted == inverted
|
||||
&& shouldMaskRecordedView == model.shouldMaskRecordedView
|
||||
&& attributes.isEqual(to: model.attributes)
|
||||
}
|
||||
|
||||
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
@ -162,7 +162,6 @@ import VDS
|
||||
&& fontName == model.fontName
|
||||
&& fontSize == model.fontSize
|
||||
&& textAlignment == model.textAlignment
|
||||
&& attributes.isVisuallyEquivalent(to: model.attributes)
|
||||
&& html == model.html
|
||||
&& hero == model.hero
|
||||
&& makeWholeViewClickable == model.makeWholeViewClickable
|
||||
@ -170,6 +169,7 @@ import VDS
|
||||
&& accessibilityText == model.accessibilityText
|
||||
&& accessibilityTraits == model.accessibilityTraits
|
||||
&& inverted == inverted
|
||||
&& attributes.isVisuallyEquivalent(to: model.attributes)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -53,17 +53,6 @@ public class TitleLockupModel: ParentMoleculeModelProtocol {
|
||||
&& alignment == model.alignment
|
||||
&& inverted == model.inverted
|
||||
&& backgroundColor == model.backgroundColor
|
||||
&& children.isEqual(to: model.children)
|
||||
}
|
||||
|
||||
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return textAlignment == model.textAlignment
|
||||
&& subTitleColor == model.subTitleColor
|
||||
&& alignment == model.alignment
|
||||
&& inverted == model.inverted
|
||||
&& backgroundColor == model.backgroundColor
|
||||
&& children.isVisuallyEquivalent(to: model.children)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -68,4 +68,9 @@
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(line, forKey: .line)
|
||||
}
|
||||
|
||||
public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return line.matchExistence(with: model.line)
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ open class TabsModel: MoleculeModelProtocol {
|
||||
&& borderLine == model.borderLine
|
||||
&& minWidth == model.minWidth
|
||||
&& selectedIndex == model.selectedIndex
|
||||
&& tabs.isEqual(to: model.tabs)
|
||||
&& tabs == model.tabs
|
||||
}
|
||||
|
||||
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
|
||||
@ -91,15 +91,7 @@ public class TwoButtonViewModel: ParentMoleculeModelProtocol {
|
||||
guard let model = model as? Self else { return false }
|
||||
return backgroundColor == model.backgroundColor
|
||||
&& fillContainer == model.fillContainer
|
||||
&& primaryButton.isEqual(to: model.primaryButton)
|
||||
&& secondaryButton.isEqual(to: model.secondaryButton)
|
||||
}
|
||||
|
||||
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return backgroundColor == model.backgroundColor
|
||||
&& fillContainer == model.fillContainer
|
||||
&& primaryButton.isVisuallyEquivalent(to: model.primaryButton)
|
||||
&& secondaryButton.isVisuallyEquivalent(to: model.secondaryButton)
|
||||
&& primaryButton.matchExistence(with: model.primaryButton)
|
||||
&& secondaryButton.matchExistence(with: model.secondaryButton)
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,6 +80,14 @@ class AccordionListItemModel: MoleculeListItemModel {
|
||||
try container.encodeModelIfPresent(expandAction, forKey: .expandAction)
|
||||
try container.encodeModelIfPresent(collapseAction, forKey: .collapseAction)
|
||||
}
|
||||
|
||||
override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard super.isEqual(to: model), let model = model as? Self else { return false }
|
||||
return selected == model.selected
|
||||
&& hideLineWhenExpanded == model.hideLineWhenExpanded
|
||||
&& expandAction.matchExistence(with: model.expandAction)
|
||||
&& collapseAction.matchExistence(with: model.collapseAction)
|
||||
}
|
||||
}
|
||||
|
||||
extension AccordionListItemModel: PageBehaviorProtocolRequirer {
|
||||
|
||||
@ -140,7 +140,7 @@ import MVMCore
|
||||
&& accessibilityText == model.accessibilityText
|
||||
&& accessibilityValue == model.accessibilityValue
|
||||
&& accessibilityTraits == model.accessibilityTraits
|
||||
&& line.isEqual(to: model.line)
|
||||
&& line.matchExistence(with: model.line)
|
||||
&& action.isEqual(to: model.action)
|
||||
}
|
||||
|
||||
@ -153,6 +153,6 @@ import MVMCore
|
||||
&& accessibilityText == model.accessibilityText
|
||||
&& accessibilityValue == model.accessibilityValue
|
||||
&& accessibilityTraits == model.accessibilityTraits
|
||||
&& line.isVisuallyEquivalent(to: model.line)
|
||||
&& line.matchExistence(with: model.line)
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,6 +82,6 @@
|
||||
|
||||
public override func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
guard super.isVisuallyEquivalent(to: model), let model = model as? Self else { return false }
|
||||
return border == border
|
||||
return border == model.border
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,14 +52,4 @@ import MVMCore
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeModel(molecule, forKey: .molecule)
|
||||
}
|
||||
|
||||
public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard super.isEqual(to: model), let model = model as? Self else { return false }
|
||||
return molecule.isEqual(to: model)
|
||||
}
|
||||
|
||||
public override func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
guard super.isVisuallyEquivalent(to: model), let model = model as? Self else { return false }
|
||||
return molecule.isVisuallyEquivalent(to: model.molecule)
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,14 +60,7 @@
|
||||
}
|
||||
|
||||
public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard super.isEqual(to: model), let model = model as? Self else { return false }
|
||||
return spacing == model.spacing
|
||||
&& percent == model.percent
|
||||
&& gone == model.gone
|
||||
}
|
||||
|
||||
public override func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
guard super.isVisuallyEquivalent(to: model), let model = model as? Self else { return false }
|
||||
guard super.isEqual(to: model), let model = model as? Self else { return false }
|
||||
return spacing == model.spacing
|
||||
&& percent == model.percent
|
||||
&& gone == model.gone
|
||||
|
||||
@ -20,7 +20,7 @@ public class TabsListItemModel: ListItemModel, ParentMoleculeModelProtocol {
|
||||
private var addedMolecules: [ListItemModelProtocol & MoleculeModelProtocol]?
|
||||
|
||||
public var children: [MoleculeModelProtocol] {
|
||||
return molecules.flatMap { $0 }
|
||||
return [tabs] + molecules.flatMap { $0 }
|
||||
}
|
||||
|
||||
public func replaceChildMolecule(with replacementMolecule: MoleculeModelProtocol) throws -> MoleculeModelProtocol? {
|
||||
@ -94,16 +94,7 @@ public class TabsListItemModel: ListItemModel, ParentMoleculeModelProtocol {
|
||||
|
||||
public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard super.isEqual(to: model), let model = model as? Self else { return false }
|
||||
return tabs.isEqual(to: model.tabs)
|
||||
&& molecules.count == model.molecules.count
|
||||
&& zip(molecules, model.molecules).allSatisfy({ $0.0.isEqual(to: $0.1) })
|
||||
}
|
||||
|
||||
public override func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
guard super.isVisuallyEquivalent(to: model), let model = model as? Self else { return false }
|
||||
return tabs.isVisuallyEquivalent(to: model.tabs)
|
||||
&& molecules.count == model.molecules.count
|
||||
&& zip(molecules, model.molecules).allSatisfy({ $0.0.isVisuallyEquivalent(to: $0.1) })
|
||||
return molecules.count == model.molecules.count
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -73,6 +73,25 @@ public class NavigationImageButtonModel: NavigationButtonModelProtocol, Molecule
|
||||
try container.encodeIfPresent(imageRenderingMode, forKey: .imageRenderingMode)
|
||||
}
|
||||
|
||||
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return true }
|
||||
return backgroundColor == model.backgroundColor
|
||||
&& accessibilityIdentifier == model.accessibilityIdentifier
|
||||
&& image == model.image
|
||||
&& accessibilityText == model.accessibilityText
|
||||
&& imageRenderingMode == model.imageRenderingMode
|
||||
&& action.isEqual(to: action)
|
||||
}
|
||||
|
||||
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return true }
|
||||
return backgroundColor == model.backgroundColor
|
||||
&& accessibilityIdentifier == model.accessibilityIdentifier
|
||||
&& image == model.image
|
||||
&& accessibilityText == model.accessibilityText
|
||||
&& imageRenderingMode == model.imageRenderingMode
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Method
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -64,8 +64,7 @@ open class MoleculeContainerModel: ContainerModel, MoleculeContainerModelProtoco
|
||||
|
||||
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return molecule.isEqual(to: model.molecule)
|
||||
&& backgroundColor == model.backgroundColor
|
||||
return backgroundColor == model.backgroundColor
|
||||
}
|
||||
|
||||
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
|
||||
@ -110,6 +110,9 @@ public class EyebrowHeadlineBodyLinkModel: ParentMoleculeModelProtocol {
|
||||
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return backgroundColor == model.backgroundColor
|
||||
&& children.isEqual(to: model.children)
|
||||
&& eyebrow.matchExistence(with: model.eyebrow)
|
||||
&& headline.matchExistence(with: model.headline)
|
||||
&& body.matchExistence(with: model.body)
|
||||
&& link.matchExistence(with: model.link)
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,18 +96,8 @@ open class HeadlineBodyModel: ParentMoleculeModelProtocol {
|
||||
|
||||
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return headline.isEqual(to: model.headline)
|
||||
&& body.isEqual(to: model.body)
|
||||
&& style == style
|
||||
&& backgroundColor == backgroundColor
|
||||
}
|
||||
|
||||
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return headline.isVisuallyEquivalent(to: model.headline)
|
||||
&& body.isVisuallyEquivalent(to: model.body)
|
||||
&& style == style
|
||||
&& backgroundColor == backgroundColor
|
||||
return style == style
|
||||
&& backgroundColor == model.backgroundColor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -174,7 +174,7 @@ open class Carousel: View {
|
||||
MVMCoreLoggingHandler.shared()?.handleDebugMessage("[\(Self.self)] [\(ObjectIdentifier(self).hashValue)]\noriginal model: \(originalModel?.debugDescription ?? "none")\nnew model: \(model)")
|
||||
|
||||
if #available(iOS 15.0, *) {
|
||||
if let originalModel, carouselModel.isVisuallyEquivalent(to: originalModel) {
|
||||
if let originalModel, carouselModel.isDeeplyVisuallyEquivalent(to: originalModel) {
|
||||
// Prevents a carousel reset while still updating the cell backing data through reconfigureItems.
|
||||
MVMCoreLoggingHandler.shared()?.handleDebugMessage("[\(Self.self)] Model is visually equivalent. Skipping rebuild...")
|
||||
FormValidator.setupValidation(for: carouselModel, delegate: delegateObject?.formHolderDelegate)
|
||||
|
||||
@ -175,14 +175,12 @@ import UIKit
|
||||
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return backgroundColor == backgroundColor
|
||||
&& molecules.isEqual(to: model.molecules)
|
||||
&& spacing == model.spacing
|
||||
&& border == model.border
|
||||
&& loop == model.loop
|
||||
&& height == model.height
|
||||
&& itemWidthPercent == model.itemWidthPercent
|
||||
&& itemAlignment == model.itemAlignment
|
||||
&& pagingMolecule.isEqual(to: model.pagingMolecule)
|
||||
&& paging == model.paging
|
||||
&& useHorizontalMargins == model.useHorizontalMargins
|
||||
&& leftPadding == model.leftPadding
|
||||
@ -193,6 +191,8 @@ import UIKit
|
||||
&& groupName == model.groupName
|
||||
&& enabled == model.enabled
|
||||
&& readOnly == model.readOnly
|
||||
&& molecules.count == model.molecules.count
|
||||
&& pagingMolecule.matchExistence(with: model.pagingMolecule)
|
||||
}
|
||||
|
||||
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
@ -212,8 +212,6 @@ import UIKit
|
||||
&& baseValue == model.baseValue
|
||||
&& enabled == model.enabled
|
||||
&& readOnly == model.readOnly
|
||||
&& pagingMolecule.isVisuallyEquivalent(to: model.pagingMolecule)
|
||||
&& molecules.isVisuallyEquivalent(to: model.molecules)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -82,16 +82,8 @@
|
||||
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return backgroundColor == model.backgroundColor
|
||||
&& molecules.isEqual(to: model.molecules)
|
||||
&& axis == model.axis
|
||||
&& spacing == model.spacing
|
||||
}
|
||||
|
||||
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return backgroundColor == model.backgroundColor
|
||||
&& molecules.isVisuallyEquivalent(to: model.molecules)
|
||||
&& axis == model.axis
|
||||
&& spacing == model.spacing
|
||||
&& molecules.count == model.molecules.count
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ import Foundation
|
||||
public protocol MoleculeModelComparisonProtocol: ModelComparisonProtocol {
|
||||
|
||||
/**
|
||||
True if there are no visual differences between models.
|
||||
Shallow check if there are no visual differences between models.
|
||||
|
||||
By default if the models are equal then they are visually equivalent. However, if there are parts of models that can be upddated without a UI update, this could be subset of properties.
|
||||
**/
|
||||
@ -25,6 +25,16 @@ extension MoleculeModelComparisonProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
public extension MoleculeModelComparisonProtocol where Self: ParentModelProtocol {
|
||||
func isDeeplyVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return !findFirst(in: model, failing: { mine, theirs in
|
||||
guard let mine = mine as? MoleculeModelComparisonProtocol, let theirs = theirs as? MoleculeModelComparisonProtocol else { return false }
|
||||
return mine.isVisuallyEquivalent(to: theirs)
|
||||
}).matched
|
||||
}
|
||||
}
|
||||
|
||||
public extension Optional {
|
||||
|
||||
/// Checks if the curent model is equal to another model.
|
||||
|
||||
@ -21,7 +21,8 @@ public extension MoleculeModelProtocol {
|
||||
|
||||
func isEqual(to model: ModelProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return id == model.id
|
||||
return moleculeName == model.moleculeName
|
||||
&& backgroundColor == model.backgroundColor
|
||||
}
|
||||
|
||||
var debugDescription: String {
|
||||
|
||||
@ -67,16 +67,6 @@ public protocol ParentMoleculeModelProtocol: ParentModelProtocol, MoleculeModelP
|
||||
|
||||
public extension ParentMoleculeModelProtocol {
|
||||
|
||||
func isEqual(to model: any ModelProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return model.children.isEqual(to: model.children)
|
||||
}
|
||||
|
||||
func areVisuallyEquivalent(to model: any ModelProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return model.children.isVisuallyEquivalent(to: model.children)
|
||||
}
|
||||
|
||||
func reduceDepthFirstTraverse<Result>(options: TreeTraversalOptions, depth: Int, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol, Int) -> Result) -> Result {
|
||||
var result = initialResult
|
||||
if (options == .parentFirst) {
|
||||
@ -122,53 +112,66 @@ public extension ParentMoleculeModelProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
extension ParentModelProtocol {
|
||||
public extension ParentModelProtocol {
|
||||
|
||||
public typealias DeepCompareResult = (matched: Bool, myChild: ModelProtocol?, theirChild: ModelProtocol?)
|
||||
typealias DeepCompareResult = (matched: Bool, mine: ModelProtocol?, theirs: ModelProtocol?)
|
||||
|
||||
public typealias ModelPair = (mine: ModelProtocol, theirs: ModelProtocol)
|
||||
typealias ModelPair = (mine: ModelProtocol, theirs: ModelProtocol)
|
||||
|
||||
public func deepEquals(to model: any ModelProtocol) -> DeepCompareResult {
|
||||
guard let model = model as? ParentModelProtocol else { return (false, self, model) }
|
||||
return findFirst(in: model) { $0.isEqual(to: $1) }
|
||||
func deepEquals(to model: any ModelProtocol) -> Bool {
|
||||
guard let model = model as? ParentModelProtocol else { return false }
|
||||
return !findFirst(in: model, failing: { $0.isEqual(to: $1) }).matched
|
||||
}
|
||||
|
||||
func findFirst(in anotherParent: ParentModelProtocol, where test: (ModelProtocol, ModelProtocol)->Bool) -> DeepCompareResult {
|
||||
func findFirst(in anotherParent: ParentModelProtocol, failing test: (ModelProtocol, ModelProtocol)->Bool, options: TreeTraversalOptions = .childFirst) -> DeepCompareResult {
|
||||
|
||||
guard test(self, anotherParent) else { return (false, myChild: self, theirChild: anotherParent)}
|
||||
guard options != .parentFirst, test(self, anotherParent) else { return (true, mine: self, theirs: anotherParent)}
|
||||
|
||||
let myChildren = children
|
||||
let theirChildren = anotherParent.children
|
||||
guard myChildren.count == theirChildren.count else { return (false, myChild: self, theirChild: self) }
|
||||
guard myChildren.count == theirChildren.count else { return (true, mine: self, theirs: anotherParent) }
|
||||
for index in myChildren.indices {
|
||||
if let myChild = myChildren[index] as? ParentModelProtocol {
|
||||
if let theirChild = theirChildren[index] as? ParentModelProtocol {
|
||||
let result = myChild.findFirst(in: theirChild, where: test)
|
||||
guard result.0 else { return result }
|
||||
let result = myChild.findFirst(in: theirChild, failing: test)
|
||||
guard !result.0 else { return result }
|
||||
} else {
|
||||
return (false, myChild: myChild, theirChild: theirChildren[index])
|
||||
return (true, mine: myChild, theirs: theirChildren[index])
|
||||
}
|
||||
} else if !test(myChildren[index], theirChildren[index]) {
|
||||
return (false, myChild: myChildren[index], theirChild: theirChildren[index])
|
||||
return (true, mine: myChildren[index], theirs: theirChildren[index])
|
||||
}
|
||||
}
|
||||
|
||||
return (true, nil, nil)
|
||||
guard options == .childFirst, test(self, anotherParent) else { return (true, mine: self, theirs: anotherParent)}
|
||||
|
||||
return (false, nil, nil)
|
||||
}
|
||||
|
||||
func findAllTheirsNotEqual<T>(against anotherParent: ParentModelProtocol) -> [T] {
|
||||
return deepCompare(against: anotherParent) { $0.isEqual(to: $1) }.compactMap { $0.theirs as? T }
|
||||
}
|
||||
|
||||
func findAllNotEqual(against anotherParent: ParentModelProtocol) -> [ModelPair] {
|
||||
return deepCompare(against: anotherParent) { $0.isEqual(to: $1) }
|
||||
}
|
||||
|
||||
func deepCompare(against anotherParent: ParentModelProtocol, where test: (ModelProtocol, ModelProtocol)->Bool) -> [ModelPair] {
|
||||
|
||||
guard test(self, anotherParent) else { return [(self, anotherParent)]}
|
||||
var allDiffs = [ModelPair]()
|
||||
|
||||
let myChildren = children
|
||||
let theirChildren = anotherParent.children
|
||||
guard myChildren.count == theirChildren.count else { return [(self, anotherParent)] }
|
||||
|
||||
var allDiffs = [ModelPair]()
|
||||
if !test(self, anotherParent) {
|
||||
allDiffs.append((self, anotherParent))
|
||||
}
|
||||
|
||||
for index in myChildren.indices {
|
||||
if let myChild = myChildren[index] as? ParentModelProtocol,
|
||||
let theirChild = theirChildren[index] as? ParentModelProtocol {
|
||||
let childDiffs = myChild.deepCompare(against: theirChild, where: test) as [ModelPair]
|
||||
let childDiffs = myChild.deepCompare(against: theirChild, where: test)
|
||||
allDiffs.append(contentsOf: childDiffs)
|
||||
} else if !test(myChildren[index], theirChildren[index]) {
|
||||
allDiffs.append((myChildren[index], theirChildren[index]))
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
|
||||
public protocol TemplateModelProtocol: PageModelProtocol, ModelProtocol, MoleculeTreeTraversalProtocol, ParentModelProtocol {
|
||||
public protocol TemplateModelProtocol: PageModelProtocol, ModelProtocol, MoleculeTreeTraversalProtocol, ParentModelProtocol, MoleculeModelComparisonProtocol {
|
||||
var template: String { get }
|
||||
var rootMolecules: [MoleculeModelProtocol] { get }
|
||||
/// Page rendering ID. Unique betwen JSON parses.
|
||||
|
||||
@ -121,4 +121,18 @@ import Foundation
|
||||
try container.encodeIfPresent(tabBarIndex, forKey: .tabBarIndex)
|
||||
try container.encode(shouldMaskScreenWhileRecording, forKey: .shouldMaskScreenWhileRecording)
|
||||
}
|
||||
|
||||
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard let model = model as? Self else { return false }
|
||||
return pageType == model.pageType
|
||||
&& backgroundColor == model.backgroundColor
|
||||
&& screenHeading == model.screenHeading
|
||||
&& formRules?.count ?? 0 == model.formRules?.count ?? 0
|
||||
&& navigationBar.matchExistence(with: model.navigationBar)
|
||||
&& tabBarHidden == model.tabBarHidden
|
||||
&& hideLeftPanel == model.hideLeftPanel
|
||||
&& hideRightPanel == model.hideRightPanel
|
||||
&& tabBarIndex == model.tabBarIndex
|
||||
&& shouldMaskScreenWhileRecording == model.shouldMaskScreenWhileRecording
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,4 +100,14 @@
|
||||
try container.encodeIfPresent(footerlessSpacerColor, forKey: .footerlessSpacerColor)
|
||||
try container.encodeIfPresent(footerlessSpacerHeight, forKey: .footerlessSpacerHeight)
|
||||
}
|
||||
|
||||
public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard super.isEqual(to: model), let model = model as? Self else { return false }
|
||||
return line.matchExistence(with: model.line)
|
||||
&& scrollToRowIndex == model.scrollToRowIndex
|
||||
&& singleCellSelection == model.singleCellSelection
|
||||
&& footerlessSpacerColor == model.footerlessSpacerColor
|
||||
&& footerlessSpacerHeight == model.footerlessSpacerHeight
|
||||
&& molecules?.count ?? 0 == model.molecules?.count ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,6 +270,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol
|
||||
return IndexPath(row: $0, section: 0)
|
||||
}
|
||||
|
||||
debugLog("Refreshing rows \(indexPaths.map { $0.row })")
|
||||
|
||||
if #available(iOS 15.0, *) {
|
||||
// All rows should have been layed out already on the first newDataBuildScreen reload with the getMoleculeInfoList call. Therefore, we can be safe to assume the top level cell configuration will not be modified and only the child content will be updated allowing us to levearage this more efficient method.
|
||||
tableView.reconfigureRows(at: indexPaths)
|
||||
|
||||
@ -77,4 +77,12 @@
|
||||
try container.encodeIfPresent(anchorFooter, forKey: .anchorFooter)
|
||||
try container.encodeModelIfPresent(footer, forKey: .footer)
|
||||
}
|
||||
|
||||
public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
|
||||
guard super.isEqual(to: model), let model = model as? Self else { return false }
|
||||
return anchorHeader == model.anchorHeader
|
||||
&& anchorFooter == model.anchorFooter
|
||||
&& header.matchExistence(with: model.header)
|
||||
&& footer.matchExistence(with: model.footer)
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ import MVMCore
|
||||
public var needsUpdateUI = false
|
||||
private var observingForResponses: NSObjectProtocol?
|
||||
private var initialLoadFinished = false
|
||||
private var isFirstRender = true
|
||||
public var isFirstRender = true
|
||||
public var previousScreenSize = CGSize.zero
|
||||
|
||||
public var selectedField: UIView?
|
||||
@ -259,7 +259,12 @@ import MVMCore
|
||||
if let updatedMolecules = behavior.onPageNew(rootMolecules: newTemplateModel.rootMolecules, delegateObjectIVar) {
|
||||
updatedMolecules.forEach { molecule in
|
||||
if let replaced = try? newTemplateModel.replaceChildMolecule(with: molecule) {
|
||||
if !replaced.isEqual(to: molecule) { // Only recognize the molecules that actually changed.
|
||||
// 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.)
|
||||
}
|
||||
@ -289,7 +294,7 @@ import MVMCore
|
||||
!new.isEqual(to: old)
|
||||
}
|
||||
debugLog("Page molecule updates\n\(diffs.map {"\($0.mine) vs. \($0.theirs)"}.joined(separator: "\n"))")
|
||||
pageUpdatedModels = diffs.compactMap { $0.mine as? MoleculeModelProtocol }
|
||||
pageUpdatedModels = diffs.compactMap { $0.theirs as? MoleculeModelProtocol }
|
||||
}
|
||||
|
||||
let allUpdatedMolecules = isFirstRender ? [] : behaviorUpdatedModels + pageUpdatedModels
|
||||
@ -303,7 +308,7 @@ import MVMCore
|
||||
debugLog("Performing full page render...")
|
||||
updateUI()
|
||||
} else {
|
||||
debugLog("Updating \(allUpdatedMolecules) molecules...")
|
||||
debugLog("Performing partial render of \(allUpdatedMolecules) molecules...")
|
||||
updateUI(for: allUpdatedMolecules)
|
||||
}
|
||||
|
||||
|
||||
807
MVMCoreUITests/JSON/Modelling/UAD_page_model.json
Normal file
807
MVMCoreUITests/JSON/Modelling/UAD_page_model.json
Normal file
@ -0,0 +1,807 @@
|
||||
{
|
||||
"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": [
|
||||
[
|
||||
{
|
||||
"id": "priorityTiles",
|
||||
"line": {
|
||||
"type": "none"
|
||||
},
|
||||
"backgroundColor": "black",
|
||||
"moleculeName": "listItem",
|
||||
"molecule": {
|
||||
"moleculeName": "carousel",
|
||||
"height": 160,
|
||||
"molecules": [
|
||||
{
|
||||
"moleculeName": "carouselItem",
|
||||
"molecule": {
|
||||
"contentMode": "scaleToFill",
|
||||
"moleculeName": "image",
|
||||
"image": "single_card_skeleton_loader",
|
||||
"imageFormat": "gif"
|
||||
},
|
||||
"topPadding": 16,
|
||||
"useHorizontalMargins": false,
|
||||
"cornerRadius": 8,
|
||||
"useVerticalMargins": true,
|
||||
"backgroundColor": "white",
|
||||
"bottomPadding": 16
|
||||
}
|
||||
],
|
||||
"itemWidthPercent": 100,
|
||||
"accessibilityText": "carousel",
|
||||
"spacing": 12,
|
||||
"pagingMolecule": {
|
||||
"moleculeName": "barsCarouselIndicator",
|
||||
"position": -20,
|
||||
"inverted": true
|
||||
},
|
||||
"rightPadding": 16,
|
||||
"leftPadding": 16
|
||||
},
|
||||
"gone": true
|
||||
},
|
||||
{
|
||||
"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
|
||||
}
|
||||
807
MVMCoreUITests/JSON/Modelling/UAD_page_model_2.json
Normal file
807
MVMCoreUITests/JSON/Modelling/UAD_page_model_2.json
Normal file
@ -0,0 +1,807 @@
|
||||
{
|
||||
"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": [
|
||||
[
|
||||
{
|
||||
"id": "priorityTiles",
|
||||
"line": {
|
||||
"type": "none"
|
||||
},
|
||||
"backgroundColor": "black",
|
||||
"moleculeName": "listItem",
|
||||
"molecule": {
|
||||
"moleculeName": "carousel",
|
||||
"height": 160,
|
||||
"molecules": [
|
||||
{
|
||||
"moleculeName": "carouselItem",
|
||||
"molecule": {
|
||||
"contentMode": "scaleToFill",
|
||||
"moleculeName": "image",
|
||||
"image": "single_card_skeleton_loader",
|
||||
"imageFormat": "gif"
|
||||
},
|
||||
"topPadding": 16,
|
||||
"useHorizontalMargins": false,
|
||||
"cornerRadius": 8,
|
||||
"useVerticalMargins": true,
|
||||
"backgroundColor": "white",
|
||||
"bottomPadding": 16
|
||||
}
|
||||
],
|
||||
"itemWidthPercent": 100,
|
||||
"accessibilityText": "carousel",
|
||||
"spacing": 12,
|
||||
"pagingMolecule": {
|
||||
"moleculeName": "barsCarouselIndicator",
|
||||
"position": -20,
|
||||
"inverted": true
|
||||
},
|
||||
"rightPadding": 16,
|
||||
"leftPadding": 16
|
||||
},
|
||||
"gone": true
|
||||
},
|
||||
{
|
||||
"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": "2",
|
||||
"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
|
||||
}
|
||||
212
MVMCoreUITests/MVMCoreUITests.swift
Normal file
212
MVMCoreUITests/MVMCoreUITests.swift
Normal file
@ -0,0 +1,212 @@
|
||||
//
|
||||
// MVMCoreUITests.swift
|
||||
// MVMCoreUITests
|
||||
//
|
||||
// Created by Kyle Hedden on 5/16/24.
|
||||
// Copyright © 2024 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import MVMCoreUI
|
||||
import MVMCore
|
||||
|
||||
enum TestError: Error {
|
||||
case resoureNotFound
|
||||
}
|
||||
|
||||
final class MVMCoreUITests: XCTestCase {
|
||||
|
||||
override class func setUp() {
|
||||
super.setUp()
|
||||
CoreUIModelMapping.registerObjects()
|
||||
}
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
//func testExample() throws {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
// Any test you write for XCTest can be annotated as throws and async.
|
||||
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
|
||||
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
|
||||
//}
|
||||
|
||||
func testModelShallowEquality() throws {
|
||||
let model1 = StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello World")
|
||||
)
|
||||
])
|
||||
|
||||
let model2 = StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello World")
|
||||
)
|
||||
])
|
||||
|
||||
let model3 = StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello Moon")
|
||||
)
|
||||
])
|
||||
|
||||
XCTAssertTrue(model1.isVisuallyEquivalent(to: model2))
|
||||
XCTAssertTrue(model1.isVisuallyEquivalent(to: model3))
|
||||
|
||||
XCTAssertTrue(LabelModel(text: "Hello World").isEqual(to: LabelModel(text: "Hello World")))
|
||||
XCTAssertFalse(LabelModel(text: "Hello World").isEqual(to: LabelModel(text: "Hello Moon")))
|
||||
}
|
||||
|
||||
func testFindFirstCompare() throws {
|
||||
|
||||
let model1 = StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello World")
|
||||
)
|
||||
])
|
||||
|
||||
let model2 = StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello Moon")
|
||||
)
|
||||
])
|
||||
|
||||
let result = model1.findFirst(in: model2) { model1, model2 in
|
||||
model1.isEqual(to: model2)
|
||||
}
|
||||
XCTAssertTrue(result.matched)
|
||||
XCTAssertEqual((result.theirs as? LabelModel)?.text, "Hello Moon")
|
||||
}
|
||||
|
||||
func testDeepCompare() throws {
|
||||
|
||||
let model1 = StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello World")
|
||||
)
|
||||
])
|
||||
|
||||
let model2 = StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello Moon")
|
||||
)
|
||||
])
|
||||
|
||||
let attributedLabel = LabelModel(text: "Hello World")
|
||||
attributedLabel.attributes = [LabelAttributeActionModel(0, 5, action: ActionNoopModel())]
|
||||
let model3 = StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
attributedLabel
|
||||
)
|
||||
])
|
||||
|
||||
let attributedLabel2 = LabelModel(text: "Hello World")
|
||||
attributedLabel2.attributes = [LabelAttributeActionModel(0, 5, action: ActionBackModel())]
|
||||
let model4 = StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
attributedLabel2
|
||||
)
|
||||
])
|
||||
|
||||
let results = model1.findAllNotEqual(against: model2)
|
||||
XCTAssertEqual(results.count, 1)
|
||||
XCTAssertEqual((results.first?.theirs as? LabelModel)?.text, "Hello Moon")
|
||||
XCTAssertFalse(model1.deepEquals(to: model2))
|
||||
XCTAssertFalse(model1.isDeeplyVisuallyEquivalent(to: model2))
|
||||
XCTAssertFalse(model1.deepEquals(to: model3))
|
||||
|
||||
let visualResults = model3.findFirst(in: model4, failing: { mine, theirs in
|
||||
guard let mine = mine as? MoleculeModelComparisonProtocol, let theirs = theirs as? MoleculeModelComparisonProtocol else { return false }
|
||||
return mine.isVisuallyEquivalent(to: theirs)
|
||||
})
|
||||
XCTAssertFalse(visualResults.matched)
|
||||
XCTAssertTrue(model3.isDeeplyVisuallyEquivalent(to: model4))
|
||||
}
|
||||
|
||||
func testDeepCompareReturnsAllResults() {
|
||||
let model1 = StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello World")
|
||||
),
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello Moon")
|
||||
),
|
||||
MoleculeStackItemModel(with:
|
||||
StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello Stars")
|
||||
)
|
||||
])
|
||||
)
|
||||
])
|
||||
|
||||
let model2 = StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello Stars")
|
||||
),
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello World")
|
||||
),
|
||||
MoleculeStackItemModel(with:
|
||||
StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello Moon")
|
||||
)
|
||||
])
|
||||
)
|
||||
])
|
||||
|
||||
let model3 = StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello Stars")
|
||||
),
|
||||
MoleculeStackItemModel(with:
|
||||
StackModel(molecules: [
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello Moon")
|
||||
)
|
||||
])
|
||||
),
|
||||
MoleculeStackItemModel(with:
|
||||
LabelModel(text: "Hello World")
|
||||
)
|
||||
])
|
||||
|
||||
var results = model1.findAllNotEqual(against: model2)
|
||||
XCTAssertEqual(results.count, 3)
|
||||
|
||||
results = model1.findAllNotEqual(against: model3)
|
||||
XCTAssertEqual(results.count, 3)
|
||||
}
|
||||
|
||||
func testPageEquality() throws {
|
||||
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 results = listTemplateModel1.findFirst(in: listTemplateModel2, failing: { $0.isEqual(to: $1) })
|
||||
XCTAssertFalse(results.matched)
|
||||
XCTAssertTrue(listTemplateModel1.deepEquals(to: listTemplateModel2))
|
||||
XCTAssertTrue(listTemplateModel1.isDeeplyVisuallyEquivalent(to: listTemplateModel2))
|
||||
|
||||
let results2 = listTemplateModel1.findFirst(in: listTemplateModel3, failing: { $0.isEqual(to: $1) })
|
||||
XCTAssertTrue(results2.matched)
|
||||
XCTAssertFalse(listTemplateModel1.deepEquals(to: listTemplateModel3))
|
||||
XCTAssertTrue(listTemplateModel1.isDeeplyVisuallyEquivalent(to: listTemplateModel3))
|
||||
}
|
||||
|
||||
func testPageEqualityPerformance() throws {
|
||||
let listTemplateModel1 = try JSONDecoder().decode(ListPageTemplateModel.self, from: getFileData("UAD_page_model"))
|
||||
let listTemplateModel2 = try JSONDecoder().decode(ListPageTemplateModel.self, from: getFileData("UAD_page_model_2"))
|
||||
measure {
|
||||
XCTAssertFalse(listTemplateModel1.deepEquals(to: listTemplateModel2))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
19
MVMCoreUITests/TestUtils.swift
Normal file
19
MVMCoreUITests/TestUtils.swift
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// TestUtils.swift
|
||||
// MVMCoreUITests
|
||||
//
|
||||
// Created by Kyle Hedden on 5/16/24.
|
||||
// Copyright © 2024 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import XCTest
|
||||
|
||||
extension XCTestCase {
|
||||
|
||||
func getFileData(_ fileName: String, type: String = "json") throws -> Data {
|
||||
guard let resourcePath = Bundle(identifier: "com.vzw.MVMCoreUITests")?.path(forResource: fileName, ofType: type) else { throw TestError.resoureNotFound }
|
||||
return try Data(contentsOf: URL(fileURLWithPath: resourcePath))
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user