@applitools/eyes-storybook
Version:
170 lines (153 loc) • 5.51 kB
JavaScript
;
const getStoryUrl = require('./getStoryUrl');
const getStoryBaselineName = require('./getStoryBaselineName');
const ora = require('ora');
const {presult} = require('@applitools/functional-commons');
function makeRenderStories({
getStoryData,
pagePool,
renderStory,
storybookUrl,
logger,
stream,
sanityCheckForPage,
maxPageTTL = 60000,
}) {
let newPageIdToAdd;
return async function renderStories(stories, isIE) {
let doneStories = 0;
const allTestResults = [];
let allStoriesPromise = Promise.resolve();
let currIndex = 0;
const spinner = ora({
text: updateSpinnerText(0, stories.length),
stream,
});
spinner.start();
prepareNewPage();
await processStoryLoop();
await allStoriesPromise;
updateSpinnerEnd();
return allTestResults;
async function processStoryLoop() {
if (currIndex === stories.length) return;
const {page, pageId, markPageAsFree, removePage, getCreatedAt} = await pagePool.getFreePage();
const livedTime = Date.now() - getCreatedAt();
logger.log(`[prepareNewPage] got free page: ${pageId}, lived time: ${livedTime}`);
if (newPageIdToAdd && livedTime > maxPageTTL) {
logger.log(`[prepareNewPage] replacing page ${pageId} with page ${newPageIdToAdd}`);
removePage();
page.close();
pagePool.addToPool(newPageIdToAdd);
prepareNewPage();
return processStoryLoop();
}
logger.log(`[page ${pageId}] waiting for queued renders`);
// await waitForQueuedRenders(storyDataGap);
logger.log(`[page ${pageId}] done waiting for queued renders`);
const storyPromise = processStory();
allStoriesPromise = allStoriesPromise.then(() => storyPromise);
return processStoryLoop();
async function processStory() {
const story = stories[currIndex++];
const storyUrl = getStoryUrl(story, storybookUrl);
const title = getStoryBaselineName(story);
try {
let [error, storyData] = await presult(
getStoryData({
story,
storyUrl,
page,
pageId,
}),
);
if (
error &&
/(Runtime.callFunctionOn timed out|Protocol error|Execution context was destroyed|timeout reached when trying to take DOM for story)/.test(
error.message,
)
) {
logger.log(
`Puppeteer error from [page ${pageId}] while getting story data. Replacing page. ${error.message}`,
);
removePage();
page
.close()
.catch(e => logger.log(`stale [page ${pageId}] already closed: ${e.message}`));
const newPageObj = await pagePool.createPage();
logger.log(`new page ${newPageObj.pageId} created ad hoc. trying it out`);
const [newError, newStoryData] = await presult(
getStoryData({
story,
storyUrl,
page: newPageObj.page,
pageId: newPageObj.pageId,
}),
);
error = newError;
storyData = newStoryData;
pagePool.addToPool(newPageObj.pageId);
} else {
markPageAsFree();
}
if (error) {
const errMsg = `[page ${pageId}] Failed to get story data for "${title}". ${error}`;
logger.log(errMsg);
}
const testResults = await renderStory({
snapshots: storyData,
url: storyUrl,
story,
});
return onDoneStory(testResults, story);
} catch (ex) {
logger.log(`[page ${pageId}] error while processing story "${title}". ${ex}`);
return onDoneStory(ex, story);
}
}
}
function didTestPass({resultsOrErr}) {
return (
Array.isArray(resultsOrErr) &&
resultsOrErr.every(r => !r.isDifferent && !r.isAborted && !r.isNew)
);
}
function updateSpinnerEnd() {
allTestResults.every(didTestPass) ? spinner.succeed() : spinner.fail();
}
function updateSpinnerText(number, length) {
return `Done ${number} stories out of ${length} ${isIE ? '(IE)' : ''}`;
}
function onDoneStory(resultsOrErr, story) {
spinner.text = updateSpinnerText(++doneStories, stories.length, story.config);
const title = getStoryBaselineName(story);
allTestResults.push({title, resultsOrErr});
return {title, resultsOrErr};
}
async function prepareNewPage() {
newPageIdToAdd = null;
logger.log('[prepareNewPage] preparing...');
const [errorInCreate, pageObj] = await presult(pagePool.createPage());
if (errorInCreate) {
logger.log(
`[prepareNewPage] error preparing new page. This is probably a fatal problem. ${errorInCreate}`,
);
return;
}
const {pageId, page} = pageObj;
logger.log(`[prepareNewPage] new page is ready: ${pageId}`);
try {
await sanityCheckForPage({page, pageId});
logger.log(`[prepareNewPage] setting new page for replacement: ${pageId}`);
newPageIdToAdd = pageId;
} catch (errorInSanity) {
logger.log(
`[prepareNewPage] new page ${pageId} is corrupted. preparing new page.`,
errorInSanity,
);
prepareNewPage();
}
}
};
}
module.exports = makeRenderStories;