@jskit-ai/google-rewarded-web 0.1.1
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.
- package/README.md +65 -0
- package/package.descriptor.mjs +66 -0
- package/package.json +11 -0
- package/src/client/components/GoogleRewardedGateHost.vue +184 -0
- package/src/client/composables/useGoogleRewardedRuntime.js +8 -0
- package/src/client/index.js +7 -0
- package/src/client/providers/GoogleRewardedClientProvider.js +59 -0
- package/src/client/runtime/googleRewardedRuntime.js +458 -0
- package/src/index.js +1 -0
- package/src/server/index.js +1 -0
- package/src/shared/index.js +1 -0
- package/test/runtime.test.js +563 -0
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import { createGoogleRewardedRuntime } from "../src/client/runtime/googleRewardedRuntime.js";
|
|
5
|
+
|
|
6
|
+
function waitForAsyncTurn() {
|
|
7
|
+
return new Promise((resolve) => {
|
|
8
|
+
setImmediate(resolve);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function createJsonResponse(data, status = 200) {
|
|
13
|
+
return {
|
|
14
|
+
ok: status >= 200 && status < 300,
|
|
15
|
+
status,
|
|
16
|
+
headers: {
|
|
17
|
+
get(name) {
|
|
18
|
+
return String(name || "").toLowerCase() === "content-type"
|
|
19
|
+
? "application/json"
|
|
20
|
+
: "";
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
async json() {
|
|
24
|
+
return data;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function createFetchStub({
|
|
30
|
+
currentResponse,
|
|
31
|
+
startResponse,
|
|
32
|
+
grantResponse,
|
|
33
|
+
closeResponse
|
|
34
|
+
} = {}) {
|
|
35
|
+
const calls = [];
|
|
36
|
+
|
|
37
|
+
async function fetchStub(url, options = {}) {
|
|
38
|
+
const method = String(options.method || "GET").toUpperCase();
|
|
39
|
+
const serializedBody = typeof options.body === "string" ? options.body : "";
|
|
40
|
+
const parsedBody = serializedBody ? JSON.parse(serializedBody) : null;
|
|
41
|
+
|
|
42
|
+
calls.push({
|
|
43
|
+
url: String(url),
|
|
44
|
+
method,
|
|
45
|
+
body: parsedBody
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
if (String(url) === "/api/session") {
|
|
49
|
+
return createJsonResponse({
|
|
50
|
+
csrfToken: "csrf-token"
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (String(url).includes("/google-rewarded/current")) {
|
|
55
|
+
return createJsonResponse(currentResponse);
|
|
56
|
+
}
|
|
57
|
+
if (String(url).includes("/google-rewarded/start")) {
|
|
58
|
+
return createJsonResponse(startResponse);
|
|
59
|
+
}
|
|
60
|
+
if (String(url).includes("/google-rewarded/grant")) {
|
|
61
|
+
return createJsonResponse(grantResponse);
|
|
62
|
+
}
|
|
63
|
+
if (String(url).includes("/google-rewarded/close")) {
|
|
64
|
+
return createJsonResponse(closeResponse);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
throw new Error(`Unexpected fetch call: ${method} ${String(url)}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
calls,
|
|
72
|
+
fetchStub
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function installBrowserGlobals({ mode = "grant" } = {}) {
|
|
77
|
+
const originalWindow = globalThis.window;
|
|
78
|
+
const originalDocument = globalThis.document;
|
|
79
|
+
const originalFetch = globalThis.fetch;
|
|
80
|
+
|
|
81
|
+
const listenerMap = new Map();
|
|
82
|
+
const slot = {
|
|
83
|
+
addService() {
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const pubads = {
|
|
88
|
+
addEventListener(name, handler) {
|
|
89
|
+
if (!listenerMap.has(name)) {
|
|
90
|
+
listenerMap.set(name, new Set());
|
|
91
|
+
}
|
|
92
|
+
listenerMap.get(name).add(handler);
|
|
93
|
+
},
|
|
94
|
+
removeEventListener(name, handler) {
|
|
95
|
+
listenerMap.get(name)?.delete(handler);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
function emit(name, event) {
|
|
100
|
+
for (const handler of listenerMap.get(name) || []) {
|
|
101
|
+
handler(event);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const googletag = {
|
|
106
|
+
apiReady: true,
|
|
107
|
+
cmd: {
|
|
108
|
+
push(handler) {
|
|
109
|
+
handler();
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
enums: {
|
|
113
|
+
OutOfPageFormat: {
|
|
114
|
+
REWARDED: "REWARDED"
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
pubads() {
|
|
118
|
+
return pubads;
|
|
119
|
+
},
|
|
120
|
+
defineOutOfPageSlot() {
|
|
121
|
+
return mode === "unavailable" ? null : slot;
|
|
122
|
+
},
|
|
123
|
+
enableServices() {},
|
|
124
|
+
display() {
|
|
125
|
+
emit("rewardedSlotReady", {
|
|
126
|
+
slot,
|
|
127
|
+
makeRewardedVisible() {}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
if (mode === "grant") {
|
|
131
|
+
emit("rewardedSlotGranted", {
|
|
132
|
+
slot
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
emit("rewardedSlotClosed", {
|
|
137
|
+
slot
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
destroySlots() {}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
globalThis.window = {
|
|
144
|
+
setTimeout,
|
|
145
|
+
clearTimeout,
|
|
146
|
+
googletag
|
|
147
|
+
};
|
|
148
|
+
globalThis.document = {};
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
restore() {
|
|
152
|
+
globalThis.window = originalWindow;
|
|
153
|
+
globalThis.document = originalDocument;
|
|
154
|
+
globalThis.fetch = originalFetch;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
test("google rewarded runtime resolves immediately when the gate is already unlocked", async () => {
|
|
160
|
+
const originalFetch = globalThis.fetch;
|
|
161
|
+
const { calls, fetchStub } = createFetchStub({
|
|
162
|
+
currentResponse: {
|
|
163
|
+
gateKey: "progress-logging",
|
|
164
|
+
workspaceSlug: "alpha",
|
|
165
|
+
surface: "app",
|
|
166
|
+
enabled: true,
|
|
167
|
+
available: true,
|
|
168
|
+
blocked: false,
|
|
169
|
+
reason: "already-unlocked",
|
|
170
|
+
rule: null,
|
|
171
|
+
providerConfig: {
|
|
172
|
+
id: "21",
|
|
173
|
+
surface: "app",
|
|
174
|
+
enabled: true,
|
|
175
|
+
adUnitPath: "/123456/rewarded",
|
|
176
|
+
scriptMode: "gpt_rewarded"
|
|
177
|
+
},
|
|
178
|
+
unlock: {
|
|
179
|
+
id: "31",
|
|
180
|
+
gateKey: "progress-logging",
|
|
181
|
+
providerConfigId: "21",
|
|
182
|
+
watchSessionId: "41",
|
|
183
|
+
grantedAt: new Date().toISOString(),
|
|
184
|
+
unlockedUntil: new Date(Date.now() + 60_000).toISOString()
|
|
185
|
+
},
|
|
186
|
+
cooldownUntil: null,
|
|
187
|
+
dailyLimitRemaining: null
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
globalThis.fetch = fetchStub;
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
const runtime = createGoogleRewardedRuntime();
|
|
194
|
+
const result = await runtime.requireUnlock({
|
|
195
|
+
gateKey: "progress-logging",
|
|
196
|
+
workspaceSlug: "alpha"
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
assert.equal(result.granted, true);
|
|
200
|
+
assert.equal(result.state.reason, "already-unlocked");
|
|
201
|
+
assert.equal(runtime.state.open, false);
|
|
202
|
+
assert.equal(calls.filter((entry) => entry.url.includes("/google-rewarded/current")).length, 1);
|
|
203
|
+
assert.doesNotMatch(
|
|
204
|
+
calls.find((entry) => entry.url.includes("/google-rewarded/current"))?.url || "",
|
|
205
|
+
/surface=/
|
|
206
|
+
);
|
|
207
|
+
} finally {
|
|
208
|
+
globalThis.fetch = originalFetch;
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("google rewarded runtime rejects when the current gate state is malformed", async () => {
|
|
213
|
+
const originalFetch = globalThis.fetch;
|
|
214
|
+
const { fetchStub } = createFetchStub({
|
|
215
|
+
currentResponse: {
|
|
216
|
+
gateKey: "progress-logging",
|
|
217
|
+
workspaceSlug: "alpha"
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
globalThis.fetch = fetchStub;
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
const runtime = createGoogleRewardedRuntime();
|
|
224
|
+
await assert.rejects(
|
|
225
|
+
() => runtime.requireUnlock({
|
|
226
|
+
gateKey: "progress-logging",
|
|
227
|
+
workspaceSlug: "alpha"
|
|
228
|
+
}),
|
|
229
|
+
/invalid state/i
|
|
230
|
+
);
|
|
231
|
+
assert.equal(runtime.state.open, false);
|
|
232
|
+
} finally {
|
|
233
|
+
globalThis.fetch = originalFetch;
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
test("google rewarded runtime rejects reasonless non-blocking gate states", async () => {
|
|
238
|
+
const originalFetch = globalThis.fetch;
|
|
239
|
+
const { fetchStub } = createFetchStub({
|
|
240
|
+
currentResponse: {
|
|
241
|
+
gateKey: "progress-logging",
|
|
242
|
+
workspaceSlug: "alpha",
|
|
243
|
+
enabled: false,
|
|
244
|
+
blocked: false
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
globalThis.fetch = fetchStub;
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
const runtime = createGoogleRewardedRuntime();
|
|
251
|
+
await assert.rejects(
|
|
252
|
+
() => runtime.requireUnlock({
|
|
253
|
+
gateKey: "progress-logging",
|
|
254
|
+
workspaceSlug: "alpha"
|
|
255
|
+
}),
|
|
256
|
+
/invalid state/i
|
|
257
|
+
);
|
|
258
|
+
assert.equal(runtime.state.open, false);
|
|
259
|
+
} finally {
|
|
260
|
+
globalThis.fetch = originalFetch;
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test("google rewarded runtime completes a rewarded watch flow and grants unlock state", async () => {
|
|
265
|
+
const globals = installBrowserGlobals({
|
|
266
|
+
mode: "grant"
|
|
267
|
+
});
|
|
268
|
+
const { calls, fetchStub } = createFetchStub({
|
|
269
|
+
currentResponse: {
|
|
270
|
+
gateKey: "progress-logging",
|
|
271
|
+
workspaceSlug: "alpha",
|
|
272
|
+
surface: "app",
|
|
273
|
+
enabled: true,
|
|
274
|
+
available: true,
|
|
275
|
+
blocked: true,
|
|
276
|
+
reason: "reward-required",
|
|
277
|
+
rule: null,
|
|
278
|
+
providerConfig: {
|
|
279
|
+
id: "21",
|
|
280
|
+
surface: "app",
|
|
281
|
+
enabled: true,
|
|
282
|
+
adUnitPath: "/123456/rewarded",
|
|
283
|
+
scriptMode: "gpt_rewarded"
|
|
284
|
+
},
|
|
285
|
+
unlock: null,
|
|
286
|
+
cooldownUntil: null,
|
|
287
|
+
dailyLimitRemaining: null
|
|
288
|
+
},
|
|
289
|
+
startResponse: {
|
|
290
|
+
gateKey: "progress-logging",
|
|
291
|
+
workspaceSlug: "alpha",
|
|
292
|
+
surface: "app",
|
|
293
|
+
enabled: true,
|
|
294
|
+
available: true,
|
|
295
|
+
blocked: true,
|
|
296
|
+
reason: "reward-required",
|
|
297
|
+
rule: null,
|
|
298
|
+
providerConfig: {
|
|
299
|
+
id: "21",
|
|
300
|
+
surface: "app",
|
|
301
|
+
enabled: true,
|
|
302
|
+
adUnitPath: "/123456/rewarded",
|
|
303
|
+
scriptMode: "gpt_rewarded"
|
|
304
|
+
},
|
|
305
|
+
unlock: null,
|
|
306
|
+
cooldownUntil: null,
|
|
307
|
+
dailyLimitRemaining: null,
|
|
308
|
+
session: {
|
|
309
|
+
id: "41",
|
|
310
|
+
gateKey: "progress-logging",
|
|
311
|
+
providerConfigId: "21",
|
|
312
|
+
status: "started",
|
|
313
|
+
startedAt: new Date().toISOString(),
|
|
314
|
+
rewardedAt: null,
|
|
315
|
+
completedAt: null,
|
|
316
|
+
closedAt: null
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
grantResponse: {
|
|
320
|
+
unlocked: true,
|
|
321
|
+
workspaceSlug: "alpha",
|
|
322
|
+
gateKey: "progress-logging",
|
|
323
|
+
unlock: {
|
|
324
|
+
id: "51",
|
|
325
|
+
gateKey: "progress-logging",
|
|
326
|
+
providerConfigId: "21",
|
|
327
|
+
watchSessionId: "41",
|
|
328
|
+
grantedAt: new Date().toISOString(),
|
|
329
|
+
unlockedUntil: new Date(Date.now() + 30 * 60_000).toISOString()
|
|
330
|
+
},
|
|
331
|
+
session: {
|
|
332
|
+
id: "41",
|
|
333
|
+
gateKey: "progress-logging",
|
|
334
|
+
providerConfigId: "21",
|
|
335
|
+
status: "rewarded",
|
|
336
|
+
startedAt: new Date().toISOString(),
|
|
337
|
+
rewardedAt: new Date().toISOString(),
|
|
338
|
+
completedAt: new Date().toISOString(),
|
|
339
|
+
closedAt: null
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
globalThis.fetch = fetchStub;
|
|
344
|
+
|
|
345
|
+
try {
|
|
346
|
+
const runtime = createGoogleRewardedRuntime();
|
|
347
|
+
const unlockPromise = runtime.requireUnlock({
|
|
348
|
+
gateKey: "progress-logging",
|
|
349
|
+
workspaceSlug: "alpha"
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
await waitForAsyncTurn();
|
|
353
|
+
assert.equal(runtime.state.phase, "prompt");
|
|
354
|
+
|
|
355
|
+
await runtime.beginWatch();
|
|
356
|
+
const result = await unlockPromise;
|
|
357
|
+
|
|
358
|
+
assert.equal(result.granted, true);
|
|
359
|
+
assert.equal(result.state.unlock.watchSessionId, "41");
|
|
360
|
+
assert.equal(runtime.state.open, false);
|
|
361
|
+
assert.equal(calls.filter((entry) => entry.url.includes("/google-rewarded/start")).length, 1);
|
|
362
|
+
assert.equal(calls.filter((entry) => entry.url.includes("/google-rewarded/grant")).length, 1);
|
|
363
|
+
assert.equal(calls.filter((entry) => entry.url.includes("/google-rewarded/close")).length, 0);
|
|
364
|
+
assert.deepEqual(calls.find((entry) => entry.url.includes("/google-rewarded/start"))?.body, {
|
|
365
|
+
gateKey: "progress-logging"
|
|
366
|
+
});
|
|
367
|
+
} finally {
|
|
368
|
+
globals.restore();
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test("google rewarded runtime closes a started session when the ad is dismissed without reward", async () => {
|
|
373
|
+
const globals = installBrowserGlobals({
|
|
374
|
+
mode: "close"
|
|
375
|
+
});
|
|
376
|
+
const { calls, fetchStub } = createFetchStub({
|
|
377
|
+
currentResponse: {
|
|
378
|
+
gateKey: "progress-logging",
|
|
379
|
+
workspaceSlug: "alpha",
|
|
380
|
+
surface: "app",
|
|
381
|
+
enabled: true,
|
|
382
|
+
available: true,
|
|
383
|
+
blocked: true,
|
|
384
|
+
reason: "reward-required",
|
|
385
|
+
rule: null,
|
|
386
|
+
providerConfig: {
|
|
387
|
+
id: "21",
|
|
388
|
+
surface: "app",
|
|
389
|
+
enabled: true,
|
|
390
|
+
adUnitPath: "/123456/rewarded",
|
|
391
|
+
scriptMode: "gpt_rewarded"
|
|
392
|
+
},
|
|
393
|
+
unlock: null,
|
|
394
|
+
cooldownUntil: null,
|
|
395
|
+
dailyLimitRemaining: null
|
|
396
|
+
},
|
|
397
|
+
startResponse: {
|
|
398
|
+
gateKey: "progress-logging",
|
|
399
|
+
workspaceSlug: "alpha",
|
|
400
|
+
surface: "app",
|
|
401
|
+
enabled: true,
|
|
402
|
+
available: true,
|
|
403
|
+
blocked: true,
|
|
404
|
+
reason: "reward-required",
|
|
405
|
+
rule: null,
|
|
406
|
+
providerConfig: {
|
|
407
|
+
id: "21",
|
|
408
|
+
surface: "app",
|
|
409
|
+
enabled: true,
|
|
410
|
+
adUnitPath: "/123456/rewarded",
|
|
411
|
+
scriptMode: "gpt_rewarded"
|
|
412
|
+
},
|
|
413
|
+
unlock: null,
|
|
414
|
+
cooldownUntil: null,
|
|
415
|
+
dailyLimitRemaining: null,
|
|
416
|
+
session: {
|
|
417
|
+
id: "41",
|
|
418
|
+
gateKey: "progress-logging",
|
|
419
|
+
providerConfigId: "21",
|
|
420
|
+
status: "started",
|
|
421
|
+
startedAt: new Date().toISOString(),
|
|
422
|
+
rewardedAt: null,
|
|
423
|
+
completedAt: null,
|
|
424
|
+
closedAt: null
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
closeResponse: {
|
|
428
|
+
closed: true,
|
|
429
|
+
workspaceSlug: "alpha",
|
|
430
|
+
gateKey: "progress-logging",
|
|
431
|
+
session: {
|
|
432
|
+
id: "41",
|
|
433
|
+
gateKey: "progress-logging",
|
|
434
|
+
providerConfigId: "21",
|
|
435
|
+
status: "closed",
|
|
436
|
+
startedAt: new Date().toISOString(),
|
|
437
|
+
rewardedAt: null,
|
|
438
|
+
completedAt: null,
|
|
439
|
+
closedAt: new Date().toISOString()
|
|
440
|
+
},
|
|
441
|
+
reason: null
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
globalThis.fetch = fetchStub;
|
|
445
|
+
|
|
446
|
+
try {
|
|
447
|
+
const runtime = createGoogleRewardedRuntime();
|
|
448
|
+
const unlockPromise = runtime.requireUnlock({
|
|
449
|
+
gateKey: "progress-logging",
|
|
450
|
+
workspaceSlug: "alpha"
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
await waitForAsyncTurn();
|
|
454
|
+
await runtime.beginWatch();
|
|
455
|
+
const result = await unlockPromise;
|
|
456
|
+
|
|
457
|
+
assert.equal(result.granted, false);
|
|
458
|
+
assert.equal(result.state.closed, true);
|
|
459
|
+
assert.equal(runtime.state.open, false);
|
|
460
|
+
assert.equal(calls.filter((entry) => entry.url.includes("/google-rewarded/grant")).length, 0);
|
|
461
|
+
assert.equal(calls.filter((entry) => entry.url.includes("/google-rewarded/close")).length, 1);
|
|
462
|
+
} finally {
|
|
463
|
+
globals.restore();
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
test("google rewarded runtime exposes an error state when no rewarded slot is available and cleans up on dismiss", async () => {
|
|
468
|
+
const globals = installBrowserGlobals({
|
|
469
|
+
mode: "unavailable"
|
|
470
|
+
});
|
|
471
|
+
const { calls, fetchStub } = createFetchStub({
|
|
472
|
+
currentResponse: {
|
|
473
|
+
gateKey: "progress-logging",
|
|
474
|
+
workspaceSlug: "alpha",
|
|
475
|
+
surface: "app",
|
|
476
|
+
enabled: true,
|
|
477
|
+
available: true,
|
|
478
|
+
blocked: true,
|
|
479
|
+
reason: "reward-required",
|
|
480
|
+
rule: null,
|
|
481
|
+
providerConfig: {
|
|
482
|
+
id: "21",
|
|
483
|
+
surface: "app",
|
|
484
|
+
enabled: true,
|
|
485
|
+
adUnitPath: "/123456/rewarded",
|
|
486
|
+
scriptMode: "gpt_rewarded"
|
|
487
|
+
},
|
|
488
|
+
unlock: null,
|
|
489
|
+
cooldownUntil: null,
|
|
490
|
+
dailyLimitRemaining: null
|
|
491
|
+
},
|
|
492
|
+
startResponse: {
|
|
493
|
+
gateKey: "progress-logging",
|
|
494
|
+
workspaceSlug: "alpha",
|
|
495
|
+
surface: "app",
|
|
496
|
+
enabled: true,
|
|
497
|
+
available: true,
|
|
498
|
+
blocked: true,
|
|
499
|
+
reason: "reward-required",
|
|
500
|
+
rule: null,
|
|
501
|
+
providerConfig: {
|
|
502
|
+
id: "21",
|
|
503
|
+
surface: "app",
|
|
504
|
+
enabled: true,
|
|
505
|
+
adUnitPath: "/123456/rewarded",
|
|
506
|
+
scriptMode: "gpt_rewarded"
|
|
507
|
+
},
|
|
508
|
+
unlock: null,
|
|
509
|
+
cooldownUntil: null,
|
|
510
|
+
dailyLimitRemaining: null,
|
|
511
|
+
session: {
|
|
512
|
+
id: "41",
|
|
513
|
+
gateKey: "progress-logging",
|
|
514
|
+
providerConfigId: "21",
|
|
515
|
+
status: "started",
|
|
516
|
+
startedAt: new Date().toISOString(),
|
|
517
|
+
rewardedAt: null,
|
|
518
|
+
completedAt: null,
|
|
519
|
+
closedAt: null
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
closeResponse: {
|
|
523
|
+
closed: true,
|
|
524
|
+
workspaceSlug: "alpha",
|
|
525
|
+
gateKey: "progress-logging",
|
|
526
|
+
session: {
|
|
527
|
+
id: "41",
|
|
528
|
+
gateKey: "progress-logging",
|
|
529
|
+
providerConfigId: "21",
|
|
530
|
+
status: "closed",
|
|
531
|
+
startedAt: new Date().toISOString(),
|
|
532
|
+
rewardedAt: null,
|
|
533
|
+
completedAt: null,
|
|
534
|
+
closedAt: new Date().toISOString()
|
|
535
|
+
},
|
|
536
|
+
reason: null
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
globalThis.fetch = fetchStub;
|
|
540
|
+
|
|
541
|
+
try {
|
|
542
|
+
const runtime = createGoogleRewardedRuntime();
|
|
543
|
+
const unlockPromise = runtime.requireUnlock({
|
|
544
|
+
gateKey: "progress-logging",
|
|
545
|
+
workspaceSlug: "alpha"
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
await waitForAsyncTurn();
|
|
549
|
+
await runtime.beginWatch();
|
|
550
|
+
|
|
551
|
+
assert.equal(runtime.state.phase, "error");
|
|
552
|
+
assert.match(runtime.state.errorMessage, /rewarded ad/i);
|
|
553
|
+
|
|
554
|
+
await runtime.dismissError();
|
|
555
|
+
const result = await unlockPromise;
|
|
556
|
+
|
|
557
|
+
assert.equal(result.granted, false);
|
|
558
|
+
assert.equal(runtime.state.open, false);
|
|
559
|
+
assert.equal(calls.filter((entry) => entry.url.includes("/google-rewarded/close")).length, 1);
|
|
560
|
+
} finally {
|
|
561
|
+
globals.restore();
|
|
562
|
+
}
|
|
563
|
+
});
|