Skip to content

Commit

Permalink
id Import Library: update with more params to capture email (prebid#7772
Browse files Browse the repository at this point in the history
)

* Updating IdImportLibrary with more parameters to get email ids

* Updating IdImportLibrary with more parameters to get email ids

* Updating unit test for IdImportLibrary

Co-authored-by: skocheri <skocheri@rubiconproject.com>
  • Loading branch information
2 people authored and Chris Pabst committed Jan 10, 2022
1 parent 13939b5 commit 740e8d2
Show file tree
Hide file tree
Showing 3 changed files with 246 additions and 18 deletions.
53 changes: 45 additions & 8 deletions modules/idImportLibrary.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ let conf;
const LOG_PRE_FIX = 'ID-Library: ';
const CONF_DEFAULT_OBSERVER_DEBOUNCE_MS = 250;
const CONF_DEFAULT_FULL_BODY_SCAN = false;
const CONF_DEFAULT_INPUT_SCAN = false;
const OBSERVER_CONFIG = {
subtree: true,
attributes: true,
Expand Down Expand Up @@ -78,7 +79,13 @@ function targetAction(mutations, observer) {
}
}

function addInputElementsElementListner(conf) {
function addInputElementsElementListner() {
if (doesInputElementsHaveEmail()) {
_logInfo('Email found in input elements ' + email);
_logInfo('Post data on email found in target without');
postData();
return;
}
_logInfo('Adding input element listeners');
const inputs = document.querySelectorAll('input[type=text], input[type=email]');

Expand All @@ -89,6 +96,19 @@ function addInputElementsElementListner(conf) {
}
}

function addFormInputElementsElementListner(id) {
_logInfo('Adding input element listeners');
if (doesFormInputElementsHaveEmail(id)) {
_logInfo('Email found in input elements ' + email);
postData();
return;
}
_logInfo('Adding input element listeners');
const input = document.getElementById(id);
input.addEventListener('change', event => processInputChange(event));
input.addEventListener('blur', event => processInputChange(event));
}

function removeInputElementsElementListner() {
_logInfo('Removing input element listeners');
const inputs = document.querySelectorAll('input[type=text], input[type=email]');
Expand Down Expand Up @@ -149,20 +169,14 @@ function handleTargetElement() {
}

function handleBodyElements() {
if (doesInputElementsHaveEmail()) {
_logInfo('Email found in input elements ' + email);
_logInfo('Post data on email found in target without');
postData();
return;
}
email = getEmail(document.body.innerHTML);
if (email !== null) {
_logInfo('Email found in body ' + email);
_logInfo('Post data on email found in the body without observer');
postData();
return;
}
addInputElementsElementListner();

if (conf.fullscan === true) {
const bodyObserver = new MutationObserver(debounce(bodyAction, conf.debounce, false));
bodyObserver.observe(document.body, OBSERVER_CONFIG);
Expand All @@ -182,6 +196,17 @@ function doesInputElementsHaveEmail() {
return false;
}

function doesFormInputElementsHaveEmail(formElementId) {
const input = document.getElementById(formElementId);
if (input) {
email = getEmail(input.value);
if (email !== null) {
return true;
}
}
return false;
}

function syncCallback() {
return {
success: function () {
Expand Down Expand Up @@ -213,6 +238,10 @@ function associateIds() {
if (window.MutationObserver || window.WebKitMutationObserver) {
if (conf.target) {
handleTargetElement();
} else if (conf.formElementId) {
addFormInputElementsElementListner(conf.formElementId);
} else if (conf.inputscan) {
addInputElementsElementListner();
} else {
handleBodyElements();
}
Expand All @@ -236,6 +265,14 @@ export function setConfig(config) {
config.fullscan = CONF_DEFAULT_FULL_BODY_SCAN;
_logInfo('Set default fullscan ' + CONF_DEFAULT_FULL_BODY_SCAN);
}
if (typeof config.inputscan !== 'boolean') {
config.inputscan = CONF_DEFAULT_INPUT_SCAN;
_logInfo('Set default input scan ' + CONF_DEFAULT_INPUT_SCAN);
}

if (typeof config.formElementId == 'string') {
_logInfo('Looking for formElementId ' + config.formElementId);
}
conf = config;
associateIds();
}
Expand Down
4 changes: 4 additions & 0 deletions modules/idImportLibrary.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
| `url` | Yes | String | N/A | URL endpoint used to post the hashed email and user IDs. |
| `debounce` | No | Number | 250 | Time in milliseconds before the email and IDs are fetched. |
| `fullscan` | No | Boolean | false | Enable/disable a full page body scan to get email. |
| `formElementId` | No | String | N/A | ID attribute of the input (type=text/email) from which the email can be read. |
| `inputscan` | No | Boolean | N/A | Enable/disable a input element (type=text/email) scan to get email. |

## Example

Expand All @@ -18,5 +20,7 @@ pbjs.setConfig({
url: 'https://example.com',
debounce: 250,
fullscan: false,
inputscan: false,
formElementId: "userid"
},
});
207 changes: 197 additions & 10 deletions test/spec/modules/idImportLibrary_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,28 @@ import * as idImportlibrary from 'modules/idImportLibrary.js';

var expect = require('chai').expect;

describe('currency', function () {
let fakeCurrencyFileServer;
const mockMutationObserver = {
observe: () => {
return null
}
}

describe('IdImportLibrary Tests', function () {
let fakeServer;
let sandbox;
let clock;

let fn = sinon.spy();

beforeEach(function () {
fakeCurrencyFileServer = sinon.fakeServer.create();
fakeServer = sinon.fakeServer.create();
sinon.stub(utils, 'logInfo');
sinon.stub(utils, 'logError');
});

afterEach(function () {
utils.logInfo.restore();
utils.logError.restore();
fakeCurrencyFileServer.restore();
fakeServer.restore();
idImportlibrary.setConfig({});
});

Expand All @@ -34,28 +39,210 @@ describe('currency', function () {
clock.restore();
});

it('results when no config available', function () {
it('results when no config is set', function () {
idImportlibrary.setConfig();
sinon.assert.called(utils.logError);
});
it('results when config is empty', function () {
idImportlibrary.setConfig({});
sinon.assert.called(utils.logError);
});
it('results with config available', function () {
idImportlibrary.setConfig({ 'url': 'URL' });
it('results with config available with url and debounce', function () {
idImportlibrary.setConfig({ 'url': 'URL', 'debounce': 0 });
sinon.assert.called(utils.logInfo);
});
it('results with config debounce ', function () {
let config = { 'url': 'URL', 'debounce': 300 }
idImportlibrary.setConfig(config);
expect(config.debounce).to.be.equal(300);
});

it('results with config default debounce ', function () {
let config = { 'url': 'URL' }
idImportlibrary.setConfig(config);
expect(config.debounce).to.be.equal(250);
});
it('results with config default fullscan ', function () {
let config = { 'url': 'URL' }
let config = { 'url': 'URL', 'debounce': 0 }
idImportlibrary.setConfig(config);
expect(config.fullscan).to.be.equal(false);
});
it('results with config fullscan ', function () {
let config = { 'url': 'URL', 'fullscan': true }
let config = { 'url': 'URL', 'fullscan': true, 'debounce': 0 }
idImportlibrary.setConfig(config);
expect(config.fullscan).to.be.equal(true);
expect(config.inputscan).to.be.equal(false);
});
it('results with config inputscan ', function () {
let config = { 'inputscan': true, 'debounce': 0 }
idImportlibrary.setConfig(config);
expect(config.inputscan).to.be.equal(true);
});
});
describe('Test with email is found', function () {
let mutationObserverStub;
let userId;
let refreshUserIdSpy;
beforeEach(function() {
let sandbox = sinon.createSandbox();
refreshUserIdSpy = sinon.spy(window.$$PREBID_GLOBAL$$, 'refreshUserIds');
clock = sinon.useFakeTimers(1046952000000); // 2003-03-06T12:00:00Z
mutationObserverStub = sinon.stub(window, 'MutationObserver').returns(mockMutationObserver);
userId = sandbox.stub(window.$$PREBID_GLOBAL$$, 'getUserIds').returns({id: {'MOCKID': '1111'}});
fakeServer.respondWith('POST', 'URL', [200,
{
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
''
]);
});
afterEach(function () {
sandbox.restore();
clock.restore();
userId.restore();
refreshUserIdSpy.restore();
mutationObserverStub.restore();
document.body.innerHTML = '';
});

it('results with config fullscan with email found in html ', function () {
document.body.innerHTML = '<body><div>test@test.com</div></body>';
let config = { 'url': 'URL', 'fullscan': true, 'debounce': 0 }
idImportlibrary.setConfig(config);
expect(config.fullscan).to.be.equal(true);
expect(config.inputscan).to.be.equal(false);
expect(refreshUserIdSpy.calledOnce).to.equal(true);
});

it('results with config fullscan with no email found in html ', function () {
document.body.innerHTML = '<body><div>test</div></body>';
let config = { 'url': 'URL', 'fullscan': true, 'debounce': 0 }
idImportlibrary.setConfig(config);
expect(config.fullscan).to.be.equal(true);
expect(config.inputscan).to.be.equal(false);
expect(refreshUserIdSpy.calledOnce).to.equal(false);
});

it('results with config formElementId without listner ', function () {
let config = { url: 'testUrl', 'formElementId': 'userid', 'debounce': 0 }
document.body.innerHTML = '<body><input type="text" id="userid" value="test@test.com"></body>';
idImportlibrary.setConfig(config);
expect(config.formElementId).to.be.equal('userid');
expect(refreshUserIdSpy.calledOnce).to.equal(true);
});

it('results with config formElementId with listner ', function () {
let config = { url: 'testUrl', 'formElementId': 'userid', 'debounce': 0 }
document.body.innerHTML = '<body><input type="text" id="userid" value=""></body>';
idImportlibrary.setConfig(config);
expect(config.formElementId).to.be.equal('userid');
expect(refreshUserIdSpy.calledOnce).to.equal(false);
});

it('results with config target without listner ', function () {
let config = { url: 'testUrl', 'target': 'userid', 'debounce': 0 }
document.body.innerHTML = '<body><div id="userid">test@test.com<div></div></body>';
idImportlibrary.setConfig(config);
expect(config.target).to.be.equal('userid');
expect(refreshUserIdSpy.calledOnce).to.equal(true);
});
it('results with config target with listner ', function () {
let config = { url: 'testUrl', 'target': 'userid', 'debounce': 0 }
document.body.innerHTML = '<body><div id="userid"><div></div></body>';
idImportlibrary.setConfig(config);

expect(config.target).to.be.equal('userid');
expect(refreshUserIdSpy.calledOnce).to.equal(false);
});

it('results with config target with listner', function () {
let config = { url: 'testUrl', 'target': 'userid', 'debounce': 0 }
idImportlibrary.setConfig(config);
document.body.innerHTML = '<body><div id="userid">test@test.com<div></div></body>';
expect(config.target).to.be.equal('userid');
expect(refreshUserIdSpy.calledOnce).to.equal(false);
});
it('results with config fullscan ', function () {
let config = { url: 'testUrl', 'fullscan': true, 'debounce': 0 }
idImportlibrary.setConfig(config);
document.body.innerHTML = '<body><div id="userid"><div></div></body>';
expect(config.fullscan).to.be.equal(true);
expect(refreshUserIdSpy.calledOnce).to.equal(false);
});
it('results with config inputscan with listner', function () {
let config = { url: 'testUrl', 'inputscan': true, 'debounce': 0 }
var input = document.createElement('input');
input.setAttribute('type', 'text');
document.body.appendChild(input);
idImportlibrary.setConfig(config);
expect(config.inputscan).to.be.equal(true);
input.setAttribute('value', 'text@text.com');
const inputEvent = new InputEvent('blur');
input.dispatchEvent(inputEvent);
expect(refreshUserIdSpy.calledOnce).to.equal(true);
});

it('results with config inputscan with listner and no user ids ', function () {
let config = { 'url': 'testUrl', 'inputscan': true, 'debounce': 0 }
document.body.innerHTML = '<body><input id="userid" value=""></body>';
idImportlibrary.setConfig(config);
expect(config.inputscan).to.be.equal(true);
expect(refreshUserIdSpy.calledOnce).to.equal(false);
});

it('results with config inputscan with listner ', function () {
let config = { 'url': 'testUrl', 'inputscan': true, 'debounce': 0 }
document.body.innerHTML = '<body><input id="userid" type=text value=""></body>';
idImportlibrary.setConfig(config);
expect(config.inputscan).to.be.equal(true);
expect(refreshUserIdSpy.calledOnce).to.equal(false);
});

it('results with config inputscan without listner ', function () {
let config = { 'url': 'testUrl', 'inputscan': true, 'debounce': 0 }
document.body.innerHTML = '<body><input id="userid" value="test@test.com"></body>';
idImportlibrary.setConfig(config);
expect(config.inputscan).to.be.equal(true);
expect(refreshUserIdSpy.calledOnce).to.equal(true);
});
});
describe('Tests with no user ids', function () {
let mutationObserverStub;
let userId;
let jsonSpy;
beforeEach(function() {
let sandbox = sinon.createSandbox();
clock = sinon.useFakeTimers(1046952000000); // 2003-03-06T12:00:00Z
mutationObserverStub = sinon.stub(window, 'MutationObserver');
jsonSpy = sinon.spy(JSON, 'stringify');
fakeServer.respondWith('POST', 'URL', [200,
{
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
''
]);
});
afterEach(function () {
sandbox.restore();
clock.restore();
jsonSpy.restore();
mutationObserverStub.restore();
});
it('results with config inputscan without listner with no user ids ', function () {
let config = { 'url': 'testUrl', 'inputscan': true, 'debounce': 0 }
document.body.innerHTML = '<body><input id="userid" value="test@test.com"></body>';
idImportlibrary.setConfig(config);
expect(config.inputscan).to.be.equal(true);
expect(jsonSpy.calledOnce).to.equal(false);
});
it('results with config inputscan without listner with no user ids ', function () {
let config = { 'url': 'testUrl', 'inputscan': true, 'debounce': 0 }
document.body.innerHTML = '<body><input id="userid"></body>';
idImportlibrary.setConfig(config);
expect(config.inputscan).to.be.equal(true);
expect(jsonSpy.calledOnce).to.equal(false);
});
});
});

0 comments on commit 740e8d2

Please sign in to comment.