Skip to content

Commit c154c9e

Browse files
authored
[MOB-11504] Fix Persistent Scrollbar in In-App Message Iframes (#527)
* [MOB-11504] Fix Persistent Scrollbar in In-App Message Iframes * [MOB-11504] Remove BASE_URL from react sample app env.example * [MOB-11504] Add unit tests
1 parent 3948ff5 commit c154c9e

File tree

3 files changed

+75
-5
lines changed

3 files changed

+75
-5
lines changed

react-example/.env.example

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
# API_KEY=1234
77
# JWT_SECRET=1234
88

9-
# Only set BASE_URL if developing locally, as it will take precedence over the production api urls.
10-
# BASE_URL="https://api.iterable.com/api"
11-
129
# You may authenticate with JWT; be sure to use an API key that is configured to require JWT.
1310
# USE_JWT=true
1411

src/inapp/inapp.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,24 @@ export function getInAppMessages(
175175

176176
const throttledResize =
177177
messagePosition !== 'Full'
178-
? throttle(750, () => {
178+
? throttle(100, () => {
179+
const iframeBody = activeIframeDocument?.body;
180+
if (!iframeBody) return;
181+
182+
/** Hide overflow to prevent scrollbar affecting height determination */
183+
const originalOverflow = iframeBody.style.overflow;
184+
const shouldHideOverflow = originalOverflow !== 'hidden';
185+
if (shouldHideOverflow) iframeBody.style.overflow = 'hidden';
186+
187+
/** Set the height of the iframe to the height of the iframe body */
179188
activeIframe.style.height = `${
180-
activeIframeDocument?.body?.scrollHeight || 0
189+
iframeBody.scrollHeight || 0
181190
}px`;
191+
192+
/** Restore overflow after new height is set */
193+
if (shouldHideOverflow) {
194+
iframeBody.style.overflow = originalOverflow;
195+
}
182196
})
183197
: () => null;
184198
global.addEventListener('resize', throttledResize);

src/inapp/tests/inapp.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,5 +1252,64 @@ describe('getInAppMessages', () => {
12521252
// Note: sendBeacon property is used internally by the authorization system
12531253
// but not preserved in the mock request history, so we don't test it here
12541254
});
1255+
1256+
it('should resize iframe and restore/hide overflow when necessary', async () => {
1257+
mockRequest.onGet(GETMESSAGES_PATH).reply(200, {
1258+
inAppMessages: [
1259+
{
1260+
...messages[0],
1261+
content: {
1262+
...messages[0].content,
1263+
html: '<div style="height: 500px">hello</div>'
1264+
}
1265+
}
1266+
]
1267+
});
1268+
const { request } = getInAppMessages(
1269+
{ count: 10, packageName: 'my-lil-website' },
1270+
{ display: DisplayOptions.Immediate }
1271+
);
1272+
await request();
1273+
1274+
const iframe = document.getElementById(
1275+
'iterable-iframe'
1276+
) as HTMLIFrameElement;
1277+
const iframeBody = iframe?.contentWindow?.document.body;
1278+
if (iframeBody) {
1279+
Object.defineProperty(iframeBody, 'scrollHeight', {
1280+
value: 500,
1281+
writable: true
1282+
});
1283+
Object.defineProperty(iframeBody, 'offsetHeight', {
1284+
value: 400,
1285+
writable: true
1286+
});
1287+
iframeBody.style.overflow = 'scroll';
1288+
}
1289+
1290+
global.dispatchEvent(new Event('resize'));
1291+
jest.advanceTimersByTime(100);
1292+
1293+
expect(iframe.style.height).toBe('500px');
1294+
expect(iframeBody?.style.overflow).toBe('scroll');
1295+
1296+
if (iframeBody) {
1297+
Object.defineProperty(iframeBody, 'scrollHeight', {
1298+
value: 500,
1299+
writable: true
1300+
});
1301+
Object.defineProperty(iframeBody, 'offsetHeight', {
1302+
value: 900,
1303+
writable: true
1304+
});
1305+
iframeBody.style.overflow = 'hidden';
1306+
}
1307+
1308+
global.dispatchEvent(new Event('resize'));
1309+
jest.advanceTimersByTime(100);
1310+
1311+
expect(iframe.style.height).toBe('500px');
1312+
expect(iframeBody?.style.overflow).toBe('hidden');
1313+
});
12551314
});
12561315
});

0 commit comments

Comments
 (0)