@chipmobilesdk/rn-ads 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -97,9 +97,27 @@ export function createTestClock(startMs = 1_000_000): TestClock {
97
97
  export type FakeConsentCall =
98
98
  | { readonly kind: 'requestInfoUpdate'; readonly options: EngineConsentOptions }
99
99
  | { readonly kind: 'showFormIfRequired' }
100
+ | { readonly kind: 'showPrivacyOptionsForm' }
100
101
  | { readonly kind: 'getInfo' }
101
102
  | { readonly kind: 'reset' };
102
103
 
104
+ /**
105
+ * A privacy options form the test is holding open (0.4.0).
106
+ *
107
+ * Settle it whenever the test chooses, which is what lets `busy`, a second
108
+ * call, a consent update, and `dispose()` all be exercised *while* the form is
109
+ * on screen — in any order, rather than only the one a resolved promise allows.
110
+ */
111
+ export interface HeldPrivacyOptionsForm {
112
+ /**
113
+ * The user closes the form. `info` is what the provider reports afterwards,
114
+ * merged over the current information; omit it for a user who changed nothing.
115
+ */
116
+ close(info?: Partial<EngineConsentInfo>): void;
117
+ /** The form fails while open. */
118
+ fail(cause?: unknown): void;
119
+ }
120
+
103
121
  export type FakeEngineCall =
104
122
  | { readonly kind: 'initialize'; readonly privacy: EnginePrivacy }
105
123
  | {
@@ -133,6 +151,7 @@ const DEFAULT_CONSENT: EngineConsentInfo = {
133
151
  status: 'not_required',
134
152
  canRequestAds: true,
135
153
  isFormAvailable: false,
154
+ privacyOptions: 'not_required',
136
155
  };
137
156
 
138
157
  export interface FakeAdsEngine extends AdsEngine {
@@ -166,6 +185,19 @@ export interface FakeAdsEngine extends AdsEngine {
166
185
  failConsentRequest(cause?: unknown): void;
167
186
  /** Makes `showFormIfRequired` reject — dismissal is not consent (FR-106). */
168
187
  failConsentForm(cause?: unknown): void;
188
+
189
+ /**
190
+ * What the privacy options form reports when the user closes it, merged over
191
+ * the current information. Unset, the form closes with nothing changed — the
192
+ * same as a user who opens it and backs out.
193
+ */
194
+ setPrivacyOptionsFormResult(info: Partial<EngineConsentInfo>): void;
195
+ /** Makes `showPrivacyOptionsForm` reject — a failure is never consent (FR-106). */
196
+ failPrivacyOptionsForm(cause?: unknown): void;
197
+ /** Holds the next privacy options form open until the test settles it. */
198
+ holdPrivacyOptionsForm(): HeldPrivacyOptionsForm;
199
+ /** Makes `getInfo` reject, for the case where even the re-read after a failed form fails. */
200
+ failConsentInfoRead(cause?: unknown): void;
169
201
  }
170
202
 
171
203
  export function createFakeAdsEngine(options: FakeEngineOptions = {}): FakeAdsEngine {
@@ -175,6 +207,11 @@ export function createFakeAdsEngine(options: FakeEngineOptions = {}): FakeAdsEng
175
207
  let consentInfo: EngineConsentInfo = { ...DEFAULT_CONSENT, ...options.consentInfo };
176
208
  let consentRequestFailure: unknown;
177
209
  let consentFormFailure: unknown;
210
+ let privacyFormFailure: unknown;
211
+ let privacyFormResult: Partial<EngineConsentInfo> = {};
212
+ let consentReadFailure: unknown;
213
+ /** Set by `holdPrivacyOptionsForm`; consumed by the next form. */
214
+ let heldForm: Promise<Partial<EngineConsentInfo>> | null = null;
178
215
 
179
216
  const consent: ConsentPort = {
180
217
  async requestInfoUpdate(consentOptions) {
@@ -192,18 +229,49 @@ export function createFakeAdsEngine(options: FakeEngineOptions = {}): FakeAdsEng
192
229
  // A presented form that the user completes moves the status on. The
193
230
  // fake only does this when a form was actually required, mirroring the
194
231
  // provider: showing nothing cannot change an answer.
232
+ // A region that required a form is one that requires a way back into
233
+ // it, which is what the provider reports once consent is obtained.
195
234
  if (consentInfo.status === 'required' && consentInfo.isFormAvailable) {
196
- consentInfo = { status: 'obtained', canRequestAds: true, isFormAvailable: false };
235
+ consentInfo = {
236
+ status: 'obtained',
237
+ canRequestAds: true,
238
+ isFormAvailable: false,
239
+ privacyOptions: 'required',
240
+ };
241
+ }
242
+ return consentInfo;
243
+ },
244
+ async showPrivacyOptionsForm() {
245
+ consentCalls.push({ kind: 'showPrivacyOptionsForm' });
246
+ const held = heldForm;
247
+ heldForm = null;
248
+ if (held) {
249
+ // Rejects if the test calls `fail`, which is exactly the provider's
250
+ // failure path; resolves with what the user left behind otherwise.
251
+ consentInfo = { ...consentInfo, ...(await held) };
252
+ return consentInfo;
197
253
  }
254
+ if (privacyFormFailure !== undefined) {
255
+ throw privacyFormFailure;
256
+ }
257
+ consentInfo = { ...consentInfo, ...privacyFormResult };
198
258
  return consentInfo;
199
259
  },
200
260
  async getInfo() {
201
261
  consentCalls.push({ kind: 'getInfo' });
262
+ if (consentReadFailure !== undefined) {
263
+ throw consentReadFailure;
264
+ }
202
265
  return consentInfo;
203
266
  },
204
267
  reset() {
205
268
  consentCalls.push({ kind: 'reset' });
206
- consentInfo = { status: 'unknown', canRequestAds: false, isFormAvailable: true };
269
+ consentInfo = {
270
+ status: 'unknown',
271
+ canRequestAds: false,
272
+ isFormAvailable: true,
273
+ privacyOptions: 'unknown',
274
+ };
207
275
  },
208
276
  };
209
277
  const listeners = new Map<string, Set<(event: EngineAdEvent) => void>>();
@@ -238,6 +306,37 @@ export function createFakeAdsEngine(options: FakeEngineOptions = {}): FakeAdsEng
238
306
  consentFormFailure = cause;
239
307
  },
240
308
 
309
+ setPrivacyOptionsFormResult(info) {
310
+ privacyFormResult = info;
311
+ },
312
+
313
+ failPrivacyOptionsForm(cause = new Error('privacy options form failed')) {
314
+ privacyFormFailure = cause;
315
+ },
316
+
317
+ holdPrivacyOptionsForm() {
318
+ let settle!: {
319
+ resolve: (info: Partial<EngineConsentInfo>) => void;
320
+ reject: (cause: unknown) => void;
321
+ };
322
+ const promise = new Promise<Partial<EngineConsentInfo>>((resolve, reject) => {
323
+ settle = { resolve, reject };
324
+ });
325
+ heldForm = promise;
326
+ return {
327
+ close(info = {}) {
328
+ settle.resolve(info);
329
+ },
330
+ fail(cause = new Error('privacy options form failed')) {
331
+ settle.reject(cause);
332
+ },
333
+ };
334
+ },
335
+
336
+ failConsentInfoRead(cause = new Error('consent information read failed')) {
337
+ consentReadFailure = cause;
338
+ },
339
+
241
340
  isAvailable() {
242
341
  return options.available !== false;
243
342
  },