From f7a348a8b0261bf8e790a2ad2d4ccd9d7ec9f922 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Tue, 23 Apr 2024 19:02:05 -0400 Subject: [PATCH 1/3] Digital PCT265 defect PRODDEF-28200 - Prevent navigation to the same controller fixing hang ups. --- MVMCore/MVMCore/PresentationHandling/NavigationOperation.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MVMCore/MVMCore/PresentationHandling/NavigationOperation.swift b/MVMCore/MVMCore/PresentationHandling/NavigationOperation.swift index ad3e37d..a6aa16c 100644 --- a/MVMCore/MVMCore/PresentationHandling/NavigationOperation.swift +++ b/MVMCore/MVMCore/PresentationHandling/NavigationOperation.swift @@ -110,7 +110,8 @@ open class NavigationOperation: MVMCoreOperation, UINavigationControllerDelegate */ @MainActor open func set(viewControllers: [UIViewController], navigationController: UINavigationController, animated: Bool) { - guard viewControllers.count > 0 else { + guard viewControllers.count > 0, + navigationController.viewControllers != viewControllers else { // If the controller stack is the same, iOS will not call the delegate method of the change, causing the operation to hang. markAsFinished() return } From a428d5f7ce3c2628481df3fe491a2b7380aa804f Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Thu, 25 Apr 2024 15:50:41 -0400 Subject: [PATCH 2/3] Digital PCT265 defect CXTDT-531317 - Adjust logging to capture webview errors. --- MVMCore/MVMCore.xcodeproj/project.pbxproj | 4 ++ .../ActionHandling/MVMCoreActionHandler.swift | 8 ++- .../Utility/ReadableDecodingErrors.swift | 69 +++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 MVMCore/MVMCore/Utility/ReadableDecodingErrors.swift diff --git a/MVMCore/MVMCore.xcodeproj/project.pbxproj b/MVMCore/MVMCore.xcodeproj/project.pbxproj index c827f0f..5c113a1 100644 --- a/MVMCore/MVMCore.xcodeproj/project.pbxproj +++ b/MVMCore/MVMCore.xcodeproj/project.pbxproj @@ -42,6 +42,7 @@ 2723337B28BD534D004EAEE0 /* MVMCoreEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2723337A28BD534D004EAEE0 /* MVMCoreEvent.swift */; }; 2723337D28BD53C2004EAEE0 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2723337C28BD53C2004EAEE0 /* Date+Extension.swift */; }; 5846ABF42B44BB9000FA6C76 /* Collection+Safe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846ABF32B44BB9000FA6C76 /* Collection+Safe.swift */; }; + 5878F0B22BDAA63E00ADE23D /* ReadableDecodingErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5878F0B12BDAA63E00ADE23D /* ReadableDecodingErrors.swift */; }; 6042E8FC2B317B190031644B /* MVMCoreLoggingHandlerHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 6042E8FB2B3094680031644B /* MVMCoreLoggingHandlerHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 605A9A2A2ABD712F00487E47 /* MVMCoreLoggingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 605A9A292ABD712F00487E47 /* MVMCoreLoggingHandler.swift */; }; 6079EDCE2AD97AA5004B7A85 /* MVMCoreLoggingDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6079EDCD2AD97AA5004B7A85 /* MVMCoreLoggingDelegateProtocol.swift */; }; @@ -194,6 +195,7 @@ 581FABEE2A71D0E6003A8508 /* mvmcore_dev.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcore_dev.xcconfig; sourceTree = ""; }; 5836B8E22A4338DF002553D9 /* mvmcore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcore.xcconfig; sourceTree = ""; }; 5846ABF32B44BB9000FA6C76 /* Collection+Safe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Collection+Safe.swift"; sourceTree = ""; }; + 5878F0B12BDAA63E00ADE23D /* ReadableDecodingErrors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadableDecodingErrors.swift; sourceTree = ""; }; 6042E8FB2B3094680031644B /* MVMCoreLoggingHandlerHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreLoggingHandlerHelper.h; sourceTree = ""; }; 605A9A292ABD712F00487E47 /* MVMCoreLoggingHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreLoggingHandler.swift; sourceTree = ""; }; 6079EDCD2AD97AA5004B7A85 /* MVMCoreLoggingDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreLoggingDelegateProtocol.swift; sourceTree = ""; }; @@ -396,6 +398,7 @@ children = ( AF60A7F1289212CA00919EEB /* MVMError.swift */, AF60A7F3289212EB00919EEB /* MVMCoreError.swift */, + 5878F0B12BDAA63E00ADE23D /* ReadableDecodingErrors.swift */, 881D26911FCC9D180079C521 /* MVMCoreErrorObject.h */, 881D268F1FCC9D180079C521 /* MVMCoreErrorObject.m */, 881D26921FCC9D180079C521 /* MVMCoreOperation.h */, @@ -877,6 +880,7 @@ AFA4931E29E5C988001A9663 /* MVMCoreActionUtility+Extension.swift in Sources */, 1DAD0FFE26AAB40000216E83 /* ActionRunJavaScriptModel.swift in Sources */, 946EE1AB237B5C940036751F /* Decoder.swift in Sources */, + 5878F0B22BDAA63E00ADE23D /* ReadableDecodingErrors.swift in Sources */, 2723337D28BD53C2004EAEE0 /* Date+Extension.swift in Sources */, AF70699A287DD02400077CF6 /* ActionContactHandler.swift in Sources */, AF69D4F3286E9DCE00BC6862 /* ActionActionsHandler.swift in Sources */, diff --git a/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift b/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift index 5d87fea..ff2378e 100644 --- a/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift @@ -154,6 +154,12 @@ public protocol MVMCoreJSONActionHandlerProtocol: MVMCoreActionHandlerProtocol { fileprivate func logActionError(_ error: Error, _ actionType: String?, _ additionalData: [AnyHashable: Any]?, _ delegateObject: DelegateObject?) { MVMCoreActionHandler.log(string: "Failed Action: Error \(error)", additionalData: additionalData) if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: MVMCoreActionHandler.getErrorLocation(with: delegateObject?.actionDelegate, actionType: actionType ?? "noAction")) { + if let fromBridge = additionalData?["fromBridge"] as? Bool, fromBridge, let browserUrl = additionalData?["browserUrl"] as? String { + errorObject.requestUrl = browserUrl + } + if let humanReadableMessage = (error as? HumanReadableDecodingErrorProtocol)?.readableDescription { + errorObject.messageToLog = humanReadableMessage + } defaultHandleActionError(errorObject, additionalData: additionalData) } } @@ -176,7 +182,7 @@ public protocol MVMCoreJSONActionHandlerProtocol: MVMCoreActionHandlerProtocol { } catch { let actionType = json?.optionalStringForKey(KeyActionType) switch error { - case ModelRegistry.Error.decoderError, is DecodingError: + case is ModelRegistry.Error, is DecodingError: MVMCoreLoggingHandler.shared()?.logCoreEvent(.actionFailedToDecode(pageType: pageType(from: delegateObject), error: error)) logActionError(error, actionType, additionalData, delegateObject) case ModelRegistry.Error.decoderErrorModelNotMapped: diff --git a/MVMCore/MVMCore/Utility/ReadableDecodingErrors.swift b/MVMCore/MVMCore/Utility/ReadableDecodingErrors.swift new file mode 100644 index 0000000..4c9b991 --- /dev/null +++ b/MVMCore/MVMCore/Utility/ReadableDecodingErrors.swift @@ -0,0 +1,69 @@ +// +// ReadableDecodingErrors.swift +// MVMCore +// +// Created by Kyle Hedden on 10/5/23. +// Copyright © 2023 myverizon. All rights reserved. +// + +import Foundation + +public protocol HumanReadableDecodingErrorProtocol { + var readableDescription: String { get } +} + +extension JSONError: HumanReadableDecodingErrorProtocol { + public var readableDescription: String { + switch (self) { + case .other(let other): + if let other = other as? HumanReadableDecodingErrorProtocol { + return other.readableDescription + } + return description + default: + return description + } + } +} + +extension ModelRegistry.Error: HumanReadableDecodingErrorProtocol { + public var readableDescription: String { + switch (self) { + case .decoderErrorModelNotMapped(let identifier, let codingKey, let codingPath) where identifier != nil && codingKey != nil && codingPath != nil: + return "Model identifier \"\(identifier!)\" is not mapped for \"\(codingKey!.stringValue)\" @ \(codingPath!.map { return $0.stringValue })" + + case .decoderErrorObjectNotPresent(let codingKey, let codingPath): + return "Required model \"\(codingKey.stringValue)\" was not found @ \(codingPath.map { return $0.stringValue })" + + case .decoderOther(let message): + return "An issue occurred while decoding: \(message)" + + case .other(let message): + return "Registry error: \(message)" + + default: + return "Registry error: \((self as NSError).localizedFailureReason ?? self.localizedDescription)" + } + } +} + +extension DecodingError: HumanReadableDecodingErrorProtocol { + public var readableDescription: String { + switch (self) { + case .keyNotFound(let codingKey, let context): + return "Required key \(codingKey.stringValue) was not found @ \(context.codingPath.map { return $0.stringValue })" + + case .valueNotFound(_, let context): + return "Value not found @ \(context.codingPath.map { return $0.stringValue })" + + case .typeMismatch(_, let context): + return "Value type mismatch @ \(context.codingPath.map { return $0.stringValue })" + + case .dataCorrupted(let context): + return "Data corrupted @ \(context.codingPath.map { return $0.stringValue })" + + @unknown default: + return (self as NSError).localizedFailureReason ?? self.localizedDescription + } + } +} From 09ff3b64573171c7a1347236a302e8017f8e9ef1 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Thu, 25 Apr 2024 16:01:55 -0400 Subject: [PATCH 3/3] Digital PCT265 defect CXTDT-531317 - Updated error messaging --- MVMCore/MVMCore/Models/Model/ModelRegistry.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift index e3cbd1c..65e413d 100644 --- a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift +++ b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift @@ -211,7 +211,7 @@ public struct ModelRegistry { public static func getCodingKey(for type: T.Type) throws -> AnyCodingKey { guard let category = getCategory(for: type) else { - throw ModelRegistry.Error.decoderOther(message: "decodeModelsIfPresent only works for objects implementing the ModelProtocol protocol") + throw ModelRegistry.Error.decoderOther(message: "Category hasn’t been registered for the CodingKey for this type: \(String(describing: type.self))") } return AnyCodingKey(category.codingKey)