Skip to content

Commit

Permalink
CriteoIdSystem returns a callback to initiate user sync (prebid#7371)
Browse files Browse the repository at this point in the history
  • Loading branch information
afewcc authored and Chris Pabst committed Jan 10, 2022
1 parent 1201109 commit e8454b4
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 51 deletions.
44 changes: 27 additions & 17 deletions modules/criteoIdSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
*/

import * as utils from '../src/utils.js'
import * as ajax from '../src/ajax.js'
import { getRefererInfo } from '../src/refererDetection.js'
import { ajax } from '../src/ajax.js';
import { getRefererInfo } from '../src/refererDetection.js';
import { submodule } from '../src/hook.js';
import { getStorageManager } from '../src/storageManager.js';

Expand Down Expand Up @@ -65,7 +65,7 @@ function buildCriteoUsersyncUrl(topUrl, domain, bundle, areCookiesWriteable, isL
return url;
}

function callCriteoUserSync(parsedCriteoData, gdprString) {
function callCriteoUserSync(parsedCriteoData, gdprString, callback) {
const cw = storage.cookiesAreEnabled();
const lsw = storage.localStorageIsEnabled();
const topUrl = extractProtocolHost(getRefererInfo().referer);
Expand All @@ -82,26 +82,32 @@ function callCriteoUserSync(parsedCriteoData, gdprString) {
gdprString
);

ajax.ajaxBuilder()(
url,
response => {
const callbacks = {
success: response => {
const jsonResponse = JSON.parse(response);
if (jsonResponse.bidId) {
saveOnAllStorages(bididStorageKey, jsonResponse.bidId);
} else {
deleteFromAllStorages(bididStorageKey);
}

if (jsonResponse.acwsUrl) {
const urlsToCall = typeof jsonResponse.acwsUrl === 'string' ? [jsonResponse.acwsUrl] : jsonResponse.acwsUrl;
urlsToCall.forEach(url => utils.triggerPixel(url));
} else if (jsonResponse.bundle) {
saveOnAllStorages(bundleStorageKey, jsonResponse.bundle);
}

if (jsonResponse.bidId) {
saveOnAllStorages(bididStorageKey, jsonResponse.bidId);
const criteoId = { criteoId: jsonResponse.bidId };
callback(criteoId);
} else {
deleteFromAllStorages(bididStorageKey);
callback();
}
},
undefined,
{ method: 'GET', contentType: 'application/json', withCredentials: true }
);
error: error => {
utils.logError(`criteoIdSystem: unable to sync user id`, error);
callback();
}
};

ajax(url, callbacks, undefined, { method: 'GET', contentType: 'application/json', withCredentials: true });
}

/** @type {Submodule} */
Expand Down Expand Up @@ -132,9 +138,13 @@ export const criteoIdSubmodule = {
const gdprConsentString = hasGdprData ? consentData.consentString : undefined;

let localData = getCriteoDataFromAllStorages();
callCriteoUserSync(localData, gdprConsentString);

return { id: localData.bidId ? { criteoId: localData.bidId } : undefined }
const result = (callback) => callCriteoUserSync(localData, gdprConsentString, callback);

return {
id: localData.bidId ? { criteoId: localData.bidId } : undefined,
callback: result
}
}
};

Expand Down
75 changes: 41 additions & 34 deletions test/spec/modules/criteoIdSystem_spec.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import { criteoIdSubmodule, storage } from 'modules/criteoIdSystem.js';
import * as utils from 'src/utils.js';
import * as ajaxLib from 'src/ajax.js';
import {server} from '../../mocks/xhr';

const pastDateString = new Date(0).toString()

function mockResponse(responseText, fakeResponse = (url, callback) => callback(responseText)) {
return function() {
return fakeResponse;
}
}

describe('CriteoId module', function () {
const cookiesMaxAge = 13 * 30 * 24 * 60 * 60 * 1000;

Expand All @@ -22,7 +16,6 @@ describe('CriteoId module', function () {
let removeFromLocalStorageStub;
let timeStampStub;
let parseUrlStub;
let ajaxBuilderStub;
let triggerPixelStub;

beforeEach(function (done) {
Expand All @@ -32,7 +25,6 @@ describe('CriteoId module', function () {
setLocalStorageStub = sinon.stub(storage, 'setDataInLocalStorage');
removeFromLocalStorageStub = sinon.stub(storage, 'removeDataFromLocalStorage');
timeStampStub = sinon.stub(utils, 'timestamp').returns(nowTimestamp);
ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(mockResponse('{}'));
parseUrlStub = sinon.stub(utils, 'parseUrl').returns({protocol: 'https', hostname: 'testdev.com'})
triggerPixelStub = sinon.stub(utils, 'triggerPixel');
done();
Expand All @@ -45,7 +37,6 @@ describe('CriteoId module', function () {
setLocalStorageStub.restore();
removeFromLocalStorageStub.restore();
timeStampStub.restore();
ajaxBuilderStub.restore();
triggerPixelStub.restore();
parseUrlStub.restore();
});
Expand All @@ -61,8 +52,9 @@ describe('CriteoId module', function () {
getCookieStub.withArgs('cto_bidid').returns(testCase.cookie);
getLocalStorageStub.withArgs('cto_bidid').returns(testCase.localStorage);

const id = criteoIdSubmodule.getId();
expect(id).to.be.deep.equal({id: testCase.expected ? { criteoId: testCase.expected } : undefined});
const result = criteoIdSubmodule.getId();
expect(result.id).to.be.deep.equal(testCase.expected ? { criteoId: testCase.expected } : undefined);
expect(result.callback).to.be.a('function');
}))

it('decode() should return the bidId when it exists in local storages', function () {
Expand All @@ -74,16 +66,21 @@ describe('CriteoId module', function () {
getCookieStub.withArgs('cto_bundle').returns('bundle');
window.criteo_pubtag = {}

const emptyObj = '{}';
let ajaxStub = sinon.stub().callsFake((url, callback) => callback(emptyObj));
ajaxBuilderStub.callsFake(mockResponse(undefined, ajaxStub))
let callBackSpy = sinon.spy();
let result = criteoIdSubmodule.getId();
result.callback(callBackSpy);

criteoIdSubmodule.getId();
const expectedUrl = `https://gum.criteo.com/sid/json?origin=prebid&topUrl=https%3A%2F%2Ftestdev.com%2F&domain=testdev.com&bundle=bundle&cw=1&pbt=1&lsw=1`;

expect(ajaxStub.calledWith(expectedUrl)).to.be.true;
let request = server.requests[0];
expect(request.url).to.be.eq(expectedUrl);

window.criteo_pubtag = undefined;
request.respond(
200,
{'Content-Type': 'application/json'},
JSON.stringify({})
);
expect(callBackSpy.calledOnce).to.be.true;
});

const responses = [
Expand All @@ -101,16 +98,19 @@ describe('CriteoId module', function () {
responses.forEach(response => describe('test user sync response behavior', function () {
const expirationTs = new Date(nowTimestamp + cookiesMaxAge).toString();

beforeEach(function (done) {
const fakeResponse = (url, callback) => {
callback(JSON.stringify(response));
setTimeout(done, 0);
}
ajaxBuilderStub.callsFake(mockResponse(undefined, fakeResponse));
criteoIdSubmodule.getId();
})

it('should save bidId if it exists', function () {
const result = criteoIdSubmodule.getId();
result.callback((id) => {
expect(id).to.be.deep.equal(response.bidId ? { criteoId: response.bidId } : undefined);
});

let request = server.requests[0];
request.respond(
200,
{'Content-Type': 'application/json'},
JSON.stringify(response)
);

if (response.acwsUrl) {
expect(triggerPixelStub.called).to.be.true;
expect(setCookieStub.calledWith('cto_bundle')).to.be.false;
Expand Down Expand Up @@ -140,16 +140,23 @@ describe('CriteoId module', function () {
];

gdprConsentTestCases.forEach(testCase => it('should call user sync url with the gdprConsent', function () {
const emptyObj = '{}';
let ajaxStub = sinon.stub().callsFake((url, callback) => callback(emptyObj));
ajaxBuilderStub.callsFake(mockResponse(undefined, ajaxStub))

criteoIdSubmodule.getId(undefined, testCase.consentData);
let callBackSpy = sinon.spy();
let result = criteoIdSubmodule.getId(undefined, testCase.consentData);
result.callback(callBackSpy);

let request = server.requests[0];
if (testCase.expected) {
expect(ajaxStub.calledWithMatch(`gdprString=${testCase.expected}`)).to.be.true;
expect(request.url).to.have.string(`gdprString=${testCase.expected}`);
} else {
expect(ajaxStub.calledWithMatch('gdprString')).not.to.be.true;
expect(request.url).to.not.have.string('gdprString');
}

request.respond(
200,
{'Content-Type': 'application/json'},
JSON.stringify({})
);

expect(callBackSpy.calledOnce).to.be.true;
}));
});

0 comments on commit e8454b4

Please sign in to comment.