Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@applitools/eyes.cypress

Package Overview
Dependencies
Maintainers
12
Versions
141
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@applitools/eyes.cypress - npm Package Compare versions

Comparing version 1.2.3 to 1.2.4

src/render-grid/sdk/extractCssResources.js

7

package.json
{
"name": "@applitools/eyes.cypress",
"version": "1.2.3",
"version": "1.2.4",
"main": "index.js",
"license": "MIT",
"scripts": {
"test:mocha": ": ${APPLITOOLS_API_KEY:?} && mocha --no-timeouts 'tests/**/*.test.js'",
"test:mocha": "mocha --no-timeouts 'tests/**/*.test.js'",
"eslint": "eslint '**/*.js'",

@@ -44,4 +44,5 @@ "test": "npm run test:mocha && npm run eslint",

"nock": "^9.2.6",
"prettier": "^1.13.0"
"prettier": "^1.13.0",
"puppeteer": "^1.5.0"
}
}

@@ -9,4 +9,4 @@ /* global fetch, Cypress, cy */

const EyesServer = {
open(url, appName, testName, viewportSize) {
return this._send('open', {url, appName, testName, viewportSize});
open(url, appName, testName, viewportSize, isVerbose) {
return this._send('open', {url, appName, testName, viewportSize, isVerbose});
},

@@ -30,6 +30,6 @@

Cypress.Commands.add('eyesOpen', (appName, testName, viewportSize) => {
Cypress.Commands.add('eyesOpen', (appName, testName, viewportSize, isVerbose) => {
Cypress.log({name: 'Eyes: open'});
return cy.window({log: false}).then(win => {
return EyesServer.open(win.location.href, appName, testName, viewportSize);
return EyesServer.open(win.location.href, appName, testName, viewportSize, isVerbose);
});

@@ -36,0 +36,0 @@ });

@@ -10,5 +10,12 @@ require('dotenv').config();

/*****************************/
/******* Eyes API key *******/
/*****************************/
const apiKey = process.env.APPLITOOLS_API_KEY;
if (!apiKey) {
throw new Error('APPLITOOLS_API_KEY env variable is not defined');
}
/*****************************/
/******* Eyes Commands *******/
/*****************************/
const apiKey = process.env.APPLITOOLS_API_KEY;
let checkWindow, close;

@@ -15,0 +22,0 @@

@@ -1,4 +0,35 @@

const {uniq} = require('lodash');
'use strict';
module.exports = el => {
function extractResources(el) {
function extractResourcesFromStyleSheet(styleSheet) {
const resourceUrls = [...styleSheet.cssRules].reduce((acc, rule) => {
if (isRuleOfType(rule, 'CSSImportRule')) {
return acc.concat(rule.href);
} else if (isRuleOfType(rule, 'CSSFontFaceRule')) {
return acc.concat(getUrlFromCssText(rule.style.getPropertyValue('src')));
} else if (isRuleOfType(rule, 'CSSStyleRule')) {
for (let i = 0, ii = rule.style.length; i < ii; i++) {
const url = getUrlFromCssText(rule.style.getPropertyValue(rule.style[i]));
url && acc.push(url);
}
}
return acc;
}, []);
return [...new Set(resourceUrls)];
}
// NOTE: this is also implemented on the server side (copy pasted to enable unit testing `extractResources` with puppeteer)
function getUrlFromCssText(cssText) {
const match = cssText.match(/url\((?!['"]?(?:data|http):)['"]?([^'"\)]*)['"]?\)/);
return match ? match[1] : match;
}
function isRuleOfType(rule, ruleType) {
return rule instanceof rule.parentStyleSheet.ownerNode.ownerDocument.defaultView[ruleType];
}
function uniq(arr) {
return Array.from(new Set(arr));
}
const srcUrls = [...el.querySelectorAll('img[src]')].map(srcEl => srcEl.getAttribute('src'));

@@ -10,3 +41,14 @@

return uniq([...srcUrls, ...cssUrls]);
};
const urlsFromStyleElements = [...el.getElementsByTagName('style')]
.map(styleEl => styleEl.sheet)
.reduce((acc, curr) => {
console.log('acc', acc);
const resourceUrls = extractResourcesFromStyleSheet(curr);
console.log('resources', resourceUrls);
return acc.concat(resourceUrls);
}, []);
return uniq([...srcUrls, ...cssUrls, ...urlsFromStyleElements]);
}
module.exports = extractResources;

@@ -1,70 +0,8 @@

const fetch = require('node-fetch');
'use strict';
const {keyBy} = require('lodash');
const {parse, CSSImportRule, CSSStyleRule, CSSFontFaceRule} = require('cssom');
const {URL} = require('url');
const fetchResource = require('./fetchResource');
function getUrlFromCssText(cssText) {
const match = cssText.match(/url\((?!['"]?(?:data|http):)['"]?([^'"\)]*)['"]?\)/);
return match ? match[1] : match;
}
function absolutizeUrl(url, absoluteUrl) {
return new URL(url, absoluteUrl).href;
}
function extractResourcesFromStyleSheet(styleSheet, absoluteUrl) {
const resourceUrls = [...styleSheet.cssRules].reduce((acc, rule) => {
if (rule instanceof CSSImportRule) {
return acc.concat(absolutizeUrl(rule.href, absoluteUrl));
} else if (rule instanceof CSSFontFaceRule) {
return acc.concat(
absolutizeUrl(getUrlFromCssText(rule.style.getPropertyValue('src')), absoluteUrl),
);
} else if (rule instanceof CSSStyleRule) {
for (let i = 0, ii = rule.style.length; i < ii; i++) {
const url = getUrlFromCssText(rule.style.getPropertyValue(rule.style[i]));
url && acc.push(absolutizeUrl(url, absoluteUrl));
}
}
return acc;
}, []);
return [...new Set(resourceUrls)];
}
function extractCssResources(cssText, absoluteUrl) {
const styleSheet = parse(cssText);
return extractResourcesFromStyleSheet(styleSheet, absoluteUrl);
}
function fetchResources(urls) {
function doFetch(resourceUrls) {
console.log('fetching ', resourceUrls);
return Promise.all(
resourceUrls.map(url =>
fetch(url).then(resp =>
resp.buffer().then(buff => {
const contentType = resp.headers.get('Content-Type');
resources.push({
url,
type: contentType,
value: buff,
});
if (/text\/css/.test(contentType)) {
return doFetch(extractCssResources(buff.toString(), url));
} else {
return true;
}
}),
),
),
);
}
const resources = [];
return doFetch(urls).then(() => {
console.log('done fetching');
return keyBy(resources, 'url');
});
}
module.exports = fetchResources;
module.exports = urls => {
const promises = urls.map(fetchResource);
return Promise.all(promises).then(resourceContents => keyBy(resourceContents, 'url'));
};

@@ -1,3 +0,4 @@

const fetchResources = require('./fetchResources');
const log = require('./log');
'use strict';
const fetchResource = require('./fetchResource');
const extractCssResources = require('./extractCssResources');
const {mapValues} = require('lodash');

@@ -7,4 +8,25 @@ const {RGridResource} = require('@applitools/eyes.sdk.core');

// NOTE: `let` and not `const` because of tests
let allResources = {};
let allResources = {_cache: {}};
allResources.add = (entry, dependencies) => {
allResources._cache[entry.url] = Object.assign({dependencies}, entry);
};
allResources.getWithDependencies = key => {
function doGet(_key) {
const entry = allResources._cache[_key];
if (!entry) return;
const ret = {};
ret[_key] = entry; // TODO omit dependencies
if (entry.dependencies) {
entry.dependencies.forEach(dep => {
Object.assign(ret, doGet(dep));
});
}
return ret;
}
return doGet(key);
};
function fromCacheToRGridResource({url, type, hash}) {

@@ -34,20 +56,29 @@ const resource = new RGridResource();

async function getAllResources(absoluteUrls = []) {
async function getOrFetchResources(resourceUrls, cache) {
const resources = {};
for (const url of absoluteUrls) {
const cacheEntry = allResources[url];
const missingResourceUrls = [];
for (const url of resourceUrls) {
const cacheEntry = cache.getWithDependencies(url);
if (cacheEntry) {
resources[url] = fromCacheToRGridResource(cacheEntry);
Object.assign(resources, mapValues(cacheEntry, fromCacheToRGridResource));
} else {
missingResourceUrls.push(url);
}
}
const missingResourceUrls = absoluteUrls.filter(resourceUrl => !allResources[resourceUrl]);
if (missingResourceUrls.length) {
log(`fetching missing resources: ${missingResourceUrls}`);
const fetchedResources = await fetchResources(missingResourceUrls);
const fetchedResourcesToReturn = mapValues(fetchedResources, fromFetchedToRGridResource);
const fetchedResourcesForCache = mapValues(fetchedResourcesToReturn, toCacheEntry);
Object.assign(allResources, fetchedResourcesForCache); // add to cache without the buffer
Object.assign(resources, fetchedResourcesToReturn);
}
await Promise.all(
missingResourceUrls.map(url =>
fetchResource(url).then(async resource => {
let dependentResources;
if (/text\/css/.test(resource.type)) {
dependentResources = extractCssResources(resource.value.toString(), url);
const fetchedResources = await getOrFetchResources(dependentResources, cache);
Object.assign(resources, fetchedResources);
}
const rGridResource = fromFetchedToRGridResource(resource);
resources[url] = rGridResource;
cache.add(toCacheEntry(rGridResource), dependentResources);
}),
),
);

@@ -57,7 +88,11 @@ return resources;

async function getAllResources(absoluteUrls = []) {
return await getOrFetchResources(absoluteUrls, allResources);
}
// NOTE: ugly, because of tests. Other alternative is to export a "createGetAllResources" which would initialize the cache.
getAllResources.clearCache = () => {
allResources = {};
allResources._cache = {};
};
module.exports = getAllResources;
const EyesWrapper = require('./EyesWrapper');
const getAllResources = require('./getAllResources');
const getRenderStatus = require('./getRenderStatus');
const waitForRenderedStatus = require('./waitForRenderedStatus');
const {URL} = require('url');

@@ -40,3 +40,3 @@ // const saveData = require('../troubleshoot/saveData');

const screenshotUrl = await getRenderStatus(renderId, wrapper);
const screenshotUrl = await waitForRenderedStatus(renderId, wrapper);

@@ -43,0 +43,0 @@ return {screenshotUrl, tag};

@@ -76,2 +76,3 @@ // 'use strict';

if (!domNodes) return '';
return renderCdtDomNode(domNodes, 0);

@@ -117,2 +118,4 @@ }

if (!domNodes || !domNodes.length) return domNodes;
const newDomNodes = [...domNodes];

@@ -119,0 +122,0 @@

@@ -14,3 +14,7 @@ 'use strict';

const path = resolve(__dirname, '../../../.applitools', renderId); // TODO production path
await mkdir(path);
try {
await mkdir(path);
} catch (ex) {
log(`${path} already exists`);
}
writeFile(resolve(path, 'cdt.json'), JSON.stringify(cdt));

@@ -24,4 +28,6 @@ const absolutizedCdt = createAbsolutizedDomNodes(cdt, resources, url);

if (content) {
log(`saving resource: ${resourceUrl}`);
return writeFile(resolve(path, getResourceName(resource)), content);
} else {
log(`NOT saving resource (missing content): ${resourceUrl}`);
return Promise.resolve();

@@ -28,0 +34,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc