diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index ca0d5c9ad..0d9635a40 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -80,19 +80,19 @@ jobs: name: Upload ConsentViewController tests results with: path: /Users/runner/Library/Developer/Xcode/DerivedData/**/*.xcresult - # NativePMExampleApp: - # runs-on: macos-12 - # steps: - # - uses: actions/checkout@v2 - # - name: Select Xcode version 14.0.1 - # run: sudo xcode-select -s '/Applications/Xcode_14.0.1.app/Contents/Developer' - # - name: ConsentViewController testing -> iPhone 14 Pro (iOS 16.0) - # run: xcodebuild test -scheme NativePMExampleApp -workspace ConsentViewController.xcworkspace -destination 'platform=tvOS Simulator,name=Apple TV,OS=16.1' - # - uses: actions/upload-artifact@v2 - # if: failure() - # name: Upload NativePMExampleApp tests results - # with: - # path: /Users/runner/Library/Developer/Xcode/DerivedData/**/*.xcresult + NativePMExampleApp: + runs-on: macos-12 + steps: + - uses: actions/checkout@v2 + - name: Select Xcode version 14.0.1 + run: sudo xcode-select -s '/Applications/Xcode_14.0.1.app/Contents/Developer' + - name: ConsentViewController testing -> Apple TV (tvOS 16.1) + run: xcodebuild test -scheme NativePMExampleApp -workspace ConsentViewController.xcworkspace -destination 'platform=tvOS Simulator,name=Apple TV,OS=16.1' + - uses: actions/upload-artifact@v2 + if: failure() + name: Upload NativePMExampleApp tests results + with: + path: /Users/runner/Library/Developer/Xcode/DerivedData/**/*.xcresult # MetaApp: # runs-on: macos-12 # steps: diff --git a/ConsentViewController/Classes/Constants.swift b/ConsentViewController/Classes/Constants.swift index fb4f701ef..078881712 100644 --- a/ConsentViewController/Classes/Constants.swift +++ b/ConsentViewController/Classes/Constants.swift @@ -22,8 +22,8 @@ struct Constants { static let additionalData: String = "scriptType=ios&scriptVersion=\(SPConsentManager.VERSION)" static let SP_ROOT = URL(string: prod ? "https://cdn.privacy-mgmt.com/" : "https://preprod-cdn.privacy-mgmt.com/")! static let WRAPPER_API = URL(string: "./wrapper/?env=\(envParam)", relativeTo: SP_ROOT)! - static let GDPR_MESSAGE_URL = URL(string: "./v2/message/gdpr?\(additionalData)", relativeTo: WRAPPER_API)! - static let CCPA_MESSAGE_URL = URL(string: "./v2/message/ccpa?\(additionalData)", relativeTo: WRAPPER_API)! + static let GDPR_MESSAGE_URL = URL(string: "./v2/message/v2/gdpr?\(additionalData)", relativeTo: WRAPPER_API)! + static let CCPA_MESSAGE_URL = URL(string: "./v2/message/v2/ccpa?\(additionalData)", relativeTo: WRAPPER_API)! static let ERROR_METRIS_URL = URL(string: "./metrics/v1/custom-metrics?\(additionalData)", relativeTo: WRAPPER_API)! static let GDPR_CONSENT_URL = URL(string: "./v2/messages/choice/gdpr/?\(additionalData)", relativeTo: WRAPPER_API)! static let CCPA_CONSENT_URL = URL(string: "./v2/messages/choice/ccpa/?\(additionalData)", relativeTo: WRAPPER_API)! diff --git a/ConsentViewController/Classes/SourcePointClient/ChoiceRequests.swift b/ConsentViewController/Classes/SourcePointClient/ChoiceRequests.swift index 2f5c9a022..4228ef1f7 100644 --- a/ConsentViewController/Classes/SourcePointClient/ChoiceRequests.swift +++ b/ConsentViewController/Classes/SourcePointClient/ChoiceRequests.swift @@ -16,7 +16,7 @@ struct GDPRChoiceBody: Encodable, Equatable { let sampleRate: Float? let idfaStatus: SPIDFAStatus? let granularStatus: ConsentStatus.GranularStatus? - let includeData = IncludeData.dictionary + let includeData = IncludeData() } struct CCPAChoiceBody: Encodable, Equatable { @@ -26,5 +26,5 @@ struct CCPAChoiceBody: Encodable, Equatable { let sendPVData: Bool let propertyId: Int let sampleRate: Float? - let includeData = IncludeData.dictionary + let includeData = IncludeData() } diff --git a/ConsentViewController/Classes/SourcePointClient/ConsentRequestResponse.swift b/ConsentViewController/Classes/SourcePointClient/ConsentRequestResponse.swift index 457706fc3..11009d88d 100644 --- a/ConsentViewController/Classes/SourcePointClient/ConsentRequestResponse.swift +++ b/ConsentViewController/Classes/SourcePointClient/ConsentRequestResponse.swift @@ -14,7 +14,7 @@ struct GDPRConsentRequest: Encodable, Equatable { let pmSaveAndExitVariables: SPJson? let pubData: SPPublisherData let requestUUID: UUID - let includeData = IncludeData.dictionary + let includeData = IncludeData() } struct CCPAConsentRequest: Encodable, Equatable { @@ -23,7 +23,7 @@ struct CCPAConsentRequest: Encodable, Equatable { let pubData: SPPublisherData let pmSaveAndExitVariables: SPJson? let requestUUID: UUID - let includeData = IncludeData.dictionary + let includeData = IncludeData() } struct ConsentResponse: Decodable & Equatable { diff --git a/ConsentViewController/Classes/SourcePointClient/IncludeData.swift b/ConsentViewController/Classes/SourcePointClient/IncludeData.swift index 2e54c7aa7..f64dc561c 100644 --- a/ConsentViewController/Classes/SourcePointClient/IncludeData.swift +++ b/ConsentViewController/Classes/SourcePointClient/IncludeData.swift @@ -5,14 +5,16 @@ // Created by Andre Herculano on 18.04.23. // +// swiftlint:disable line_length + import Foundation -struct IncludeData { - static let dictionary = [ - "localState": ["type": "RecordString"], - "TCData": ["type": "RecordString"], - "webConsentPayload": ["type": "string"] - ] +struct IncludeData: Encodable, Equatable { + static let string = "{\"TCData\":{\"type\":\"RecordString\"},\"webConsentPayload\":{\"type\":\"string\"},\"localState\":{\"type\":\"RecordString\"},\"categories\":true,\"translateMessage\":true}" - static let string = "{\"TCData\":{\"type\":\"RecordString\"},\"webConsentPayload\":{\"type\":\"string\"},\"localState\":{\"type\":\"RecordString\"}}" + let localState = ["type": "RecordString"] + let TCData = ["type": "RecordString"] + let webConsentPayload = ["type": "string"] + let categories = true + let translateMessage = true } diff --git a/ConsentViewController/Classes/SourcePointClient/MessageRequest.swift b/ConsentViewController/Classes/SourcePointClient/MessageRequest.swift index 4316771c2..173e825c1 100644 --- a/ConsentViewController/Classes/SourcePointClient/MessageRequest.swift +++ b/ConsentViewController/Classes/SourcePointClient/MessageRequest.swift @@ -43,5 +43,5 @@ struct MessageRequest: Equatable, Encodable { let consentLanguage: SPMessageLanguage let campaigns: CampaignsRequest let pubData: SPPublisherData - let includeData = IncludeData.dictionary + let includeData = IncludeData() } diff --git a/ConsentViewController/Classes/SourcePointClient/MessagesRequest.swift b/ConsentViewController/Classes/SourcePointClient/MessagesRequest.swift index 83e9b85bc..a790fca3f 100644 --- a/ConsentViewController/Classes/SourcePointClient/MessagesRequest.swift +++ b/ConsentViewController/Classes/SourcePointClient/MessagesRequest.swift @@ -39,7 +39,7 @@ struct MessagesRequest: QueryParamEncodable { let hasCSP = true let campaignEnv: SPCampaignEnv? let idfaStatus: SPIDFAStatus? - let includeData = IncludeData.string + let includeData = IncludeData() } struct MetaData: QueryParamEncodable { diff --git a/ConsentViewController/Classes/Views/tvOS/NativePrivacyManager/Common/SPPMHeader.swift b/ConsentViewController/Classes/Views/tvOS/NativePrivacyManager/Common/SPPMHeader.swift index d9b4d89eb..593ab988d 100644 --- a/ConsentViewController/Classes/Views/tvOS/NativePrivacyManager/Common/SPPMHeader.swift +++ b/ConsentViewController/Classes/Views/tvOS/NativePrivacyManager/Common/SPPMHeader.swift @@ -43,6 +43,7 @@ class SPPMHeader: UIView { var spTitleText: SPNativeText? { didSet { titleLabel.setup(from: spTitleText) + titleLabel.text = titleLabel.text?.trimmingCharacters(in: .newlines) } } @@ -82,7 +83,9 @@ class SPPMHeader: UIView { let nib = UINib(nibName: "SPPMHeader", bundle: Bundle.framework) nib.instantiate(withOwner: self, options: nil) contentView.frame = bounds + titleLabel.accessibilityIdentifier = "Header Title" titleLabel.isAccessibilityElement = true + backButton.accessibilityIdentifier = "Back Button" backButton.isAccessibilityElement = true addSubview(contentView) } diff --git a/ConsentViewController/Classes/Views/tvOS/NativePrivacyManager/GDPR/SPGDPRNativePrivacyManagerViewController.swift b/ConsentViewController/Classes/Views/tvOS/NativePrivacyManager/GDPR/SPGDPRNativePrivacyManagerViewController.swift index c5559f748..f06c6b193 100644 --- a/ConsentViewController/Classes/Views/tvOS/NativePrivacyManager/GDPR/SPGDPRNativePrivacyManagerViewController.swift +++ b/ConsentViewController/Classes/Views/tvOS/NativePrivacyManager/GDPR/SPGDPRNativePrivacyManagerViewController.swift @@ -42,6 +42,7 @@ protocol SPNativePrivacyManagerHome { override func viewDidLoad() { super.viewDidLoad() + view.accessibilityIdentifier = "GDPR Message" setHeader() loadTextView(forComponentId: "PublisherDescription", textView: descriptionTextView, bounces: false) descriptionTextView.flashScrollIndicators() @@ -53,6 +54,7 @@ protocol SPNativePrivacyManagerHome { loadButton(forComponentId: "NavPrivacyPolicyButton", button: privacyPolicyButton) loadImage(forComponentId: "LogoImage", imageView: logoImageView) setFocusGuidesForButtons() + categoryTableView.accessibilityIdentifier = "Categories List" categoryTableView.allowsSelection = false categoryTableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier) categoryTableView.delegate = self diff --git a/Example/ConsentViewController_ExampleTests/SPClientCoordinator/SourcePointClient/UnmockedSourcepointClientSpec.swift b/Example/ConsentViewController_ExampleTests/SPClientCoordinator/SourcePointClient/UnmockedSourcepointClientSpec.swift index f507bbbf8..9c2480c9a 100644 --- a/Example/ConsentViewController_ExampleTests/SPClientCoordinator/SourcePointClient/UnmockedSourcepointClientSpec.swift +++ b/Example/ConsentViewController_ExampleTests/SPClientCoordinator/SourcePointClient/UnmockedSourcepointClientSpec.swift @@ -51,7 +51,7 @@ class UnmockedSourcepointClientSpec: QuickSpec { it("should contain all query params") { let url = client.consentStatusURLWithParams(propertyId: propertyId, metadata: emptyMetaData, authId: nil) - let paramsRaw = "env=\(Constants.Urls.envParam)&scriptType=ios&scriptVersion=\(SPConsentManager.VERSION)&hasCsp=true&includeData={\"TCData\":{\"type\":\"RecordString\"},\"webConsentPayload\":{\"type\":\"string\"},\"localState\":{\"type\":\"RecordString\"}}&metadata={}&propertyId=17801&withSiteActions=false" + let paramsRaw = "env=\(Constants.Urls.envParam)&scriptType=ios&scriptVersion=\(SPConsentManager.VERSION)&hasCsp=true&includeData={\"TCData\":{\"type\":\"RecordString\"},\"webConsentPayload\":{\"type\":\"string\"},\"localState\":{\"type\":\"RecordString\"},\"categories\":true,\"translateMessage\":true}&metadata={}&propertyId=17801&withSiteActions=false" expect(url?.query) == paramsRaw.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) } } diff --git a/Example/NativePMExampleApp/AppDelegate.swift b/Example/NativePMExampleApp/AppDelegate.swift index 855c91c8f..d80603b52 100644 --- a/Example/NativePMExampleApp/AppDelegate.swift +++ b/Example/NativePMExampleApp/AppDelegate.swift @@ -22,6 +22,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } UserDefaults.standard.set(CommandLine.arguments.contains("-gdpr"), forKey: "app.campaigns.gdpr") UserDefaults.standard.set(CommandLine.arguments.contains("-ccpa"), forKey: "app.campaigns.ccpa") + let language = CommandLine.arguments + .first(where: { $0.starts(with: "-lang=")})? + .replacingOccurrences(of: "-lang=", with: "") + UserDefaults.standard.set(language, forKey: "app.lang") return true } diff --git a/Example/NativePMExampleApp/ViewController.swift b/Example/NativePMExampleApp/ViewController.swift index 5a0574211..74e96f788 100644 --- a/Example/NativePMExampleApp/ViewController.swift +++ b/Example/NativePMExampleApp/ViewController.swift @@ -27,10 +27,11 @@ class ViewController: UIViewController { lazy var consentManager: SPSDK = { SPConsentManager( accountId: 22, - propertyId: 21927, + propertyId: 17935, // swiftlint:disable:next force_try propertyName: try! SPPropertyName("appletv.demo"), campaigns: campaigns, + language: SPMessageLanguage(rawValue: UserDefaults.standard.string(forKey: "app.lang") ?? "")!, delegate: self ) }() @@ -50,11 +51,11 @@ class ViewController: UIViewController { } @IBAction func onGDPRTap(_ sender: Any) { - consentManager.loadGDPRPrivacyManager(withId: "713324") + consentManager.loadGDPRPrivacyManager(withId: "529561") } @IBAction func onCCPATap(_ sender: Any) { - consentManager.loadCCPAPrivacyManager(withId: "753814") + consentManager.loadCCPAPrivacyManager(withId: "753802") } } diff --git a/Example/NativePMExampleAppUITests/NativePMApp.swift b/Example/NativePMExampleAppUITests/NativePMApp.swift index 036d19ced..d861a5e82 100644 --- a/Example/NativePMExampleAppUITests/NativePMApp.swift +++ b/Example/NativePMExampleAppUITests/NativePMApp.swift @@ -8,11 +8,12 @@ import Nimble import XCTest +import ConsentViewController protocol App { func launch() func terminate() - func relaunch(clean: Bool, gdpr: Bool, ccpa: Bool) + func relaunch(clean: Bool, gdpr: Bool, ccpa: Bool, language: SPMessageLanguage) } extension XCUIApplication: App { @@ -22,12 +23,18 @@ extension XCUIApplication: App { launchArguments.removeAll { $0 == "-\(name)" } } - func relaunch(clean: Bool = false, gdpr: Bool = true, ccpa: Bool = true) { + func setArgument(_ name: String, _ value: String) { + launchArguments.removeAll { $0.starts(with: "-\(name)=") } + launchArguments.append("-\(name)=\(value)") + } + + func relaunch(clean: Bool = false, gdpr: Bool = true, ccpa: Bool = true, language: SPMessageLanguage = .BrowserDefault) { UserDefaults.standard.synchronize() self.terminate() setArgument("cleanAppsData", clean) setArgument("gdpr", gdpr) setArgument("ccpa", ccpa) + setArgument("lang", language.rawValue) launch() } } @@ -35,14 +42,15 @@ extension XCUIApplication: App { class NativePMApp: XCUIApplication { class GDPRMessage: XCUIApplication { var container: XCUIElement { - windows.containing(.staticText, identifier: "GDPR Message").firstMatch + otherElements["GDPR Message"] } - + var headerTitle: XCUIElement { container.staticTexts["Header Title"] } var acceptAllButton: XCUIElement { container.buttons["Accept"].firstMatch } - var rejectAllButton: XCUIElement { container.buttons["Reject All"].firstMatch } - var categoriesDetailsButton: XCUIElement { container.buttons["Manage Preferences"].firstMatch } - var vendorsDetailsButton: XCUIElement { container.buttons["Our Partners"].firstMatch } - var privacyPolicyButton: XCUIElement { container.buttons["Privacy Policy"].firstMatch } + var rejectAllButton: XCUIElement { container.buttons["Reject All"] } + var categoriesDetailsButton: XCUIElement { container.buttons["Manage Preferences"] } + var vendorsDetailsButton: XCUIElement { container.buttons["Our Partners"] } + var privacyPolicyButton: XCUIElement { container.buttons["Privacy Policy"] } + var categoriesList: XCUIElement { container.tables["Categories List"] } } class CCPAMessage: XCUIApplication { @@ -53,12 +61,12 @@ class NativePMApp: XCUIApplication { var doNotSellMyInfoButton: XCUIElement { container.cells.containing(.staticText, identifier: "Do Not Sell My Personal Data").firstMatch } - var acceptAllButton: XCUIElement { container.buttons["Accept"].firstMatch } - var rejectAllButton: XCUIElement { container.buttons["Reject All"].firstMatch } - var saveAndExitButton: XCUIElement { container.buttons["Save and Exit"].firstMatch } - var categoriesDetailsButton: XCUIElement { container.buttons["Manage Preferences"].firstMatch } - var vendorsDetailsButton: XCUIElement { container.buttons["Our Partners"].firstMatch } - var privacyPolicyButton: XCUIElement { container.buttons["Privacy Policy"].firstMatch } + var acceptAllButton: XCUIElement { container.buttons["Accept"] } + var rejectAllButton: XCUIElement { container.buttons["Reject All"] } + var saveAndExitButton: XCUIElement { container.buttons["Save and Exit"] } + var categoriesDetailsButton: XCUIElement { container.buttons["Manage Preferences"] } + var vendorsDetailsButton: XCUIElement { container.buttons["Our Partners"] } + var privacyPolicyButton: XCUIElement { container.buttons["Privacy Policy"] } } let gdprMessage = GDPRMessage() @@ -109,67 +117,67 @@ class NativePMApp: XCUIApplication { } var acceptButton: XCUIElement { - buttons["Accept"].firstMatch + buttons["Accept"] } var acceptAllButton: XCUIElement { - buttons["Accept All"].firstMatch + buttons["Accept All"] } var managePreferencesButton: XCUIElement { - buttons["Manage Preferences"].firstMatch + buttons["Manage Preferences"] } var rejectAllButton: XCUIElement { - buttons["Reject All"].firstMatch + buttons["Reject All"] } var saveAndExitButton: XCUIElement { - buttons["Save and Exit"].firstMatch + buttons["Save and Exit"] } var saveAndExitInternalButton: XCUIElement { - buttons["Save & Exit"].firstMatch + buttons["Save & Exit"] } var homeButton: XCUIElement { - buttons["Home"].firstMatch + buttons["Home"] } var backButton: XCUIElement { - buttons["Back"].firstMatch + buttons["Back"] } var onButton: XCUIElement { - buttons["On"].firstMatch + buttons["On"] } var offButton: XCUIElement { - buttons["Off"].firstMatch + buttons["Off"] } var privacyPolicyButton: XCUIElement { - buttons["Privacy Policy"].firstMatch + buttons["Privacy Policy"] } var consentButton: XCUIElement { - buttons["CONSENT"].firstMatch + buttons["CONSENT"] } var legitimateInterestButton: XCUIElement { - buttons["LEGITIMATE INTEREST"].firstMatch + buttons["LEGITIMATE INTEREST"] } var ourPartnersButton: XCUIElement { - buttons["Our Partners"].firstMatch + buttons["Our Partners"] } var gdprPrivacyManagerButton: XCUIElement { - buttons["GDPR Privacy Manager"].firstMatch + buttons["GDPR Privacy Manager"] } var ccpaPrivacyManagerButton: XCUIElement { - buttons["CCPA Privacy Manager"].firstMatch + buttons["CCPA Privacy Manager"] } var sdkStatusLabel: XCUIElement { @@ -181,8 +189,6 @@ class NativePMApp: XCUIApplication { extension NativePMApp { func pressDoNotSellButton() { remote.press(.right) -// expectedMessageShowUP(element: doNotSellMyPersonalInformation) -// previous line is commented since appletv.demo "Do Not Sell" button has blank text remote.press(.select) remote.press(.left) } diff --git a/Example/NativePMExampleAppUITests/NativePMUITests.swift b/Example/NativePMExampleAppUITests/NativePMUITests.swift index d566c1023..7c126537a 100644 --- a/Example/NativePMExampleAppUITests/NativePMUITests.swift +++ b/Example/NativePMExampleAppUITests/NativePMUITests.swift @@ -54,11 +54,9 @@ class NativePMUITests: QuickSpec { Nimble.AsyncDefaults.pollInterval = .milliseconds(100) } - beforeEach { + it("Accept all through CCPA & GDPR Privacy Manager") { self.app.relaunch(clean: true) - } - it("Accept all through CCPA & GDPR Privacy Manager") { // Accept all GDPR Message self.waitFor(self.app.gdprMessage) self.app.gdprMessage.acceptAllButton.remotePress() @@ -91,6 +89,8 @@ class NativePMUITests: QuickSpec { } it("Reject all through CCPA & GDPR Privacy Manager") { + self.app.relaunch(clean: true) + // Accept all GDPR Message self.waitFor(self.app.gdprMessage) self.app.gdprMessage.rejectAllButton.remotePress() @@ -152,6 +152,16 @@ class NativePMUITests: QuickSpec { expect(self.app.ccpaMessage.doNotSellMyInfoButton.staticTexts["OFF"]).toEventually(showUp()) } + it("Handles message translation") { + self.app.relaunch(clean: true, language: .Spanish) + + // Message content is translated + expect(self.app.gdprMessage.headerTitle).toEventually(containText("Mensage GDPR")) + + // as well as categories + expect(self.app.gdprMessage.categoriesList.staticTexts["Almacenar o acceder a informaciĆ³n en un dispositivo"].exists).toEventually(beTrue()) + } + // it("Save and Exit through CCPA & GDPR Privacy Manager") { // self.app.gdprPrivacyManagerButton.remotePress() // self.app.acceptButton.expectToHaveFocus() diff --git a/Example/Pods/Target Support Files/ConsentViewController-tvOS/ConsentViewController-tvOS-Info.plist b/Example/Pods/Target Support Files/ConsentViewController-tvOS/ConsentViewController-tvOS-Info.plist index 75c0049a3..ef9653711 100644 --- a/Example/Pods/Target Support Files/ConsentViewController-tvOS/ConsentViewController-tvOS-Info.plist +++ b/Example/Pods/Target Support Files/ConsentViewController-tvOS/ConsentViewController-tvOS-Info.plist @@ -2,27 +2,27 @@ - CFBundleDevelopmentRegion - ${PODS_DEVELOPMENT_LANGUAGE} - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - ${PRODUCT_BUNDLE_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - FMWK - CFBundleShortVersionString - 7.0.3 - CFBundleSignature - ???? - CFBundleVersion - ${CURRENT_PROJECT_VERSION} - NSPrincipalClass - - SPEnv - prod + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 7.0.3 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + SPEnv + prod