fix(client): handle missing document in preview frame (#44833)

This commit is contained in:
Oliver Eyton-Williams
2022-01-20 14:22:25 +01:00
committed by GitHub
parent 5aaf8677d4
commit f88473f994

View File

@ -9,6 +9,8 @@ const testId = 'fcc-test-frame';
// the project preview frame demos the finished project
export const projectPreviewId = 'fcc-project-preview-frame';
const DOCUMENT_NOT_FOUND_ERROR = 'document not found';
// base tag here will force relative links
// within iframe to point to '' instead of
// append to the current challenge url
@ -103,48 +105,60 @@ const buildProxyConsole = proxyLogger => ctx => {
};
const initTestFrame = frameReady => ctx => {
waitForFrame(ctx).then(async () => {
const { sources, loadEnzyme } = ctx;
// default for classic challenges
// should not be used for modern
const code = {
contents: sources.index,
editableContents: sources.editableContents
};
// provide the file name and get the original source
const getUserInput = fileName => toString(sources[fileName]);
await ctx.document.__initTestFrame({ code, getUserInput, loadEnzyme });
frameReady();
});
waitForFrame(ctx)
.then(async () => {
const { sources, loadEnzyme } = ctx;
// default for classic challenges
// should not be used for modern
const code = {
contents: sources.index,
editableContents: sources.editableContents
};
// provide the file name and get the original source
const getUserInput = fileName => toString(sources[fileName]);
await ctx.document.__initTestFrame({ code, getUserInput, loadEnzyme });
frameReady();
})
.catch(handleDocumentNotFound);
return ctx;
};
const initMainFrame = (_, proxyLogger) => ctx => {
waitForFrame(ctx).then(() => {
// Overwriting the onerror added by createHeader to catch any errors thrown
// after the frame is ready. It has to be overwritten, as proxyLogger cannot
// be added as part of createHeader.
ctx.window.onerror = function (msg) {
var string = msg.toLowerCase();
if (string.includes('script error')) {
msg = 'Error, open your browser console to learn more.';
}
if (proxyLogger) {
proxyLogger(msg);
}
// let the error propagate so it appears in the browser console, otherwise
// an error from a cross origin script just appears as 'Script error.'
return false;
};
});
waitForFrame(ctx)
.then(() => {
// Overwriting the onerror added by createHeader to catch any errors thrown
// after the frame is ready. It has to be overwritten, as proxyLogger cannot
// be added as part of createHeader.
ctx.window.onerror = function (msg) {
var string = msg.toLowerCase();
if (string.includes('script error')) {
msg = 'Error, open your browser console to learn more.';
}
if (proxyLogger) {
proxyLogger(msg);
}
// let the error propagate so it appears in the browser console, otherwise
// an error from a cross origin script just appears as 'Script error.'
return false;
};
})
.catch(handleDocumentNotFound);
return ctx;
};
function handleDocumentNotFound(err) {
if (err !== DOCUMENT_NOT_FOUND_ERROR) {
console.log(err);
}
}
const initPreviewFrame = () => ctx => ctx;
const waitForFrame = ctx => {
return new Promise(resolve => {
if (ctx.document.readyState === 'loading') {
return new Promise((resolve, reject) => {
if (!ctx.document) {
reject(DOCUMENT_NOT_FOUND_ERROR);
} else if (ctx.document.readyState === 'loading') {
ctx.document.addEventListener('DOMContentLoaded', resolve);
} else {
resolve();
@ -153,10 +167,13 @@ const waitForFrame = ctx => {
};
function writeToFrame(content, frame) {
frame.open();
frame.write(content);
frame.close();
return frame;
// it's possible, if the preview is rapidly opened and closed, for the frame
// to be null at this point.
if (frame) {
frame.open();
frame.write(content);
frame.close();
}
}
const writeContentToFrame = ctx => {