Skip to content

Commit

Permalink
IDx user id submodule (prebid#5826)
Browse files Browse the repository at this point in the history
* add idx user id

* Update modules/idxIdSystem.js to match new SubmoduleConfig param

Co-authored-by: Scott <smenzer@gmail.com>

Co-authored-by: Scott <smenzer@gmail.com>
  • Loading branch information
rtoscani and smenzer committed Oct 8, 2020
1 parent 752bd27 commit 7d27095
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 1 deletion.
1 change: 1 addition & 0 deletions modules/.submodules.json
Expand Up @@ -16,6 +16,7 @@
"zeotapIdPlusIdSystem",
"haloIdSystem",
"quantcastIdSystem",
"idxIdSystem",
"fabrickIdSystem"
],
"adpod": [
Expand Down
61 changes: 61 additions & 0 deletions modules/idxIdSystem.js
@@ -0,0 +1,61 @@
/**
* This module adds IDx to the User ID module
* The {@link module:modules/userId} module is required
* @module modules/idxIdSystem
* @requires module:modules/userId
*/
import * as utils from '../src/utils.js'
import { submodule } from '../src/hook.js';
import { getStorageManager } from '../src/storageManager.js';

const IDX_MODULE_NAME = 'idx';
const IDX_COOKIE_NAME = '_idx';
export const storage = getStorageManager();

function readIDxFromCookie() {
return storage.cookiesAreEnabled ? storage.getCookie(IDX_COOKIE_NAME) : null;
}

function readIDxFromLocalStorage() {
return storage.localStorageIsEnabled ? storage.getDataFromLocalStorage(IDX_COOKIE_NAME) : null;
}

/** @type {Submodule} */
export const idxIdSubmodule = {
/**
* used to link submodule with config
* @type {string}
*/
name: IDX_MODULE_NAME,
/**
* decode the stored id value for passing to bid requests
* @function
* @param { Object | string | undefined } value
* @return { Object | string | undefined }
*/
decode(value) {
const idxVal = value ? utils.isStr(value) ? value : utils.isPlainObject(value) ? value.id : undefined : undefined;
return idxVal ? {
'idx': idxVal
} : undefined;
},
/**
* performs action to obtain id and return a value in the callback's response argument
* @function
* @param {SubmoduleConfig} config
* @return {{id: string | undefined } | undefined}
*/
getId() {
const idxString = readIDxFromLocalStorage() || readIDxFromCookie();
if (typeof idxString == 'string' && idxString) {
try {
const idxObj = JSON.parse(idxString);
return idxObj && idxObj.idx ? { id: idxObj.idx } : undefined;
} catch (error) {
utils.logError(error);
}
}
return undefined;
}
};
submodule('userId', idxIdSubmodule);
22 changes: 22 additions & 0 deletions modules/idxIdSystem.md
@@ -0,0 +1,22 @@
## IDx User ID Submodule

For assistance setting up your module please contact us at [prebid@idx.lat](prebid@idx.lat).

### Prebid Params

Individual params may be set for the IDx Submodule.
```
pbjs.setConfig({
userSync: {
userIds: [{
name: 'idx',
}]
}
});
```
## Parameter Descriptions for the `userSync` Configuration Section
The below parameters apply only to the IDx integration.

| Param under usersync.userIds[] | Scope | Type | Description | Example |
| --- | --- | --- | --- | --- |
| name | Required | String | ID of the module - `"idx"` | `"idx"` |
8 changes: 7 additions & 1 deletion modules/userId/eids.js
Expand Up @@ -150,7 +150,13 @@ const USER_IDS_CONFIG = {
'quantcastId': {
source: 'quantcast.com',
atype: 1
}
},

// IDx
'idx': {
source: 'idx.lat',
atype: 1
},
};

// this function will create an eid object for the given UserId sub-module
Expand Down
117 changes: 117 additions & 0 deletions test/spec/modules/idxIdSystem_spec.js
@@ -0,0 +1,117 @@
import { expect } from 'chai';
import find from 'core-js-pure/features/array/find.js';
import { config } from 'src/config.js';
import { init, requestBidsHook, setSubmoduleRegistry } from 'modules/userId/index.js';
import { storage, idxIdSubmodule } from 'modules/idxIdSystem.js';

