Skip to content

Commit 7582618

Browse files
authored
Merge pull request #376 from auth0/delay-iframe-removal
[SDK-1127] Delay removal of iframe to prevent Chrome hanging status bug #240
2 parents 57f4b4a + 55b9bbf commit 7582618

File tree

4 files changed

+45
-29
lines changed

4 files changed

+45
-29
lines changed

__tests__/cache.test.ts

+18
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,24 @@ import Cache from '../src/cache';
22

33
describe('cache', () => {
44
let cache: Cache;
5+
let OriginalDate: Date;
6+
7+
beforeEach(() => {
8+
OriginalDate = (<any>global).Date;
9+
(<any>global).Date = class {
10+
time: number;
11+
constructor(time: number) {
12+
this.time = time;
13+
}
14+
getTime() {
15+
return this.time || 0;
16+
}
17+
};
18+
});
19+
afterEach(() => {
20+
(<any>global).Date = OriginalDate;
21+
});
22+
523
beforeEach(() => {
624
cache = new Cache();
725
jest.useFakeTimers();

__tests__/utils.test.ts

+12-27
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,9 @@ describe('utils', () => {
502502
}
503503
};
504504
const { iframe, url } = setup(message);
505+
jest.useFakeTimers();
505506
await runIframe(url, origin);
506-
507+
jest.runAllTimers();
507508
expect(message.source.close).toHaveBeenCalled();
508509
expect(window.document.body.appendChild).toHaveBeenCalledWith(iframe);
509510
expect(window.document.body.removeChild).toHaveBeenCalledWith(iframe);
@@ -524,20 +525,10 @@ describe('utils', () => {
524525
].forEach(m => {
525526
it(`ignores invalid messages: ${JSON.stringify(m)}`, async () => {
526527
const { iframe, url, origin } = setup(m);
527-
/**
528-
* We need to run the timers after we start `runIframe` to simulate
529-
* the window event listener, but we also need to use `jest.useFakeTimers`
530-
* to trigger the timeout. That's why we're using a real `setTimeout`,
531-
* then using fake timers then rolling back to real timers
532-
*/
533-
setTimeout(() => {
534-
jest.runAllTimers();
535-
}, 10);
536528
jest.useFakeTimers();
537-
await expect(runIframe(url, origin)).rejects.toMatchObject(
538-
TIMEOUT_ERROR
539-
);
540-
jest.useRealTimers();
529+
const promise = runIframe(url, origin);
530+
jest.runAllTimers();
531+
await expect(promise).rejects.toMatchObject(TIMEOUT_ERROR);
541532
expect(window.document.body.removeChild).toHaveBeenCalledWith(iframe);
542533
});
543534
});
@@ -553,9 +544,11 @@ describe('utils', () => {
553544
}
554545
};
555546
const { iframe, url } = setup(message);
547+
jest.useFakeTimers();
556548
await expect(runIframe(url, origin)).resolves.toMatchObject(
557549
message.data.response
558550
);
551+
jest.runAllTimers();
559552
expect(message.source.close).toHaveBeenCalled();
560553
expect(window.document.body.removeChild).toHaveBeenCalledWith(iframe);
561554
});
@@ -570,30 +563,22 @@ describe('utils', () => {
570563
}
571564
};
572565
const { iframe, url } = setup(message);
566+
jest.useFakeTimers();
573567
await expect(runIframe(url, origin)).rejects.toMatchObject(
574568
message.data.response
575569
);
570+
jest.runAllTimers();
576571
expect(message.source.close).toHaveBeenCalled();
577572
expect(window.document.body.removeChild).toHaveBeenCalledWith(iframe);
578573
});
579574
it('times out after timeoutInSeconds', async () => {
580575
const { iframe, url, origin } = setup('');
581576
const seconds = 10;
582-
/**
583-
* We need to run the timers after we start `runIframe` to simulate
584-
* the window event listener, but we also need to use `jest.useFakeTimers`
585-
* to trigger the timeout. That's why we're using a real `setTimeout`,
586-
* then using fake timers then rolling back to real timers
587-
*/
588-
setTimeout(() => {
589-
jest.runTimersToTime(seconds * 1000);
590-
}, 10);
591577
jest.useFakeTimers();
592-
await expect(runIframe(url, origin, seconds)).rejects.toMatchObject(
593-
TIMEOUT_ERROR
594-
);
578+
const promise = runIframe(url, origin, seconds);
579+
jest.runTimersToTime(seconds * 1000);
580+
await expect(promise).rejects.toMatchObject(TIMEOUT_ERROR);
595581
expect(window.document.body.removeChild).toHaveBeenCalledWith(iframe);
596-
jest.useRealTimers();
597582
});
598583
});
599584
describe('getCrypto', () => {

src/constants.ts

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
*/
44
export const DEFAULT_AUTHORIZE_TIMEOUT_IN_SECONDS = 60;
55

6+
/**
7+
* @ignore
8+
*/
9+
export const CLEANUP_IFRAME_TIMEOUT_IN_SECONDS = 2;
10+
611
/**
712
* @ignore
813
*/

src/utils.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import fetch from 'unfetch';
22

3-
import { DEFAULT_AUTHORIZE_TIMEOUT_IN_SECONDS } from './constants';
3+
import {
4+
DEFAULT_AUTHORIZE_TIMEOUT_IN_SECONDS,
5+
CLEANUP_IFRAME_TIMEOUT_IN_SECONDS
6+
} from './constants';
47

58
const dedupe = arr => arr.filter((x, i) => arr.indexOf(x) === i);
69

@@ -54,7 +57,12 @@ export const runIframe = (
5457
e.data.response.error ? rej(e.data.response) : res(e.data.response);
5558
clearTimeout(timeoutSetTimeoutId);
5659
window.removeEventListener('message', iframeEventHandler, false);
57-
window.document.body.removeChild(iframe);
60+
// Delay the removal of the iframe to prevent hanging loading status
61+
// in Chrome: https://github.com/auth0/auth0-spa-js/issues/240
62+
setTimeout(
63+
() => window.document.body.removeChild(iframe),
64+
CLEANUP_IFRAME_TIMEOUT_IN_SECONDS * 1000
65+
);
5866
};
5967
window.addEventListener('message', iframeEventHandler, false);
6068
window.document.body.appendChild(iframe);

0 commit comments

Comments
 (0)