@applitools/eyes-storybook
Version:
170 lines (147 loc) • 5.32 kB
JavaScript
const getClientAPI = require('./getClientAPI');
async function getStories() {
const Stories = {
_getStoriesV2: () => {
let categories = getCategoriesV2();
console.log(`got ${categories.length} categories`);
let stories = [];
for (const anchor of categories) {
verifyOpen(anchor);
const kind = anchor.textContent;
const storyEls = Array.from(anchor.nextElementSibling.querySelectorAll('a'));
console.log('found', storyEls.length, 'stories for category', kind);
stories = stories.concat(
storyEls.map(storyEl => ({
kind,
name: storyEl.textContent,
})),
);
}
console.log(stories.map(({kind, name}, i) => `${i + 1}) story kind=${kind}, name=${name}`));
return stories;
function verifyOpen(anchor) {
if (!anchor.nextElementSibling) {
anchor.click();
}
}
},
_getStoriesV3: () => {
let menuItems = getAllMenuItemsV3();
console.log(`got ${menuItems.length} menu items`);
let closedMenuItems = getClosedMenus(menuItems);
console.log(
`got ${closedMenuItems.length} closed menu items:\n${menuItemsToString(closedMenuItems)}`,
);
while (closedMenuItems.length) {
console.log(`opening ${closedMenuItems.length} closed menu items`);
openMenus(closedMenuItems);
menuItems = getAllMenuItemsV3();
closedMenuItems = getClosedMenus(menuItems);
console.log(`after opening menus, got ${menuItems.length} menu items`);
console.log(
`after opening menus, got ${
closedMenuItems.length
} closed menu items:\n${menuItemsToString(closedMenuItems)}`,
);
}
const anchors = Array.from(
document.querySelectorAll('.Pane.vertical.Pane1 [role="menuitem"] + * a[href]'),
);
console.log(`returning ${anchors.length} stories.`);
return anchors.map((anchor, i) => {
const url = new URL(anchor.href);
const kind = url.searchParams.get('selectedKind');
const name = url.searchParams.get('selectedStory');
console.log(`${i + 1}) story kind=${kind}, name=${name}`);
return {
kind,
name,
};
});
function getClosedMenus(menuItems) {
return menuItems.filter(
menuItem => !menuItem.nextElementSibling || !menuItem.nextElementSibling.children[0],
);
}
function openMenus(menuItems) {
menuItems.forEach(menuItem => menuItem.click());
}
function menuItemsToString(menuItems) {
return menuItems.map(item => item.textContent).join('\n');
}
},
};
const clientApi = await getClientAPI().catch(() => null);
if (clientApi) {
console.log(`getting stories from storybook via API. ${clientApi.version}`);
return getStoriesThroughClientAPI(clientApi);
} else if (isStoryBookLoading()) {
return Promise.reject('storybook is loading for too long');
} else {
const storybookVersion = getVersion();
if (storybookVersion) {
console.log(`getting stories from storybook via scraping. ${storybookVersion}`);
return Stories[`_getStories${storybookVersion}`]();
} else {
return Promise.reject('could not determine storybook version in order to extract stories');
}
}
async function getStoriesThroughClientAPI(clientApi) {
const stories = await clientApi.getStories();
return stories.map((story, index) => {
const {name, kind, parameters, id} = story;
const hasEyesParameters =
parameters && parameters.eyes && typeof parameters.eyes === 'object';
let parametersIfSerialized, error;
try {
parametersIfSerialized = JSON.parse(JSON.stringify(parameters));
} catch (e) {
try {
if (hasEyesParameters) {
parametersIfSerialized = JSON.parse(JSON.stringify({eyes: parameters.eyes}));
}
} catch (ex) {
error = `Ignoring parameters for story: "${name} ${kind}" since they are not serilizable. Error: "${e.message}"`;
}
}
if (parametersIfSerialized && hasEyesParameters) {
for (const prop in parameters.eyes) {
if (typeof parameters.eyes[prop] === 'function') {
parametersIfSerialized.eyes[prop] = '__func';
}
}
}
const hasPlayFunction = !!story.playFunction;
return {
isApi: true,
hasPlayFunction,
index,
name,
kind,
id,
parameters: parametersIfSerialized,
error,
};
});
}
function getAllMenuItemsV3() {
return Array.from(document.querySelectorAll('.Pane.vertical.Pane1 [role="menuitem"]'));
}
function getCategoriesV2() {
const ul = document.querySelector('.Pane.vertical.Pane1 ul');
return ul && Array.from(ul.children).map(li => li.querySelector('a'));
}
function getVersion() {
if (getAllMenuItemsV3().length !== 0) {
return 'V3';
} else if (getCategoriesV2()) {
return 'V2';
}
}
function isStoryBookLoading() {
return Array.from(document.querySelectorAll('nav.container span')).some(
s => s.innerText === 'loading story',
);
}
}
module.exports = getStories;