Skip to content

Commit

Permalink
geolocationRtdProvider: fix geo.lastfix (prebid#10383)
Browse files Browse the repository at this point in the history
  • Loading branch information
dgirardi authored Aug 23, 2023
1 parent c0048a9 commit e804885
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 108 deletions.
6 changes: 2 additions & 4 deletions modules/geolocationRtdProvider.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {submodule} from '../src/hook.js';
import {isFn, logError, deepAccess, deepSetValue, logInfo, logWarn} from '../src/utils.js';
import {isFn, logError, deepAccess, deepSetValue, logInfo, logWarn, timestamp} from '../src/utils.js';
import { ACTIVITY_TRANSMIT_PRECISE_GEO } from '../src/activities/activities.js';
import { MODULE_TYPE_RTD } from '../src/activities/modules.js';
import { isActivityAllowed } from '../src/activities/rules.js';
Expand All @@ -18,7 +18,6 @@ function getGeolocationData(requestBidsObject, onDone, providerConfig, userConse
return complete()
};
const requestPermission = deepAccess(providerConfig, 'params.requestPermission') === true;
const waitForIt = providerConfig.waitForIt;
navigator.permissions.query({
name: 'geolocation',
}).then(permission => {
Expand All @@ -28,15 +27,14 @@ function getGeolocationData(requestBidsObject, onDone, providerConfig, userConse
complete();
});
});
if (!waitForIt) complete();
function complete() {
if (done) return;
done = true;
if (geolocation) {
deepSetValue(requestBidsObject, 'ortb2Fragments.global.device.geo', {
lat: geolocation.coords.latitude,
lon: geolocation.coords.longitude,
lastfix: geolocation.timestamp,
lastfix: Math.round((timestamp() - geolocation.timestamp) / 1000),
type: 1
});
logInfo('geolocation was successfully received ', requestBidsObject.ortb2Fragments.global.device.geo)
Expand Down
199 changes: 95 additions & 104 deletions test/spec/modules/geolocationRtdProvider_spec.js
Original file line number Diff line number Diff line change
@@ -1,119 +1,110 @@
import {config as _config, config} from 'src/config.js';
import { expect } from 'chai';
import * as events from 'src/events.js';
import * as prebidGlobal from 'src/prebidGlobal.js';
import { geolocationSubmodule } from 'modules/geolocationRtdProvider.js';
import * as utils from 'src/utils.js';
import {getGlobal} from 'src/prebidGlobal.js';
import {expect} from 'chai';
import {geolocationSubmodule} from 'modules/geolocationRtdProvider.js';
import * as activityRules from 'src/activities/rules.js';
import 'src/prebid.js';
import {GreedyPromise} from '../../../src/utils/promise.js';
import {ACTIVITY_TRANSMIT_PRECISE_GEO} from '../../../src/activities/activities.js';

describe('Geolocation RTD Provider', function () {
let sandbox;
let placeholder;
const pbjs = getGlobal();
const adUnit = {
code: 'ad-slot-1',
mediaTypes: {
banner: {
sizes: [ [300, 250] ]
}
},
bids: [
{
bidder: 'fake'
}
]
};
const providerConfig = {name: 'geolocation', waitForIt: true};
const rtdConfig = {realTimeData: {auctionDelay: 200, dataProviders: [providerConfig]}}

before(() => {
if (!navigator.permissions) {
navigator.permissions = {mock: true, query: false}
}
});

after(() => {
if (navigator.permissions.mock) {
delete navigator.permissions;
}
});

beforeEach(() => {
sandbox = sinon.sandbox.create();
});

afterEach(() => {
sandbox.restore();
})

describe('Geolocation not supported', function() {
beforeEach(function() {
sandbox = sinon.sandbox.create();
});
afterEach(function() {
sandbox.restore();
sandbox = undefined;
});
it('init should return false', function () {
if (navigator.permissions) { sandbox.stub(navigator.permissions, 'query').value(undefined); expect(geolocationSubmodule.init({})).is.false; }
Object.entries({
'permissions.query': () => sandbox.stub(navigator.permissions, 'query').value(undefined),
'permissions': () => sandbox.stub(navigator, 'permissions').value(undefined),
}).forEach(([t, setup]) => {
describe(`${t} not available`, () => {
beforeEach(setup);
it('init should return false', function () {
expect(geolocationSubmodule.init({})).is.false;
});
});
});
});

describe('Geolocation supported', function() {
beforeEach(function() {
sandbox = sinon.sandbox.create();
// placeholder = createDiv();
// append();
const __config = {};
sandbox.stub(_config, 'getConfig').callsFake(function (path) {
return utils.deepAccess(__config, path);
});
sandbox.stub(_config, 'setConfig').callsFake(function (obj) {
utils.mergeDeep(__config, obj);
let clock, rtdConfig, permState, onDone;

beforeEach(() => {
onDone = sinon.stub();
permState = 'prompt';
rtdConfig = {params: {}};
clock = sandbox.useFakeTimers(11000);
sandbox.stub(navigator.geolocation, 'getCurrentPosition').value((cb) => {
// eslint-disable-next-line standard/no-callback-literal
cb({coords: {latitude: 1, longitude: 2}, timestamp: 1000});
});
sandbox.stub(navigator.permissions, 'query').value(() => GreedyPromise.resolve({
state: permState,
}));
geolocationSubmodule.init(rtdConfig);
});
afterEach(function() {
sandbox.restore();
// remove();
sandbox = undefined;
placeholder = undefined;
pbjs.removeAdUnit();
});

it('init should return true', function () {
navigator.permissions && expect(geolocationSubmodule.init({})).is.true;
expect(geolocationSubmodule.init({})).is.true;
});
it('should set geolocation. (request all)', function(done) {
navigator.permissions && sandbox.stub(navigator.permissions, 'query').value(() => Promise.resolve({
state: 'granted',
}));
navigator.geolocation && sandbox.stub(navigator.geolocation, 'getCurrentPosition').value((cb) => {
// eslint-disable-next-line standard/no-callback-literal
cb({coords: {latitude: 1, longitude: 1}});
});
pbjs.addAdUnits([utils.deepClone(adUnit)]);
config.setConfig(rtdConfig);
const onDone = sandbox.stub();
const requestBidObject = {};
geolocationSubmodule.init({});
geolocationSubmodule.getBidRequestData(
requestBidObject,
onDone,
providerConfig
);
expect(pbjs.adUnits.length).to.eq(1);
setTimeout(function() {
// expect(requestBidObject?.ortb2Fragments?.global.device.geo?.type).to.eq(1);
done();
}, 300);
});
it('should call done due timeout', function(done) {
// sandbox.stub(navigator.permissions, 'query').value(() => new Promise(() => {}));
// sandbox.stub(navigator.geolocation, 'getCurrentPosition').value((cb) => {});
config.setConfig(rtdConfig);
// remove();
const onDone = sandbox.stub();
const requestBidObject = {adUnits: [utils.deepClone(adUnit)]};
geolocationSubmodule.init({});
geolocationSubmodule.getBidRequestData(
requestBidObject,
onDone,
{...providerConfig, test: 1}
);
setTimeout(function() {
sinon.assert.calledOnce(onDone);
expect(requestBidObject).to.not.have.property('ortb2Fragments.global.device.geo');
done();
}, 300);

Object.entries({
'not necessary, requestPermission not set': [undefined, 'granted'],
'not necessary, requestPermission = false': [false, 'granted'],
'required, with requestPermission = true': [true, 'prompt']
}).forEach(([t, [requestPermission, navPerm]]) => {
describe(`when browser permission is ${t}`, () => {
beforeEach(() => {
permState = navPerm;
rtdConfig.params.requestPermission = requestPermission;
});

it(`should set geolocation`, () => {
const requestBidObject = {ortb2Fragments: {global: {}}};
geolocationSubmodule.getBidRequestData(requestBidObject, onDone, rtdConfig);
clock.tick(300);
expect(onDone.called).to.be.true;
expect(requestBidObject.ortb2Fragments.global.device.geo).to.eql({
type: 1,
lat: 1,
lon: 2,
lastfix: 10
})
})
})
})

Object.entries({
'transmitPreciseGeo is denied': () => sandbox.stub(activityRules, 'isActivityAllowed').callsFake(activity => activity !== ACTIVITY_TRANSMIT_PRECISE_GEO),
'permissions are required, but requestPermission is not set': () => { delete rtdConfig.params.requestPermission; permState = 'prompt' },
'permissions are required, but requestPermission is false': () => { rtdConfig.params.requestPermission = false; permState = 'prompt' }
}).forEach(([t, setup]) => {
describe(`when ${t}`, () => {
beforeEach(setup);

it(`should NOT set geo`, () => {
const req = {ortb2Fragments: {global: {}}};
geolocationSubmodule.getBidRequestData(req, onDone, rtdConfig);
clock.tick(300);
expect(req.ortb2Fragments.global.device?.geo).to.not.exist;
})
})
});
});
// function createDiv() {
// const div = document.createElement('div');
// div.id = adUnit.code;
// return div;
// }
// function append() {
// placeholder && document.body.appendChild(placeholder);
// }
// function remove() {
// placeholder && placeholder.parentElement && placeholder.parentElement.removeChild(placeholder);
// }
});

0 comments on commit e804885

Please sign in to comment.