const IDX_COOKIE_NAME = '_idx';
const IDX_DUMMY_VALUE = 'idx value for testing';
const IDX_COOKIE_STORED = '{ "idx": "' + IDX_DUMMY_VALUE + '" }';
const ID_COOKIE_OBJECT = { id: IDX_DUMMY_VALUE };
const IDX_COOKIE_OBJECT = { idx: IDX_DUMMY_VALUE };

function getConfigMock() {
return {
userSync: {
syncDelay: 0,
userIds: [{
name: 'idx'
}]
}
}
}

function getAdUnitMock(code = 'adUnit-code') {
return {
code,
mediaTypes: {banner: {}, native: {}},
sizes: [
[300, 200],
[300, 600]
],
bids: [{
bidder: 'sampleBidder',
params: { placementId: 'banner-only-bidder' }
}]
};
}

describe('IDx ID System', () => {
let getDataFromLocalStorageStub, localStorageIsEnabledStub;
let getCookieStub, cookiesAreEnabledStub;

beforeEach(() => {
getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage');
localStorageIsEnabledStub = sinon.stub(storage, 'localStorageIsEnabled');
getCookieStub = sinon.stub(storage, 'getCookie');
cookiesAreEnabledStub = sinon.stub(storage, 'cookiesAreEnabled');
});

afterEach(() => {
getDataFromLocalStorageStub.restore();
localStorageIsEnabledStub.restore();
getCookieStub.restore();
cookiesAreEnabledStub.restore();
});

describe('IDx: test "getId" method', () => {
it('provides the stored IDx if a cookie exists', () => {
getCookieStub.withArgs(IDX_COOKIE_NAME).returns(IDX_COOKIE_STORED);
let idx = idxIdSubmodule.getId();
expect(idx).to.deep.equal(ID_COOKIE_OBJECT);
});

it('provides the stored IDx if cookie is absent but present in local storage', () => {
getDataFromLocalStorageStub.withArgs(IDX_COOKIE_NAME).returns(IDX_COOKIE_STORED);
let idx = idxIdSubmodule.getId();
expect(idx).to.deep.equal(ID_COOKIE_OBJECT);
});

it('returns undefined if both cookie and local storage are empty', () => {
let idx = idxIdSubmodule.getId();
expect(idx).to.be.undefined;
})
});

describe('IDx: test "decode" method', () => {
it('provides the IDx from a stored object', () => {
expect(idxIdSubmodule.decode(ID_COOKIE_OBJECT)).to.deep.equal(IDX_COOKIE_OBJECT);
});

it('provides the IDx from a stored string', () => {
expect(idxIdSubmodule.decode(IDX_DUMMY_VALUE)).to.deep.equal(IDX_COOKIE_OBJECT);
});
});

describe('requestBids hook', () => {
let adUnits;

beforeEach(() => {
adUnits = [getAdUnitMock()];
setSubmoduleRegistry([idxIdSubmodule]);
init(config);
config.setConfig(getConfigMock());
getCookieStub.withArgs(IDX_COOKIE_NAME).returns(IDX_COOKIE_STORED);
});

it('when a stored IDx exists it is added to bids', (done) => {
requestBidsHook(() => {
adUnits.forEach(unit => {
unit.bids.forEach(bid => {
expect(bid).to.have.deep.nested.property('userId.idx');
expect(bid.userId.idx).to.equal(IDX_DUMMY_VALUE);
const idxIdAsEid = find(bid.userIdAsEids, e => e.source == 'idx.lat');
expect(idxIdAsEid).to.deep.equal({
source: 'idx.lat',
uids: [{
id: IDX_DUMMY_VALUE,
atype: 1,
}]
});
});
});
done();
}, { adUnits });
});
});
});

0 comments on commit 7d27095

Please sign in to comment.