Skip to content

Commit 740e8d2

Browse files
SKOCHERIskocheri
authored and
Chris Pabst
committed
id Import Library: update with more params to capture email (prebid#7772)
* 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 <[email protected]>
1 parent 13939b5 commit 740e8d2

File tree

3 files changed

+246
-18
lines changed

3 files changed

+246
-18
lines changed

modules/idImportLibrary.js

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ let conf;
99
const LOG_PRE_FIX = 'ID-Library: ';
1010
const CONF_DEFAULT_OBSERVER_DEBOUNCE_MS = 250;
1111
const CONF_DEFAULT_FULL_BODY_SCAN = false;
12+
const CONF_DEFAULT_INPUT_SCAN = false;
1213
const OBSERVER_CONFIG = {
1314
subtree: true,
1415
attributes: true,
@@ -78,7 +79,13 @@ function targetAction(mutations, observer) {
7879
}
7980
}
8081

81-
function addInputElementsElementListner(conf) {
82+
function addInputElementsElementListner() {
83+
if (doesInputElementsHaveEmail()) {
84+
_logInfo('Email found in input elements ' + email);
85+
_logInfo('Post data on email found in target without');
86+
postData();
87+
return;
88+
}
8289
_logInfo('Adding input element listeners');
8390
const inputs = document.querySelectorAll('input[type=text], input[type=email]');
8491

@@ -89,6 +96,19 @@ function addInputElementsElementListner(conf) {
8996
}
9097
}
9198

99+
function addFormInputElementsElementListner(id) {
100+
_logInfo('Adding input element listeners');
101+
if (doesFormInputElementsHaveEmail(id)) {
102+
_logInfo('Email found in input elements ' + email);
103+
postData();
104+
return;
105+
}
106+
_logInfo('Adding input element listeners');
107+
const input = document.getElementById(id);
108+
input.addEventListener('change', event => processInputChange(event));
109+
input.addEventListener('blur', event => processInputChange(event));
110+
}
111+
92112
function removeInputElementsElementListner() {
93113
_logInfo('Removing input element listeners');
94114
const inputs = document.querySelectorAll('input[type=text], input[type=email]');
@@ -149,20 +169,14 @@ function handleTargetElement() {
149169
}
150170

151171
function handleBodyElements() {
152-
if (doesInputElementsHaveEmail()) {
153-
_logInfo('Email found in input elements ' + email);
154-
_logInfo('Post data on email found in target without');
155-
postData();
156-
return;
157-
}
158172
email = getEmail(document.body.innerHTML);
159173
if (email !== null) {
160174
_logInfo('Email found in body ' + email);
161175
_logInfo('Post data on email found in the body without observer');
162176
postData();
163177
return;
164178
}
165-
addInputElementsElementListner();
179+
166180
if (conf.fullscan === true) {
167181
const bodyObserver = new MutationObserver(debounce(bodyAction, conf.debounce, false));
168182
bodyObserver.observe(document.body, OBSERVER_CONFIG);
@@ -182,6 +196,17 @@ function doesInputElementsHaveEmail() {
182196
return false;
183197
}
184198

199+
function doesFormInputElementsHaveEmail(formElementId) {
200+
const input = document.getElementById(formElementId);
201+
if (input) {
202+
email = getEmail(input.value);
203+
if (email !== null) {
204+
return true;
205+
}
206+
}
207+
return false;
208+
}
209+
185210
function syncCallback() {
186211
return {
187212
success: function () {
@@ -213,6 +238,10 @@ function associateIds() {
213238
if (window.MutationObserver || window.WebKitMutationObserver) {
214239
if (conf.target) {
215240
handleTargetElement();
241+
} else if (conf.formElementId) {
242+
addFormInputElementsElementListner(conf.formElementId);
243+
} else if (conf.inputscan) {
244+
addInputElementsElementListner();
216245
} else {
217246
handleBodyElements();
218247
}
@@ -236,6 +265,14 @@ export function setConfig(config) {
236265
config.fullscan = CONF_DEFAULT_FULL_BODY_SCAN;
237266
_logInfo('Set default fullscan ' + CONF_DEFAULT_FULL_BODY_SCAN);
238267
}
268+
if (typeof config.inputscan !== 'boolean') {
269+
config.inputscan = CONF_DEFAULT_INPUT_SCAN;
270+
_logInfo('Set default input scan ' + CONF_DEFAULT_INPUT_SCAN);
271+
}
272+
273+
if (typeof config.formElementId == 'string') {
274+
_logInfo('Looking for formElementId ' + config.formElementId);
275+
}
239276
conf = config;
240277
associateIds();
241278
}

modules/idImportLibrary.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
| `url` | Yes | String | N/A | URL endpoint used to post the hashed email and user IDs. |
99
| `debounce` | No | Number | 250 | Time in milliseconds before the email and IDs are fetched. |
1010
| `fullscan` | No | Boolean | false | Enable/disable a full page body scan to get email. |
11+
| `formElementId` | No | String | N/A | ID attribute of the input (type=text/email) from which the email can be read. |
12+
| `inputscan` | No | Boolean | N/A | Enable/disable a input element (type=text/email) scan to get email. |
1113

1214
## Example
1315

@@ -18,5 +20,7 @@ pbjs.setConfig({
1820
url: 'https://example.com',
1921
debounce: 250,
2022
fullscan: false,
23+
inputscan: false,
24+
formElementId: "userid"
2125
},
2226
});

test/spec/modules/idImportLibrary_spec.js

Lines changed: 197 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,28 @@ import * as idImportlibrary from 'modules/idImportLibrary.js';
33

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

6-
describe('currency', function () {
7-
let fakeCurrencyFileServer;
6+
const mockMutationObserver = {
7+
observe: () => {
8+
return null
9+
}
10+
}
11+
12+
describe('IdImportLibrary Tests', function () {
13+
let fakeServer;
814
let sandbox;
915
let clock;
10-
1116
let fn = sinon.spy();
1217

1318
beforeEach(function () {
14-
fakeCurrencyFileServer = sinon.fakeServer.create();
19+
fakeServer = sinon.fakeServer.create();
1520
sinon.stub(utils, 'logInfo');
1621
sinon.stub(utils, 'logError');
1722
});
1823

1924
afterEach(function () {
2025
utils.logInfo.restore();
2126
utils.logError.restore();
22-
fakeCurrencyFileServer.restore();
27+
fakeServer.restore();
2328
idImportlibrary.setConfig({});
2429
});
2530

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

37-
it('results when no config available', function () {
42+
it('results when no config is set', function () {
43+
idImportlibrary.setConfig();
44+
sinon.assert.called(utils.logError);
45+
});
46+
it('results when config is empty', function () {
3847
idImportlibrary.setConfig({});
3948
sinon.assert.called(utils.logError);
4049
});
41-
it('results with config available', function () {
42-
idImportlibrary.setConfig({ 'url': 'URL' });
50+
it('results with config available with url and debounce', function () {
51+
idImportlibrary.setConfig({ 'url': 'URL', 'debounce': 0 });
4352
sinon.assert.called(utils.logInfo);
4453
});
54+
it('results with config debounce ', function () {
55+
let config = { 'url': 'URL', 'debounce': 300 }
56+
idImportlibrary.setConfig(config);
57+
expect(config.debounce).to.be.equal(300);
58+
});
59+
4560
it('results with config default debounce ', function () {
4661
let config = { 'url': 'URL' }
4762
idImportlibrary.setConfig(config);
4863
expect(config.debounce).to.be.equal(250);
4964
});
5065
it('results with config default fullscan ', function () {
51-
let config = { 'url': 'URL' }
66+
let config = { 'url': 'URL', 'debounce': 0 }
5267
idImportlibrary.setConfig(config);
5368
expect(config.fullscan).to.be.equal(false);
5469
});
5570
it('results with config fullscan ', function () {
56-
let config = { 'url': 'URL', 'fullscan': true }
71+
let config = { 'url': 'URL', 'fullscan': true, 'debounce': 0 }
72+
idImportlibrary.setConfig(config);
73+
expect(config.fullscan).to.be.equal(true);
74+
expect(config.inputscan).to.be.equal(false);
75+
});
76+
it('results with config inputscan ', function () {
77+
let config = { 'inputscan': true, 'debounce': 0 }
78+
idImportlibrary.setConfig(config);
79+
expect(config.inputscan).to.be.equal(true);
80+
});
81+
});
82+
describe('Test with email is found', function () {
83+
let mutationObserverStub;
84+
let userId;
85+
let refreshUserIdSpy;
86+
beforeEach(function() {
87+
let sandbox = sinon.createSandbox();
88+
refreshUserIdSpy = sinon.spy(window.$$PREBID_GLOBAL$$, 'refreshUserIds');
89+
clock = sinon.useFakeTimers(1046952000000); // 2003-03-06T12:00:00Z
90+
mutationObserverStub = sinon.stub(window, 'MutationObserver').returns(mockMutationObserver);
91+
userId = sandbox.stub(window.$$PREBID_GLOBAL$$, 'getUserIds').returns({id: {'MOCKID': '1111'}});
92+
fakeServer.respondWith('POST', 'URL', [200,
93+
{
94+
'Content-Type': 'application/json',
95+
'Access-Control-Allow-Origin': '*'
96+
},
97+
''
98+
]);
99+
});
100+
afterEach(function () {
101+
sandbox.restore();
102+
clock.restore();
103+
userId.restore();
104+
refreshUserIdSpy.restore();
105+
mutationObserverStub.restore();
106+
document.body.innerHTML = '';
107+
});
108+
109+
it('results with config fullscan with email found in html ', function () {
110+
document.body.innerHTML = '<body><div>[email protected]</div></body>';
111+
let config = { 'url': 'URL', 'fullscan': true, 'debounce': 0 }
112+
idImportlibrary.setConfig(config);
113+
expect(config.fullscan).to.be.equal(true);
114+
expect(config.inputscan).to.be.equal(false);
115+
expect(refreshUserIdSpy.calledOnce).to.equal(true);
116+
});
117+
118+
it('results with config fullscan with no email found in html ', function () {
119+
document.body.innerHTML = '<body><div>test</div></body>';
120+
let config = { 'url': 'URL', 'fullscan': true, 'debounce': 0 }
121+
idImportlibrary.setConfig(config);
122+
expect(config.fullscan).to.be.equal(true);
123+
expect(config.inputscan).to.be.equal(false);
124+
expect(refreshUserIdSpy.calledOnce).to.equal(false);
125+
});
126+
127+
it('results with config formElementId without listner ', function () {
128+
let config = { url: 'testUrl', 'formElementId': 'userid', 'debounce': 0 }
129+
document.body.innerHTML = '<body><input type="text" id="userid" value="[email protected]"></body>';
130+
idImportlibrary.setConfig(config);
131+
expect(config.formElementId).to.be.equal('userid');
132+
expect(refreshUserIdSpy.calledOnce).to.equal(true);
133+
});
134+
135+
it('results with config formElementId with listner ', function () {
136+
let config = { url: 'testUrl', 'formElementId': 'userid', 'debounce': 0 }
137+
document.body.innerHTML = '<body><input type="text" id="userid" value=""></body>';
138+
idImportlibrary.setConfig(config);
139+
expect(config.formElementId).to.be.equal('userid');
140+
expect(refreshUserIdSpy.calledOnce).to.equal(false);
141+
});
142+
143+
it('results with config target without listner ', function () {
144+
let config = { url: 'testUrl', 'target': 'userid', 'debounce': 0 }
145+
document.body.innerHTML = '<body><div id="userid">[email protected]<div></div></body>';
146+
idImportlibrary.setConfig(config);
147+
expect(config.target).to.be.equal('userid');
148+
expect(refreshUserIdSpy.calledOnce).to.equal(true);
149+
});
150+
it('results with config target with listner ', function () {
151+
let config = { url: 'testUrl', 'target': 'userid', 'debounce': 0 }
152+
document.body.innerHTML = '<body><div id="userid"><div></div></body>';
153+
idImportlibrary.setConfig(config);
154+
155+
expect(config.target).to.be.equal('userid');
156+
expect(refreshUserIdSpy.calledOnce).to.equal(false);
157+
});
158+
159+
it('results with config target with listner', function () {
160+
let config = { url: 'testUrl', 'target': 'userid', 'debounce': 0 }
161+
idImportlibrary.setConfig(config);
162+
document.body.innerHTML = '<body><div id="userid">[email protected]<div></div></body>';
163+
expect(config.target).to.be.equal('userid');
164+
expect(refreshUserIdSpy.calledOnce).to.equal(false);
165+
});
166+
it('results with config fullscan ', function () {
167+
let config = { url: 'testUrl', 'fullscan': true, 'debounce': 0 }
57168
idImportlibrary.setConfig(config);
169+
document.body.innerHTML = '<body><div id="userid"><div></div></body>';
58170
expect(config.fullscan).to.be.equal(true);
171+
expect(refreshUserIdSpy.calledOnce).to.equal(false);
172+
});
173+
it('results with config inputscan with listner', function () {
174+
let config = { url: 'testUrl', 'inputscan': true, 'debounce': 0 }
175+
var input = document.createElement('input');
176+
input.setAttribute('type', 'text');
177+
document.body.appendChild(input);
178+
idImportlibrary.setConfig(config);
179+
expect(config.inputscan).to.be.equal(true);
180+
input.setAttribute('value', '[email protected]');
181+
const inputEvent = new InputEvent('blur');
182+
input.dispatchEvent(inputEvent);
183+
expect(refreshUserIdSpy.calledOnce).to.equal(true);
184+
});
185+
186+
it('results with config inputscan with listner and no user ids ', function () {
187+
let config = { 'url': 'testUrl', 'inputscan': true, 'debounce': 0 }
188+
document.body.innerHTML = '<body><input id="userid" value=""></body>';
189+
idImportlibrary.setConfig(config);
190+
expect(config.inputscan).to.be.equal(true);
191+
expect(refreshUserIdSpy.calledOnce).to.equal(false);
192+
});
193+
194+
it('results with config inputscan with listner ', function () {
195+
let config = { 'url': 'testUrl', 'inputscan': true, 'debounce': 0 }
196+
document.body.innerHTML = '<body><input id="userid" type=text value=""></body>';
197+
idImportlibrary.setConfig(config);
198+
expect(config.inputscan).to.be.equal(true);
199+
expect(refreshUserIdSpy.calledOnce).to.equal(false);
200+
});
201+
202+
it('results with config inputscan without listner ', function () {
203+
let config = { 'url': 'testUrl', 'inputscan': true, 'debounce': 0 }
204+
document.body.innerHTML = '<body><input id="userid" value="[email protected]"></body>';
205+
idImportlibrary.setConfig(config);
206+
expect(config.inputscan).to.be.equal(true);
207+
expect(refreshUserIdSpy.calledOnce).to.equal(true);
208+
});
209+
});
210+
describe('Tests with no user ids', function () {
211+
let mutationObserverStub;
212+
let userId;
213+
let jsonSpy;
214+
beforeEach(function() {
215+
let sandbox = sinon.createSandbox();
216+
clock = sinon.useFakeTimers(1046952000000); // 2003-03-06T12:00:00Z
217+
mutationObserverStub = sinon.stub(window, 'MutationObserver');
218+
jsonSpy = sinon.spy(JSON, 'stringify');
219+
fakeServer.respondWith('POST', 'URL', [200,
220+
{
221+
'Content-Type': 'application/json',
222+
'Access-Control-Allow-Origin': '*'
223+
},
224+
''
225+
]);
226+
});
227+
afterEach(function () {
228+
sandbox.restore();
229+
clock.restore();
230+
jsonSpy.restore();
231+
mutationObserverStub.restore();
232+
});
233+
it('results with config inputscan without listner with no user ids ', function () {
234+
let config = { 'url': 'testUrl', 'inputscan': true, 'debounce': 0 }
235+
document.body.innerHTML = '<body><input id="userid" value="[email protected]"></body>';
236+
idImportlibrary.setConfig(config);
237+
expect(config.inputscan).to.be.equal(true);
238+
expect(jsonSpy.calledOnce).to.equal(false);
239+
});
240+
it('results with config inputscan without listner with no user ids ', function () {
241+
let config = { 'url': 'testUrl', 'inputscan': true, 'debounce': 0 }
242+
document.body.innerHTML = '<body><input id="userid"></body>';
243+
idImportlibrary.setConfig(config);
244+
expect(config.inputscan).to.be.equal(true);
245+
expect(jsonSpy.calledOnce).to.equal(false);
59246
});
60247
});
61248
});

0 commit comments

Comments
 (0)