Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/loadScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ export const loadScript = (
loaded = true;
runCallbacks();
};
embedScript.onerror = () => {
// Remove the failed script tag so a later loadScript call (e.g. a
// remount) is able to inject and retry it; otherwise isScriptInjected
// keeps returning true and the editor can never load on this page.
embedScript.remove();
console.error(
`react-email-editor: failed to load unlayer embed script from ${scriptUrl}`
);
};
document.head.appendChild(embedScript);
} else {
runCallbacks();
Expand Down
31 changes: 31 additions & 0 deletions test/loadScript.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { loadScript } from '../src/loadScript';

const scriptUrl = 'https://example.com/test-embed.js';

const getScript = () =>
document.querySelector(`script[src="${scriptUrl}"]`) as HTMLScriptElement | null;

it('removes a failed script tag so a later call can retry', () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
const callback = jest.fn();

loadScript(callback, scriptUrl);
const firstScript = getScript();
expect(firstScript).toBeTruthy();

// Simulate a network failure loading the embed script.
firstScript!.dispatchEvent(new Event('error'));

expect(getScript()).toBeNull();
expect(callback).not.toHaveBeenCalled();

// A subsequent call (e.g. a remount) injects the script again.
loadScript(callback, scriptUrl);
const secondScript = getScript();
expect(secondScript).toBeTruthy();

secondScript!.dispatchEvent(new Event('load'));

// Both queued callbacks run once the script finally loads.
expect(callback).toHaveBeenCalledTimes(2);
});