@lambdatest/smartui-storybook
Version:
LambdaTest's command-line interface (CLI) aimed to help you run your SmartUI tests on LambdaTest platform
198 lines (181 loc) • 9.38 kB
JavaScript
const { default: axios } = require('axios')
const fs = require('fs')
const { sendDoM } = require('./utils/dom')
const { validateStorybookUrl, validateStorybookDir } = require('./utils/validate')
const { defaultSmartUIConfig } = require('./utils/config')
const { skipStory } = require('./utils/story')
const { getLastCommit } = require('./utils/git')
const static = require('./utils/static')
var { constants } = require('./utils/constants');
const { shortPolling } = require('./utils/polling');
async function storybook(serve, options) {
let type = /^https?:\/\//.test(serve) ? 'url' : 'dir';
let storybookConfig = options.config ? options.config : defaultSmartUIConfig.storybook;
const buildName = options.buildName? options.buildName : "";
if (type === 'url') {
await validateStorybookUrl(serve);
let url = serve;
// Convert browsers and resolutions arrays to string
let resolutions = [];
storybookConfig.resolutions.forEach(element => {
resolutions.push(element.join('x'));
});
storybookConfig.resolutions = (!resolutions.length) ? 'all' : resolutions.toString();
storybookConfig.browsers = (!storybookConfig.browsers.length) ? 'all' : storybookConfig.browsers.map(x => x.toLowerCase()).toString();
// Get stories object from stories.json and add url corresponding to every story ID
await axios.get(new URL('stories.json', url).href)
.then(async function (response) {
let stories = {}
for (const [storyId, storyInfo] of Object.entries(response.data.stories)) {
if (!skipStory(storyInfo, storybookConfig)) {
stories[storyId] = {
name: storyInfo.name,
kind: storyInfo.kind,
url: new URL('/iframe.html?id=' + storyId + '&viewMode=story', url).href
}
}
}
if (Object.keys(stories).length === 0) {
console.log('[smartui] Error: No stories found');
process.exit(constants.ERROR_CATCHALL);
}
console.log('[smartui] Stories found: ', Object.keys(stories).length);
console.log('[smartui] Number of stories rendered may differ based on the config file.');
// Capture DoM of every story and send it to renderer API
await sendDoM(url, stories, storybookConfig, options);
})
.catch(function (error) {
process.exitCode = constants.ERROR_CATCHALL;
if (error.response) {
console.log('[smartui] Cannot fetch stories. Error: ', error.message);
} else if (error.request) {
console.log('[smartui] Cannot fetch stories. Error: ', error.message);
} else {
console.log('[smartui] Cannot fetch stories. Error: ', error.message);
}
});
} else {
let dirPath = serve;
await validateStorybookDir(dirPath);
// Get storyIds to be rendered
let storyIds = static.filterStories(dirPath, storybookConfig)
// Upload Storybook static
await static.getSignedUrl(options)
.then(async function (response) {
let { url, uploadId } = response.data.data;
// Compress static build
await static.compress(dirPath, uploadId)
.then(function () {
console.log(`[smartui] ${dirPath} compressed.`)
})
.catch(function (err) {
console.log(`[smartui] Cannot compress ${dirPath}. Error: ${err.message}`);
process.exit(constants.ERROR_CATCHALL);
});
// Upload to S3
const zipData = fs.readFileSync('storybook-static.zip');
console.log('[smartui] Upload in progress...')
await axios.put(url, zipData, {
headers: {
'Content-Type': 'application/zip',
'Content-Length': zipData.length
}})
.then(function (response) {
console.log(`[smartui] ${dirPath} uploaded.`);
fs.rmSync('storybook-static.zip');
})
.catch(function (error) {
console.log(`[smartui] Cannot upload ${dirPath}. Error: ${error.message}`);
fs.rmSync('storybook-static.zip');
process.exit(constants.ERROR_CATCHALL);
});
// Prepare payload data
let browsers = []
let resolutions = []
storybookConfig.browsers.forEach(element => {
browsers.push(element.toLowerCase());
});
let rs = storybookConfig.resolutions || storybookConfig.viewports
if (rs && rs.length){
rs.forEach(element => {
resolutions.push({ width: element[0], height: element[1] });
});
}
let commit = await getLastCommit();
let baseLine = process.env.BASELINE_BRANCH;
let currentBranch = process.env.CURRENT_BRANCH;
if (baseLine !== null && baseLine !== undefined){
if(baseLine === ''){
const error = {
"error": "MISSING_BRANCH_NAME",
"message": "Error : The baseline branch name environment variable cannot be empty."
};
console.log(JSON.stringify(error, null, 2));
process.exit(1);
}
}
if(currentBranch !== null && currentBranch !==undefined){
if(currentBranch === ''){
const error = {
"error": "MISSING_BRANCH_NAME",
"message": "Error : The current branch name environment variable cannot be empty."
};
console.log(JSON.stringify(error, null, 2));
process.exit(1);
}
}
let payload = {
downloadURL: url.substring(url.search(/.com/)+5, url.search(/.zip/)+4),
uploadId: uploadId,
projectToken: process.env.PROJECT_TOKEN,
storybookConfig: {
browsers: browsers,
resolutions: resolutions,
storyIds: storyIds,
waitForTimeout: storybookConfig.waitForTimeout,
customViewports: storybookConfig.customViewports,
useOnlyCustomViewports: storybookConfig.useOnlyCustomViewports
},
git: {
branch: currentBranch || commit.branch|| '',
baselineBranch: baseLine || '',
commitId: commit.shortHash,
commitAuthor: commit.author.name,
commitMessage: commit.subject,
githubURL: process.env.GITHUB_URL || '',
},
buildName: buildName,
tunnel: options.tunnel || {},
}
// Call static render API
await axios.post(new URL(constants[options.env].STATIC_RENDER_PATH, constants[options.env].BASE_URL).href, payload)
.then(async function (response) {
if (response.data && response.data.error) {
console.log('[smartui] Error: ', response.data.error.message);
process.exitCode = constants.ERROR_CATCHALL;
return
}
console.log('[smartui] Build URL: ', response.data.data.buildURL);
console.log('[smartui] Build in progress...');
await shortPolling(response.data.data.buildId, 0, options);
})
.catch(function (error) {
if (error.response) {
console.log('[smartui] Build failed: Error: ', error.response.data.error?.message);
} else {
console.log('[smartui] Build failed: Error: ', error.message);
}
process.exitCode = constants.ERROR_CATCHALL;
});
})
.catch(function (error) {
if (error.response) {
console.log('[smartui] Error: ', error.response.data.error?.message);
} else {
console.log('[smartui] Error: ', error.message);
}
process.exitCode = constants.ERROR_CATCHALL;
});
}
};
module.exports = { storybook };