diff --git a/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt b/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt index fa85c01..8e55f1e 100644 --- a/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt +++ b/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModule.kt @@ -85,6 +85,16 @@ internal class RNUsercentricsModule( promise.resolve(usercentricsProxy.instance.getABTestingVariant()) } + @ReactMethod + override fun getDpsMetadata(templateId: String, promise: Promise) { + val metadata = usercentricsProxy.instance.getDpsMetadata(templateId) + if (metadata == null) { + promise.resolve(null) + } else { + promise.resolve(metadata.toWritableMap()) + } + } + @ReactMethod override fun getConsents(promise: Promise) { promise.resolve(usercentricsProxy.instance.getConsents().toWritableArray()) diff --git a/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt b/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt index cbc258a..6262d34 100644 --- a/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt +++ b/android/src/main/java/com/usercentrics/reactnative/RNUsercentricsModuleSpec.kt @@ -60,6 +60,9 @@ abstract class RNUsercentricsModuleSpec internal constructor(context: ReactAppli @ReactMethod abstract fun getABTestingVariant(promise: Promise) + @ReactMethod + abstract fun getDpsMetadata(templateId: String, promise: Promise) + @ReactMethod abstract fun setCMPId(id: Double) diff --git a/example/ios/exampleTests/Fake/FakeUsercentricsManager.swift b/example/ios/exampleTests/Fake/FakeUsercentricsManager.swift index 65ffb02..7653ae3 100644 --- a/example/ios/exampleTests/Fake/FakeUsercentricsManager.swift +++ b/example/ios/exampleTests/Fake/FakeUsercentricsManager.swift @@ -118,6 +118,13 @@ final class FakeUsercentricsManager: UsercentricsManager { callback(getTCFDataResponse!) } + var getDpsMetadataResponse: [String: Any]? + var getDpsMetadataTemplateId: String? + func getDpsMetadata(templateId: String) -> [String: Any]? { + getDpsMetadataTemplateId = templateId + return getDpsMetadataResponse + } + var getAdditionalConsentModeDataResponse: AdditionalConsentModeData? func getAdditionalConsentModeData() -> AdditionalConsentModeData { return getAdditionalConsentModeDataResponse! diff --git a/example/ios/exampleTests/RNUsercentricsModuleTests.swift b/example/ios/exampleTests/RNUsercentricsModuleTests.swift index 60adf32..307a909 100644 --- a/example/ios/exampleTests/RNUsercentricsModuleTests.swift +++ b/example/ios/exampleTests/RNUsercentricsModuleTests.swift @@ -563,6 +563,43 @@ class RNUsercentricsModuleTests: XCTestCase { } } + func testGetDpsMetadataWithValidData() { + fakeUsercentrics.getDpsMetadataResponse = ["partner": "appsflyer", "source": "campaign_1"] + module.getDpsMetadata("template123") { result in + guard let result = result as? NSDictionary else { + XCTFail() + return + } + XCTAssertEqual("appsflyer", result["partner"] as! String) + XCTAssertEqual("campaign_1", result["source"] as! String) + } reject: { _, _, _ in + XCTFail("Should not go here") + } + XCTAssertEqual("template123", fakeUsercentrics.getDpsMetadataTemplateId) + } + + func testGetDpsMetadataWhenNull() { + fakeUsercentrics.getDpsMetadataResponse = nil + module.getDpsMetadata("nonExistent") { result in + XCTAssertNil(result) + } reject: { _, _, _ in + XCTFail("Should not go here") + } + } + + func testGetDpsMetadataWithEmptyMap() { + fakeUsercentrics.getDpsMetadataResponse = [:] + module.getDpsMetadata("template123") { result in + guard let result = result as? NSDictionary else { + XCTFail() + return + } + XCTAssertEqual(0, result.count) + } reject: { _, _, _ in + XCTFail("Should not go here") + } + } + func testGetAdditionalConsentModeData() { let expected = AdditionalConsentModeData(acString: "2~43.46.55~dv.", adTechProviders: [AdTechProvider(id: 43, name: "AdPredictive", privacyPolicyUrl: "https://adpredictive.com/privacy", consent: true)]) diff --git a/ios/Manager/UsercentricsManager.swift b/ios/Manager/UsercentricsManager.swift index bd283d4..d109560 100644 --- a/ios/Manager/UsercentricsManager.swift +++ b/ios/Manager/UsercentricsManager.swift @@ -24,6 +24,7 @@ public protocol UsercentricsManager { func setGPPConsent(sectionName: String, fieldName: String, value: Any) func getTCFData(callback: @escaping (TCFData) -> Void) func getABTestingVariant() -> String? + func getDpsMetadata(templateId: String) -> [String: Any]? func getAdditionalConsentModeData() -> AdditionalConsentModeData func onGppSectionChange(callback: @escaping (GppSectionChangePayload) -> Void) -> UsercentricsDisposableEvent @@ -116,6 +117,10 @@ final class UsercentricsManagerImplementation: UsercentricsManager { UsercentricsCore.shared.getTCFData(callback: callback) } + func getDpsMetadata(templateId: String) -> [String: Any]? { + return UsercentricsCore.shared.getDpsMetadata(templateId: templateId) + } + func getAdditionalConsentModeData() -> AdditionalConsentModeData { return UsercentricsCore.shared.getAdditionalConsentModeData() } diff --git a/ios/RNUsercentricsModule.swift b/ios/RNUsercentricsModule.swift index 4fa537a..96ef537 100644 --- a/ios/RNUsercentricsModule.swift +++ b/ios/RNUsercentricsModule.swift @@ -159,6 +159,11 @@ class RNUsercentricsModule: RCTEventEmitter { resolve(usercentricsManager.getABTestingVariant()) } + @objc func getDpsMetadata(_ templateId: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { + let metadata = usercentricsManager.getDpsMetadata(templateId: templateId) + resolve(metadata as NSDictionary?) + } + @objc func getAdditionalConsentModeData(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { resolve(usercentricsManager.getAdditionalConsentModeData().toDictionary()) } diff --git a/ios/RNUsercentricsModuleSpec.h b/ios/RNUsercentricsModuleSpec.h index 2e1e56f..b3cde89 100644 --- a/ios/RNUsercentricsModuleSpec.h +++ b/ios/RNUsercentricsModuleSpec.h @@ -36,6 +36,10 @@ NS_ASSUME_NONNULL_BEGIN - (void)getCMPData:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)getDpsMetadata:(NSString *)templateId + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject; + - (void)getAdditionalConsentModeData:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; diff --git a/sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift b/sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift index c921a1d..af72df5 100644 --- a/sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift +++ b/sample/ios/sampleTests/Fake/FakeUsercentricsManager.swift @@ -119,6 +119,13 @@ final class FakeUsercentricsManager: UsercentricsManager { callback(getTCFDataResponse!) } + var getDpsMetadataResponse: [String: Any]? + var getDpsMetadataTemplateId: String? + func getDpsMetadata(templateId: String) -> [String: Any]? { + getDpsMetadataTemplateId = templateId + return getDpsMetadataResponse + } + var getAdditionalConsentModeDataResponse: AdditionalConsentModeData? func getAdditionalConsentModeData() -> AdditionalConsentModeData { return getAdditionalConsentModeDataResponse! diff --git a/sample/ios/sampleTests/RNUsercentricsModuleTests.swift b/sample/ios/sampleTests/RNUsercentricsModuleTests.swift index 6009e96..8e36811 100644 --- a/sample/ios/sampleTests/RNUsercentricsModuleTests.swift +++ b/sample/ios/sampleTests/RNUsercentricsModuleTests.swift @@ -564,6 +564,43 @@ class RNUsercentricsModuleTests: XCTestCase { } } + func testGetDpsMetadataWithValidData() { + fakeUsercentrics.getDpsMetadataResponse = ["partner": "appsflyer", "source": "campaign_1"] + module.getDpsMetadata("template123") { result in + guard let result = result as? NSDictionary else { + XCTFail() + return + } + XCTAssertEqual("appsflyer", result["partner"] as! String) + XCTAssertEqual("campaign_1", result["source"] as! String) + } reject: { _, _, _ in + XCTFail("Should not go here") + } + XCTAssertEqual("template123", fakeUsercentrics.getDpsMetadataTemplateId) + } + + func testGetDpsMetadataWhenNull() { + fakeUsercentrics.getDpsMetadataResponse = nil + module.getDpsMetadata("nonExistent") { result in + XCTAssertNil(result) + } reject: { _, _, _ in + XCTFail("Should not go here") + } + } + + func testGetDpsMetadataWithEmptyMap() { + fakeUsercentrics.getDpsMetadataResponse = [:] + module.getDpsMetadata("template123") { result in + guard let result = result as? NSDictionary else { + XCTFail() + return + } + XCTAssertEqual(0, result.count) + } reject: { _, _, _ in + XCTFail("Should not go here") + } + } + func testGetAdditionalConsentModeData() { let expected = AdditionalConsentModeData(acString: "2~43.46.55~dv.", adTechProviders: [AdTechProvider(id: 43, name: "AdPredictive", privacyPolicyUrl: "https://adpredictive.com/privacy", consent: true)]) diff --git a/src/NativeUsercentrics.ts b/src/NativeUsercentrics.ts index c35acbb..171ba66 100644 --- a/src/NativeUsercentrics.ts +++ b/src/NativeUsercentrics.ts @@ -40,6 +40,7 @@ export interface Spec extends TurboModule { getGPPData(): Promise; getGPPString(): Promise; getABTestingVariant(): Promise; + getDpsMetadata(templateId: string): Promise | null>; // Configuration Setters setCMPId(id: number): void; diff --git a/src/Usercentrics.tsx b/src/Usercentrics.tsx index cf5d03a..e870c3c 100644 --- a/src/Usercentrics.tsx +++ b/src/Usercentrics.tsx @@ -100,6 +100,11 @@ export const Usercentrics = { return RNUsercentricsModule.getAdditionalConsentModeData(); }, + getDpsMetadata: async (templateId: string): Promise | null> => { + await RNUsercentricsModule.isReady(); + return RNUsercentricsModule.getDpsMetadata(templateId); + }, + changeLanguage: async (language: string): Promise => { await RNUsercentricsModule.isReady(); return RNUsercentricsModule.changeLanguage(language); diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index 755d588..144c49d 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -61,6 +61,7 @@ jest.mock("react-native", () => { setGPPConsent: jest.fn(), track: jest.fn(), reset: jest.fn(), + getDpsMetadata: jest.fn(), clearUserSession: jest.fn(), addListener: jest.fn(), removeListeners: jest.fn() @@ -455,6 +456,37 @@ describe('Test Usercentrics Module', () => { expect(data).toStrictEqual(response) }) + test('testGetDpsMetadataWithValidData', async () => { + const metadata = { partner: "appsflyer", source: "campaign_1" }; + RNUsercentricsModule.getDpsMetadata.mockImplementationOnce( + (): Promise => Promise.resolve(metadata) + ) + + const data = await Usercentrics.getDpsMetadata("templateId123"); + expect(data).toStrictEqual(metadata); + + const call = RNUsercentricsModule.getDpsMetadata.mock.calls[0][0]; + expect(call).toBe("templateId123"); + }) + + test('testGetDpsMetadataWhenNull', async () => { + RNUsercentricsModule.getDpsMetadata.mockImplementationOnce( + (): Promise => Promise.resolve(null) + ) + + const data = await Usercentrics.getDpsMetadata("nonExistentId"); + expect(data).toBe(null); + }) + + test('testGetDpsMetadataWithEmptyObject', async () => { + RNUsercentricsModule.getDpsMetadata.mockImplementationOnce( + (): Promise => Promise.resolve({}) + ) + + const data = await Usercentrics.getDpsMetadata("templateId123"); + expect(data).toStrictEqual({}); + }) + test('testClearUserSession', async () => { const readyStatus = new UsercentricsReadyStatus( true, diff --git a/src/fabric/NativeUsercentricsModule.ts b/src/fabric/NativeUsercentricsModule.ts index 3eb0869..52aa87a 100644 --- a/src/fabric/NativeUsercentricsModule.ts +++ b/src/fabric/NativeUsercentricsModule.ts @@ -25,6 +25,7 @@ export interface Spec extends TurboModule { getGPPData(): Promise; getGPPString(): Promise; getABTestingVariant(): Promise; + getDpsMetadata(templateId: string): Promise; // Configuration Setters setCMPId(id: number): void;