849 lines
32 KiB
JavaScript
849 lines
32 KiB
JavaScript
// META: script=/resources/testdriver.js
|
|
// META: script=/resources/testdriver-vendor.js
|
|
// META: script=/common/utils.js
|
|
// META: script=resources/ba-fledge-util.sub.js
|
|
// META: script=resources/fledge-util.sub.js
|
|
// META: script=third_party/cbor-js/cbor.js
|
|
// META: script=/common/subset-tests.js
|
|
// META: timeout=long
|
|
// META: variant=?1-4
|
|
// META: variant=?5-8
|
|
// META: variant=?9-12
|
|
// META: variant=?13-16
|
|
// META: variant=?17-last
|
|
|
|
"use strict";
|
|
|
|
// These tests focus on the navigator.getInterestGroupAdAuctionData() method.
|
|
|
|
// Checks various fields for decoded InterestGroupAdAuctionData that's
|
|
// one IG owned by this origin, and returns that IG's info.
|
|
function validateWithOneIg(decoded) {
|
|
assert_equals(decoded.message.version, 0);
|
|
assert_equals(decoded.message.publisher, window.location.hostname);
|
|
assert_equals(typeof decoded.message.generationId, 'string');
|
|
let igMapKeys = Object.getOwnPropertyNames(decoded.message.interestGroups);
|
|
assert_array_equals(igMapKeys, [window.location.origin]);
|
|
let igInfo = decoded.message.interestGroups[window.location.origin];
|
|
assert_true(igInfo instanceof Array);
|
|
assert_equals(igInfo.length, 1, 'number of IGs');
|
|
return igInfo[0];
|
|
}
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length === 0);
|
|
}, 'getInterestGroupAdAuctionData() with no interest groups returns a zero length result.');
|
|
|
|
async function testInvalidConfig(test, configObj, desc) {
|
|
if (!configObj.coordinatorOrigin) {
|
|
configObj.coordinatorOrigin = await BA.configureCoordinator();
|
|
}
|
|
await promise_rejects_js(
|
|
test, TypeError, navigator.getInterestGroupAdAuctionData(configObj),
|
|
desc);
|
|
}
|
|
|
|
subsetTest(promise_test, async test => {
|
|
await testInvalidConfig(test, {}, 'no seller');
|
|
await testInvalidConfig(test, {seller: 'example'}, 'invalid seller 1');
|
|
await testInvalidConfig(
|
|
test, {seller: 'http://example.org'}, 'invalid seller 2');
|
|
await testInvalidConfig(
|
|
test, {seller: 'https://example.org', coordinatorOrigin: 'example'},
|
|
'invalid coordinator 1');
|
|
await testInvalidConfig(
|
|
test, {seller: 'https://example.org', coordinatorOrigin: 'example.org'},
|
|
'invalid coordinator 2');
|
|
|
|
await testInvalidConfig(
|
|
test, {seller: 'https://example.org', perBuyerConfig: {'a': {}}},
|
|
'invalid buyer 1');
|
|
|
|
await testInvalidConfig(
|
|
test,
|
|
{seller: 'https://example.org', perBuyerConfig: {'http://a.com': {}}},
|
|
'invalid buyer 2');
|
|
|
|
await testInvalidConfig(
|
|
test, {
|
|
seller: 'https://example.org',
|
|
perBuyerConfig: {'https://a.com': {}, 'http://b.com': {}}
|
|
},
|
|
'invalid buyer 3');
|
|
|
|
await testInvalidConfig(
|
|
test, {
|
|
seller: 'https://example.org',
|
|
perBuyerConfig: {'https://a.com': {}, 'https://b.com': {}}
|
|
},
|
|
'missing size info w/per-buyer config 1');
|
|
|
|
await testInvalidConfig(
|
|
test, {
|
|
seller: 'https://example.org',
|
|
perBuyerConfig:
|
|
{'https://a.com': {targetSize: 400}, 'https://b.com': {}}
|
|
},
|
|
'missing size info w/per-buyer config 2');
|
|
|
|
// These two actually succeed.
|
|
let result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: 'https://example.org',
|
|
perBuyerConfig:
|
|
{'https://a.com': {targetSize: 400}, 'https://b.com': {targetSize: 500}}
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
|
|
result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: 'https://example.org',
|
|
perBuyerConfig: {'https://a.com': {targetSize: 400}, 'https://b.com': {}},
|
|
requestSize: 5000
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
}, 'getInterestGroupAdAuctionData() config checks');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
await joinInterestGroup(test, uuid);
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
|
|
// Check that the required field and one IG (but no ad data) are here,
|
|
// since we neither provided adRenderIds or asked for full data to be
|
|
// included.
|
|
let ig = validateWithOneIg(decoded);
|
|
assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
|
|
assert_array_equals(ig.ads, []);
|
|
assert_equals(ig.browserSignals.joinCount, 1, 'joinCount');
|
|
assert_equals(ig.browserSignals.bidCount, 0, 'bidCount');
|
|
assert_array_equals(ig.browserSignals.prevWins, []);
|
|
}, 'getInterestGroupAdAuctionData() with one interest group returns a valid result.');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
await joinInterestGroup(test, uuid, {
|
|
ads: [
|
|
{renderURL: createRenderURL(uuid) + '&a', adRenderId: 'a'},
|
|
{renderURL: createRenderURL(uuid) + '&a', adRenderId: 'b'}
|
|
]
|
|
});
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
let ig = validateWithOneIg(decoded);
|
|
|
|
// This ig should have two ads with adRenderIds, but not URLs.
|
|
assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
|
|
assert_array_equals(ig.ads, ['a', 'b']);
|
|
assert_equals(ig.browserSignals.joinCount, 1, 'joinCount');
|
|
assert_equals(ig.browserSignals.bidCount, 0, 'bidCount');
|
|
assert_array_equals(ig.browserSignals.prevWins, []);
|
|
}, 'getInterestGroupAdAuctionData() with one interest group with two ads w/renderIds.');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
await joinInterestGroup(test, uuid, {
|
|
auctionServerRequestFlags: ['omit-ads'],
|
|
ads: [
|
|
{renderURL: createRenderURL(uuid) + '&a', adRenderId: 'a'},
|
|
{renderURL: createRenderURL(uuid) + '&a', adRenderId: 'b'}
|
|
]
|
|
});
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
let ig = validateWithOneIg(decoded);
|
|
|
|
assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
|
|
assert_not_own_property(ig, 'ads', 'no ads expected');
|
|
assert_equals(ig.browserSignals.joinCount, 1, 'joinCount');
|
|
}, 'getInterestGroupAdAuctionData() with one interest group with two ads w/renderIds and omit-ads.');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
|
|
const adsArray = [
|
|
{renderURL: createRenderURL(uuid) + '&a', adRenderId: 'a'},
|
|
{renderURL: createRenderURL(uuid) + '&a', adRenderId: 'b'}
|
|
];
|
|
await joinInterestGroup(
|
|
test, uuid,
|
|
{auctionServerRequestFlags: ['include-full-ads'], ads: adsArray});
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
let ig = validateWithOneIg(decoded);
|
|
|
|
// Since include-full-ads is on, this gets entire objects, not just
|
|
// adRenderId.
|
|
assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
|
|
assert_equals(ig.ads.length, 2, '# of ads');
|
|
assert_equals(ig.ads[0].renderURL, adsArray[0].renderURL, 'renderURL 0');
|
|
assert_equals(ig.ads[1].renderURL, adsArray[1].renderURL, 'renderURL 1');
|
|
assert_equals(ig.ads[0].adRenderId, adsArray[0].adRenderId, 'adRenderId 0');
|
|
assert_equals(ig.ads[1].adRenderId, adsArray[1].adRenderId, 'adRenderId 1');
|
|
assert_equals(ig.browserSignals.joinCount, 1, 'joinCount');
|
|
}, 'getInterestGroupAdAuctionData() with one interest group with two ads w/renderIds and include-full-ads.');
|
|
|
|
// Returns an AuctionAdInterestGroup that sets all fields that can be exported
|
|
// via getInterestGroupAdAuctionData().
|
|
function makeTemplateIgConfig(uuid) {
|
|
const adsArray = [
|
|
{
|
|
renderURL: createRenderURL(uuid) + '&a',
|
|
adRenderId: 'a',
|
|
metadata: 'ada',
|
|
sizeGroup: 'small'
|
|
},
|
|
{
|
|
renderURL: createRenderURL(uuid) + '&b',
|
|
adRenderId: 'b',
|
|
metadata: 'adb',
|
|
sizeGroup: 'big'
|
|
}
|
|
];
|
|
const adComponentsArray = [
|
|
{
|
|
renderURL: 'https://example.org/ca',
|
|
adRenderId: 'ca',
|
|
metadata: 'compa',
|
|
sizeGroup: 'big'
|
|
},
|
|
{
|
|
renderURL: 'https://example.org/cb',
|
|
adRenderId: 'cb',
|
|
metadata: 'compb',
|
|
sizeGroup: 'small'
|
|
},
|
|
{
|
|
renderURL: 'https://example.org/cc',
|
|
adRenderId: 'cc',
|
|
metadata: 'compc',
|
|
sizeGroup: 'big'
|
|
},
|
|
];
|
|
return {
|
|
ads: adsArray,
|
|
adComponents: adComponentsArray,
|
|
adSizes: {
|
|
's': {width: '100px', height: '30px'},
|
|
'xl': {width: '1000px', height: '300px'}
|
|
},
|
|
sizeGroups: {'small': ['s'], 'big': ['xl']},
|
|
trustedBiddingSignalsKeys: ['alpha', 'beta'],
|
|
userBiddingSignals: 14
|
|
};
|
|
}
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
igConfig.auctionServerRequestFlags = ['include-full-ads'];
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
let ig = validateWithOneIg(decoded);
|
|
|
|
assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
|
|
assert_true(ig.ads instanceof Array);
|
|
assert_equals(ig.ads.length, 2, '# of ads');
|
|
assert_equals(ig.ads[0].renderURL, igConfig.ads[0].renderURL, 'renderURL 0');
|
|
assert_equals(ig.ads[1].renderURL, igConfig.ads[1].renderURL, 'renderURL 1');
|
|
assert_equals(ig.ads[0].adRenderId, 'a', 'adRenderId 0');
|
|
assert_equals(ig.ads[1].adRenderId, 'b', 'adRenderId 1');
|
|
assert_equals(ig.ads[0].metadata, '"ada"', 'metadata 0');
|
|
assert_equals(ig.ads[1].metadata, '"adb"', 'metadata 1');
|
|
assert_equals(ig.ads[0].sizeGroup, 'small', 'sizegroup 0');
|
|
assert_equals(ig.ads[1].sizeGroup, 'big', 'sizegroup 1');
|
|
|
|
assert_true(ig.components instanceof Array);
|
|
assert_equals(ig.components.length, 3, '# of component ads');
|
|
assert_equals(
|
|
ig.components[0].renderURL, igConfig.adComponents[0].renderURL,
|
|
'component renderURL 0');
|
|
assert_equals(
|
|
ig.components[1].renderURL, igConfig.adComponents[1].renderURL,
|
|
'component renderURL 1');
|
|
assert_equals(
|
|
ig.components[2].renderURL, igConfig.adComponents[2].renderURL,
|
|
'component renderURL 2');
|
|
assert_equals(ig.components[0].adRenderId, 'ca', 'component adRenderId 0');
|
|
assert_equals(ig.components[1].adRenderId, 'cb', 'component adRenderId 1');
|
|
assert_equals(ig.components[2].adRenderId, 'cc', 'component adRenderId 2');
|
|
assert_equals(ig.components[0].metadata, '"compa"', 'component metadata 0');
|
|
assert_equals(ig.components[1].metadata, '"compb"', 'component metadata 1');
|
|
assert_equals(ig.components[2].metadata, '"compc"', 'component metadata 2');
|
|
assert_equals(ig.components[0].sizeGroup, 'big', 'component sizegroup 0');
|
|
assert_equals(ig.components[1].sizeGroup, 'small', 'component sizegroup 1');
|
|
assert_equals(ig.components[2].sizeGroup, 'big', 'component sizegroup 2');
|
|
|
|
assert_true(ig.biddingSignalsKeys instanceof Array);
|
|
assert_array_equals(ig.biddingSignalsKeys, ['alpha', 'beta']);
|
|
assert_equals(ig.userBiddingSignals, '14');
|
|
}, 'getInterestGroupAdAuctionData() all IG data fields, with include-full-ads');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
let ig = validateWithOneIg(decoded);
|
|
|
|
assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
|
|
assert_array_equals(ig.ads, ['a', 'b']);
|
|
|
|
assert_true(ig.components instanceof Array);
|
|
assert_array_equals(ig.ads, ['a', 'b']);
|
|
assert_array_equals(ig.components, ['ca', 'cb', 'cc']);
|
|
|
|
assert_array_equals(ig.biddingSignalsKeys, ['alpha', 'beta']);
|
|
assert_equals(ig.userBiddingSignals, '14');
|
|
}, 'getInterestGroupAdAuctionData() all IG data fields, w/o include-full-ads');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
igConfig.auctionServerRequestFlags = ['omit-user-bidding-signals'];
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
let ig = validateWithOneIg(decoded);
|
|
|
|
assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
|
|
assert_array_equals(ig.ads, ['a', 'b']);
|
|
|
|
assert_true(ig.components instanceof Array);
|
|
assert_array_equals(ig.ads, ['a', 'b']);
|
|
assert_array_equals(ig.components, ['ca', 'cb', 'cc']);
|
|
|
|
assert_array_equals(ig.biddingSignalsKeys, ['alpha', 'beta']);
|
|
assert_false('userBiddingSignals' in ig, 'userBiddingSignals');
|
|
}, 'getInterestGroupAdAuctionData() all IG data fields, with omit-user-bidding-signals');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
|
|
// Join twice.
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
// And run an auction. This is a local auction, not a B&A one, run to update
|
|
// bid/win stats.
|
|
await runBasicFledgeAuctionAndNavigate(test, uuid);
|
|
await waitForObservedRequests(
|
|
uuid, [createBidderReportURL(uuid), createSellerReportURL(uuid)]);
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
let ig = validateWithOneIg(decoded);
|
|
assert_equals(ig.browserSignals.joinCount, 2, 'joinCount');
|
|
assert_equals(ig.browserSignals.bidCount, 1, 'bidCount');
|
|
|
|
// RecencyMs is the # of milliseconds since the join. We can't exactly say
|
|
// what it is, but it shouldn't be too huge.
|
|
assert_true(typeof ig.browserSignals.recencyMs === 'number');
|
|
assert_between_inclusive(
|
|
ig.browserSignals.recencyMs, 0, 60000,
|
|
'RecencyMs is between 0 and 60 seconds');
|
|
// It's also supposed to be an integer.
|
|
assert_equals(
|
|
ig.browserSignals.recencyMs, Math.round(ig.browserSignals.recencyMs),
|
|
'RecencyMs is an integer');
|
|
|
|
// One win. The format here depends highly on whether full ads are used or
|
|
// not.
|
|
assert_true(
|
|
ig.browserSignals.prevWins instanceof Array, 'prevWins is an array');
|
|
assert_equals(ig.browserSignals.prevWins.length, 1, 'prevWins length');
|
|
assert_true(
|
|
ig.browserSignals.prevWins[0] instanceof Array,
|
|
'prevWins[0] is an array');
|
|
assert_equals(ig.browserSignals.prevWins[0].length, 2, 'prevWins[0] length');
|
|
|
|
// prevWins[0][0] is the time delta in second again.
|
|
let prevWinTime = ig.browserSignals.prevWins[0][0];
|
|
assert_true(typeof prevWinTime === 'number');
|
|
assert_between_inclusive(
|
|
prevWinTime, 0, 60, 'prevWinTime is between 0 and 60 seconds');
|
|
// It's also supposed to be an integer.
|
|
assert_equals(
|
|
prevWinTime, Math.round(prevWinTime), 'prevWinTime is an integer');
|
|
|
|
// prevWins[0][1] is the adRenderId of the winner.
|
|
assert_equals(ig.browserSignals.prevWins[0][1], 'a');
|
|
}, 'getInterestGroupAdAuctionData() browserSignals');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
igConfig.auctionServerRequestFlags = ['include-full-ads'];
|
|
|
|
// Join twice.
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
// And run an auction. This is a local auction, not a B&A one, run to update
|
|
// bid/win stats.
|
|
await runBasicFledgeAuctionAndNavigate(test, uuid);
|
|
await waitForObservedRequests(
|
|
uuid, [createBidderReportURL(uuid), createSellerReportURL(uuid)]);
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
let ig = validateWithOneIg(decoded);
|
|
assert_equals(ig.browserSignals.joinCount, 2, 'joinCount');
|
|
assert_equals(ig.browserSignals.bidCount, 1, 'bidCount');
|
|
|
|
// RecencyMs is the # of milliseconds since the join. We can't exactly say
|
|
// what it is, but it shouldn't be too huge.
|
|
assert_true(typeof ig.browserSignals.recencyMs === 'number');
|
|
assert_between_inclusive(
|
|
ig.browserSignals.recencyMs, 0, 60000,
|
|
'RecencyMs is between 0 and 60 seconds');
|
|
// It's also supposed to be an integer.
|
|
assert_equals(
|
|
ig.browserSignals.recencyMs, Math.round(ig.browserSignals.recencyMs),
|
|
'RecencyMs is an integer');
|
|
|
|
// One win. The format here depends highly on whether full ads are used or
|
|
// not.
|
|
assert_true(
|
|
ig.browserSignals.prevWins instanceof Array, 'prevWins is an array');
|
|
assert_equals(ig.browserSignals.prevWins.length, 1, 'prevWins length');
|
|
assert_true(
|
|
ig.browserSignals.prevWins[0] instanceof Array,
|
|
'prevWins[0] is an array');
|
|
assert_equals(ig.browserSignals.prevWins[0].length, 2, 'prevWins[0] length');
|
|
|
|
// prevWins[0][0] is the time delta in second again.
|
|
let prevWinTime = ig.browserSignals.prevWins[0][0];
|
|
assert_true(typeof prevWinTime === 'number');
|
|
assert_between_inclusive(
|
|
prevWinTime, 0, 60, 'prevWinTime is between 0 and 60 seconds');
|
|
// It's also supposed to be an integer.
|
|
assert_equals(
|
|
prevWinTime, Math.round(prevWinTime), 'prevWinTime is an integer');
|
|
|
|
// prevWins[0][1] is an ad object w/include-full-ads on (with renderURL,
|
|
// metadata, and adRenderId).
|
|
let prevWinAd = ig.browserSignals.prevWins[0][1];
|
|
assert_equals(
|
|
prevWinAd.renderURL, igConfig.ads[0].renderURL, 'prevWin ad renderURL');
|
|
assert_equals(prevWinAd.metadata, '"ada"', 'prevWin ad metadata');
|
|
assert_equals(prevWinAd.adRenderId, 'a', 'prevWin ad adRenderId');
|
|
}, 'getInterestGroupAdAuctionData() browserSignals with include-full-ads');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
|
|
const igTemplate = makeTemplateIgConfig(uuid);
|
|
await joinInterestGroup(test, uuid, {...igTemplate, name: 'first'});
|
|
await joinInterestGroup(test, uuid, {...igTemplate, name: 'second'});
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
assert_equals(decoded.message.version, 0);
|
|
assert_equals(decoded.message.publisher, window.location.hostname);
|
|
assert_equals(typeof decoded.message.generationId, 'string');
|
|
|
|
let origin = window.location.origin;
|
|
let igMapKeys = Object.getOwnPropertyNames(decoded.message.interestGroups);
|
|
assert_array_equals(igMapKeys, [origin]);
|
|
assert_equals(decoded.message.interestGroups[origin].length, 2);
|
|
let names = [
|
|
decoded.message.interestGroups[origin][0].name,
|
|
decoded.message.interestGroups[origin][1].name
|
|
];
|
|
assert_array_equals(names.sort(), ['first', 'second']);
|
|
}, 'getInterestGroupAdAuctionData() with multiple interest groups');
|
|
|
|
async function joinCrossOriginIG(test, uuid, origin, name) {
|
|
let iframe = await createIframe(test, origin, 'join-ad-interest-group');
|
|
await runInFrame(
|
|
test, iframe,
|
|
`await joinInterestGroup(test_instance, "${uuid}", {name: "${name}"});`);
|
|
}
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
|
|
await joinCrossOriginIG(test, uuid, OTHER_ORIGIN1, 'o1');
|
|
await joinCrossOriginIG(test, uuid, OTHER_ORIGIN2, 'o2');
|
|
await joinCrossOriginIG(test, uuid, OTHER_ORIGIN3, 'o3');
|
|
await joinCrossOriginIG(test, uuid, OTHER_ORIGIN4, 'o4');
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
assert_equals(decoded.message.version, 0);
|
|
assert_equals(decoded.message.publisher, window.location.hostname);
|
|
assert_equals(typeof decoded.message.generationId, 'string');
|
|
let igMapKeys = Object.getOwnPropertyNames(decoded.message.interestGroups);
|
|
assert_array_equals(
|
|
igMapKeys.sort(),
|
|
[OTHER_ORIGIN1, OTHER_ORIGIN2, OTHER_ORIGIN3, OTHER_ORIGIN4].sort());
|
|
assert_equals(decoded.message.interestGroups[OTHER_ORIGIN1].length, 1);
|
|
assert_equals(decoded.message.interestGroups[OTHER_ORIGIN1][0].name, 'o1');
|
|
assert_equals(decoded.message.interestGroups[OTHER_ORIGIN2].length, 1);
|
|
assert_equals(decoded.message.interestGroups[OTHER_ORIGIN2][0].name, 'o2');
|
|
assert_equals(decoded.message.interestGroups[OTHER_ORIGIN3].length, 1);
|
|
assert_equals(decoded.message.interestGroups[OTHER_ORIGIN3][0].name, 'o3');
|
|
assert_equals(decoded.message.interestGroups[OTHER_ORIGIN4].length, 1);
|
|
assert_equals(decoded.message.interestGroups[OTHER_ORIGIN4][0].name, 'o4');
|
|
}, 'getInterestGroupAdAuctionData() with multiple buyers');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
|
|
let renderURL = createRenderURL(uuid);
|
|
let bidderDebugReportURL =
|
|
createBidderReportURL(uuid, /*id=*/ 'forDebuggingOnly');
|
|
|
|
let biddingLogicURL = createBiddingScriptURL({
|
|
generateBid: `
|
|
forDebuggingOnly.reportAdAuctionWin('${bidderDebugReportURL}');
|
|
return {bid: 1, render: '${renderURL}'};`
|
|
});
|
|
|
|
await Promise.all([
|
|
joinInterestGroup(
|
|
test, uuid,
|
|
{name: 'o1', ads: [{renderURL: renderURL}], biddingLogicURL}),
|
|
joinInterestGroup(
|
|
test, uuid,
|
|
{name: 'o2', ads: [{renderURL: renderURL}], biddingLogicURL})
|
|
]);
|
|
|
|
// Run an auction to put the origin to cooldown, or lockout.
|
|
await runBasicFledgeAuctionAndNavigate(test, uuid);
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
assert_equals(decoded.message.version, 0);
|
|
assert_equals(decoded.message.publisher, window.location.hostname);
|
|
assert_equals(typeof decoded.message.generationId, 'string');
|
|
|
|
assert_equals(
|
|
decoded.message.interestGroups[window.location.origin].length, 2);
|
|
assert_equals(
|
|
decoded.message.interestGroups[window.location.origin][0]
|
|
.inCooldownOrLockout,
|
|
true);
|
|
assert_equals(
|
|
decoded.message.interestGroups[window.location.origin][1]
|
|
.inCooldownOrLockout,
|
|
true);
|
|
}, 'getInterestGroupAdAuctionData() InCooldownOrLockout in each IG');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
|
|
await joinCrossOriginIG(test, uuid, OTHER_ORIGIN1, 'o1');
|
|
await joinCrossOriginIG(test, uuid, OTHER_ORIGIN2, 'o2');
|
|
await joinCrossOriginIG(test, uuid, OTHER_ORIGIN3, 'o3');
|
|
await joinCrossOriginIG(test, uuid, OTHER_ORIGIN4, 'o4');
|
|
|
|
let config = {
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin,
|
|
perBuyerConfig: {},
|
|
requestSize: 5000
|
|
};
|
|
config.perBuyerConfig[OTHER_ORIGIN2] = {};
|
|
config.perBuyerConfig[OTHER_ORIGIN3] = {};
|
|
const result = await navigator.getInterestGroupAdAuctionData(config);
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
assert_equals(decoded.message.version, 0);
|
|
assert_equals(decoded.message.publisher, window.location.hostname);
|
|
assert_equals(typeof decoded.message.generationId, 'string');
|
|
let igMapKeys = Object.getOwnPropertyNames(decoded.message.interestGroups);
|
|
assert_array_equals(igMapKeys.sort(), [OTHER_ORIGIN2, OTHER_ORIGIN3].sort());
|
|
assert_equals(decoded.message.interestGroups[OTHER_ORIGIN2].length, 1);
|
|
assert_equals(decoded.message.interestGroups[OTHER_ORIGIN2][0].name, 'o2');
|
|
assert_equals(decoded.message.interestGroups[OTHER_ORIGIN3].length, 1);
|
|
assert_equals(decoded.message.interestGroups[OTHER_ORIGIN3][0].name, 'o3');
|
|
}, 'getInterestGroupAdAuctionData() uses perBuyerConfig to select buyers');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
await joinInterestGroup(test, uuid);
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin
|
|
});
|
|
assert_true(result.requestId !== null);
|
|
assert_true(result.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(result.request);
|
|
|
|
assert_own_property(decoded.message, 'enforceKAnon');
|
|
assert_equals(decoded.message.enforceKAnon, true);
|
|
}, 'getInterestGroupAdAuctionData() requests k-anon.');
|
|
|
|
|
|
/*************************************************************************
|
|
* Tests for the multi-seller variant of the API
|
|
*************************************************************************/
|
|
|
|
async function validateForSeller(adAuctionData, seller) {
|
|
assert_equals(adAuctionData.seller, seller);
|
|
assert_not_own_property(adAuctionData, 'error');
|
|
assert_own_property(adAuctionData, 'request');
|
|
assert_true(adAuctionData.request.length > 0);
|
|
|
|
let decoded = await BA.decodeInterestGroupData(adAuctionData.request);
|
|
let ig = validateWithOneIg(decoded);
|
|
|
|
assert_equals(ig.name, DEFAULT_INTEREST_GROUP_NAME);
|
|
assert_array_equals(ig.ads, ['a', 'b']);
|
|
|
|
assert_true(ig.components instanceof Array);
|
|
assert_array_equals(ig.components, ['ca', 'cb', 'cc']);
|
|
|
|
assert_array_equals(ig.biddingSignalsKeys, ['alpha', 'beta']);
|
|
assert_equals(ig.userBiddingSignals, '14');
|
|
}
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
sellers: [{
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin,
|
|
}]
|
|
});
|
|
|
|
assert_true(result.requestId !== null);
|
|
assert_own_property(result, 'requests');
|
|
assert_equals(result.requests.length, 1);
|
|
await validateForSeller(result.requests[0], window.location.origin);
|
|
}, 'getInterestGroupAdAuctionData() multi-seller with single seller');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
sellers: [{
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin,
|
|
}, {
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: OTHER_ORIGIN1,
|
|
}]
|
|
});
|
|
|
|
assert_true(result.requestId !== null);
|
|
assert_own_property(result, 'requests');
|
|
assert_equals(result.requests.length, 2, JSON.stringify(result));
|
|
result.requests.sort((a,b)=> (a.seller < b.seller ? -1 : +(a.seller > b.seller)));
|
|
|
|
await validateForSeller(result.requests[0], OTHER_ORIGIN1);
|
|
await validateForSeller(result.requests[1], window.location.origin);
|
|
|
|
assert_not_equals(result.requests[0].request.toString(), result.requests[1].request.toString());
|
|
}, 'getInterestGroupAdAuctionData() multi-seller with multiple sellers - valid');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
sellers: [{
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin,
|
|
}, {
|
|
coordinatorOrigin: "https://invalid.coordinator.test/",
|
|
seller: OTHER_ORIGIN1,
|
|
}]
|
|
});
|
|
|
|
assert_true(result.requestId !== null);
|
|
assert_own_property(result, 'requests');
|
|
assert_equals(result.requests.length, 2, JSON.stringify(result));
|
|
result.requests.sort((a,b)=> (a.seller < b.seller ? -1 : +(a.seller > b.seller)));
|
|
|
|
assert_equals(result.requests[0].seller, OTHER_ORIGIN1);
|
|
assert_own_property(result.requests[0], 'error');
|
|
assert_not_own_property(result.requests[0], 'request');
|
|
|
|
await validateForSeller(result.requests[1], window.location.origin);
|
|
}, 'getInterestGroupAdAuctionData() multi-seller with multiple sellers - one invalid coordinator');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
await promise_rejects_js(test, TypeError, navigator.getInterestGroupAdAuctionData({
|
|
sellers: [{
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin,
|
|
}, {
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: "http://not.secure.test/",
|
|
}]
|
|
}));
|
|
}, 'getInterestGroupAdAuctionData() multi-seller with multiple sellers - one invalid seller');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
await promise_rejects_js(test, TypeError, navigator.getInterestGroupAdAuctionData({
|
|
}));
|
|
}, 'getInterestGroupAdAuctionData() one of "seller" and "sellers" is required');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
await promise_rejects_js(test, TypeError, navigator.getInterestGroupAdAuctionData({
|
|
seller: window.location.origin,
|
|
sellers: [{
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin,
|
|
}]
|
|
}));
|
|
}, 'getInterestGroupAdAuctionData() doesn\'t allow "seller" and "sellers" fields');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
await promise_rejects_js(test, TypeError, navigator.getInterestGroupAdAuctionData({
|
|
coordinatorOrigin: window.location.origin,
|
|
sellers: [{
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin,
|
|
}]
|
|
}));
|
|
}, 'getInterestGroupAdAuctionData() doesn\'t allow "coordinatorOrigin" and "sellers" fields');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
await promise_rejects_js(test, TypeError, navigator.getInterestGroupAdAuctionData({
|
|
sellers: [{
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin,
|
|
}, {
|
|
coordinatorOrigin: await BA.configureCoordinator(),
|
|
seller: window.location.origin,
|
|
}
|
|
]
|
|
}));
|
|
}, 'getInterestGroupAdAuctionData() doesn\'t allow duplicate sellers in "sellers" field');
|
|
|
|
subsetTest(promise_test, async test => {
|
|
const uuid = generateUuid(test);
|
|
const igConfig = makeTemplateIgConfig(uuid);
|
|
await joinInterestGroup(test, uuid, igConfig);
|
|
|
|
const result = await navigator.getInterestGroupAdAuctionData({
|
|
sellers: []
|
|
});
|
|
assert_equals(result.requestId, "");
|
|
assert_array_equals(result.requests, []);
|
|
}, 'getInterestGroupAdAuctionData() with no sellers');
|