|
| 1 | +import * as pubmaticBidAdapter from 'modules/pubmaticBidAdapter.js'; |
1 | 2 | import { expect } from 'chai';
|
2 |
| -import { spec, cpmAdjustment } from 'modules/pubmaticBidAdapter.js'; |
| 3 | +import { spec, cpmAdjustment, _getViewability, addViewabilityToImp, _isViewabilityMeasurable } from 'modules/pubmaticBidAdapter.js'; |
3 | 4 | import * as utils from 'src/utils.js';
|
4 | 5 | import { bidderSettings } from 'src/bidderSettings.js';
|
5 | 6 |
|
@@ -276,7 +277,7 @@ describe('PubMatic adapter', () => {
|
276 | 277 | const { imp } = request?.data;
|
277 | 278 | expect(imp).to.be.an('array');
|
278 | 279 | expect(imp[0]).to.have.property('banner').to.have.property('format');
|
279 |
| - expect(imp[0]).to.have.property('banner').to.have.property('format').with.lengthOf(2); |
| 280 | + expect(imp[0]).to.have.property('banner').to.have.property('format').to.be.an('array'); |
280 | 281 | });
|
281 | 282 |
|
282 | 283 | it('should add pmZoneId in ext if pmzoneid is present in parameters', () => {
|
@@ -1061,3 +1062,124 @@ describe('PubMatic adapter', () => {
|
1061 | 1062 | }
|
1062 | 1063 | })
|
1063 | 1064 | })
|
| 1065 | + |
| 1066 | +describe('_getViewability', () => { |
| 1067 | + let element; |
| 1068 | + let getBoundingClientRectStub; |
| 1069 | + let topWinMock; |
| 1070 | + |
| 1071 | + beforeEach(() => { |
| 1072 | + element = document.createElement('div'); |
| 1073 | + getBoundingClientRectStub = sinon.stub(element, 'getBoundingClientRect'); |
| 1074 | + topWinMock = { |
| 1075 | + innerWidth: 1000, |
| 1076 | + innerHeight: 800, |
| 1077 | + document: { visibilityState: 'visible' } |
| 1078 | + }; |
| 1079 | + }); |
| 1080 | + |
| 1081 | + afterEach(() => { |
| 1082 | + getBoundingClientRectStub.restore(); |
| 1083 | + }); |
| 1084 | + |
| 1085 | + it('should return 100 when element is fully in viewport', () => { |
| 1086 | + getBoundingClientRectStub.returns({ top: 0, left: 0, width: 300, height: 250, right: 300, bottom: 250 }); |
| 1087 | + const result = _getViewability(element, topWinMock, { w: 300, h: 250 }); |
| 1088 | + expect(result).to.equal(100); |
| 1089 | + }); |
| 1090 | + |
| 1091 | + it('should return 0 if document is not visible', () => { |
| 1092 | + topWinMock.document.visibilityState = 'hidden'; |
| 1093 | + getBoundingClientRectStub.returns({ top: 0, left: 0, width: 300, height: 250, right: 300, bottom: 250 }); |
| 1094 | + const result = _getViewability(element, topWinMock, { w: 300, h: 250 }); |
| 1095 | + expect(result).to.equal(0); |
| 1096 | + }); |
| 1097 | + |
| 1098 | + it('should return 0 if element is not in viewport at all', () => { |
| 1099 | + getBoundingClientRectStub.returns({ top: 2000, left: 2000, width: 300, height: 250, right: 2300, bottom: 2250 }); |
| 1100 | + const result = _getViewability(element, topWinMock, { w: 300, h: 250 }); |
| 1101 | + expect(result).to.equal(0); |
| 1102 | + }); |
| 1103 | + |
| 1104 | + it('should handle missing size object gracefully', () => { |
| 1105 | + getBoundingClientRectStub.returns({ top: 0, left: 0, width: 300, height: 250, right: 300, bottom: 250 }); |
| 1106 | + const result = _getViewability(element, topWinMock); |
| 1107 | + expect(result).to.be.a('number'); |
| 1108 | + }); |
| 1109 | + |
| 1110 | + it('should return the correct percentage if the element is partially in view', () => { |
| 1111 | + // Only 100x100 of the 200x200 element is visible in the viewport |
| 1112 | + const boundingBox = { left: 700, top: 500, right: 900, bottom: 700, width: 200, height: 200 }; |
| 1113 | + getBoundingClientRectStub.returns(boundingBox); |
| 1114 | + |
| 1115 | + // Stub getWinDimensions to simulate a viewport that only covers 800x600 (so only a quarter of the element is visible) |
| 1116 | + const getWinDimensionsStub = sinon.stub(utils, 'getWinDimensions'); |
| 1117 | + getWinDimensionsStub.returns({ innerWidth: 800, innerHeight: 600 }); |
| 1118 | + |
| 1119 | + // Call with the real window or a mock, as your percentInView implementation expects |
| 1120 | + const result = _getViewability(element, window, { w: 200, h: 200 }); |
| 1121 | + |
| 1122 | + expect(result).to.equal(25); // 100x100 / 200x200 = 0.25 -> 25% |
| 1123 | + getWinDimensionsStub.restore(); |
| 1124 | + }); |
| 1125 | +}); |
| 1126 | + |
| 1127 | +describe('addViewabilityToImp', () => { |
| 1128 | + let imp; |
| 1129 | + let element; |
| 1130 | + let originalGetElementById; |
| 1131 | + let originalVisibilityState; |
| 1132 | + let sandbox; |
| 1133 | + |
| 1134 | + beforeEach(() => { |
| 1135 | + sandbox = sinon.createSandbox(); |
| 1136 | + imp = { ext: {} }; |
| 1137 | + element = document.createElement('div'); |
| 1138 | + element.id = 'Div1'; |
| 1139 | + document.body.appendChild(element); |
| 1140 | + originalGetElementById = document.getElementById; |
| 1141 | + sandbox.stub(document, 'getElementById').callsFake(id => id === 'Div1' ? element : null); |
| 1142 | + originalVisibilityState = document.visibilityState; |
| 1143 | + Object.defineProperty(document, 'visibilityState', { |
| 1144 | + value: 'visible', |
| 1145 | + configurable: true |
| 1146 | + }); |
| 1147 | + sandbox.stub(require('src/utils.js'), 'getWindowTop').returns(window); |
| 1148 | + }); |
| 1149 | + |
| 1150 | + afterEach(() => { |
| 1151 | + sandbox.restore(); |
| 1152 | + document.body.removeChild(element); |
| 1153 | + Object.defineProperty(document, 'visibilityState', { |
| 1154 | + value: originalVisibilityState, |
| 1155 | + configurable: true |
| 1156 | + }); |
| 1157 | + document.getElementById = originalGetElementById; |
| 1158 | + }); |
| 1159 | + |
| 1160 | + it('should add viewability to imp.ext when measurable', () => { |
| 1161 | + addViewabilityToImp(imp, 'Div1', { w: 300, h: 250 }); |
| 1162 | + expect(imp.ext).to.have.property('viewability'); |
| 1163 | + }); |
| 1164 | + |
| 1165 | + it('should set viewability amount to "na" if not measurable (e.g., in iframe)', () => { |
| 1166 | + sandbox.stub(pubmaticBidAdapter, '_isViewabilityMeasurable').returns(false); |
| 1167 | + pubmaticBidAdapter.addViewabilityToImp(imp, 'Div1', { w: 300, h: 250 }); |
| 1168 | + expect(imp.ext).to.have.property('viewability'); |
| 1169 | + expect(imp.ext.viewability.amount).to.equal('na'); |
| 1170 | + }); |
| 1171 | + |
| 1172 | + it('should not add viewability if element is not found', () => { |
| 1173 | + document.getElementById.restore(); |
| 1174 | + sandbox.stub(document, 'getElementById').returns(null); |
| 1175 | + addViewabilityToImp(imp, 'Div1', { w: 300, h: 250 }); |
| 1176 | + expect(imp.ext).to.not.have.property('viewability'); |
| 1177 | + }); |
| 1178 | + |
| 1179 | + it('should create imp.ext if not present', () => { |
| 1180 | + imp = {}; |
| 1181 | + addViewabilityToImp(imp, 'Div1', { w: 300, h: 250 }); |
| 1182 | + expect(imp.ext).to.exist; |
| 1183 | + expect(imp.ext).to.have.property('viewability'); |
| 1184 | + }); |
| 1185 | +}); |
0 commit comments