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

percy

Package Overview
Dependencies
Maintainers
2
Versions
105
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

percy - npm Package Compare versions

Comparing version 0.4.9 to 0.5.0

2

.oclif.manifest.json

@@ -1,1 +0,1 @@

{"version":"0.4.9","commands":{"exec":{"id":"exec","description":"Start and stop Percy around a supplied command.","pluginName":"percy","pluginType":"core","hidden":false,"aliases":[],"examples":["$ percy exec -- echo \"percy is running around this echo command\"","$ percy exec -- bash -c \"echo foo && echo bar\""],"flags":{"network-idle-timeout":{"name":"network-idle-timeout","type":"option","char":"t","description":"asset discovery network idle timeout (in milliseconds)","default":50},"port":{"name":"port","type":"option","char":"p","description":"port","default":5338}},"args":[]},"finalize":{"id":"finalize","description":"Finalize a build. Commonly used for parallelized builds, especially when the number of parallelized processes is unknown.","pluginName":"percy","pluginType":"core","hidden":false,"aliases":[],"examples":["$ percy finalize --all\n[percy] Finalized parallel build."],"flags":{"all":{"name":"all","type":"boolean","char":"a","required":true,"allowNo":false}},"args":[]},"health-check":{"id":"health-check","description":"Determines if the Percy Agent process is currently running","pluginName":"percy","pluginType":"core","hidden":true,"aliases":[],"examples":["$ percy healthcheck","$ percy healthcheck --port 6884"],"flags":{"port":{"name":"port","type":"option","char":"p","description":"port","default":5338}},"args":[]},"percy-command":{"id":"percy-command","pluginName":"percy","pluginType":"core","hidden":true,"aliases":[],"flags":{},"args":[]},"snapshot":{"id":"snapshot","description":"Snapshot a directory containing a pre-built static website.","pluginName":"percy","pluginType":"core","hidden":false,"aliases":[],"examples":["$ percy snapshot _site/","$ percy snapshot _site/ --base-url \"/blog\"","$ percy snapshot _site/ --ignore-files \"/blog/drafts/**\""],"flags":{"snapshot-files":{"name":"snapshot-files","type":"option","char":"s","description":"Glob or comma-seperated string of globs for matching the files and directories to snapshot.","default":"**/*.html,**/*.htm"},"ignore-files":{"name":"ignore-files","type":"option","char":"i","description":"Glob or comma-seperated string of globs for matching the files and directories to ignore.","default":""},"base-url":{"name":"base-url","type":"option","char":"b","description":"If your static files will be hosted in a subdirectory, instead \nof the webserver's root path, set that subdirectory with this flag.","default":"/"},"network-idle-timeout":{"name":"network-idle-timeout","type":"option","char":"t","description":"Asset discovery network idle timeout (in milliseconds)","default":50},"port":{"name":"port","type":"option","char":"p","description":"Port","default":5338}},"args":[{"name":"snapshotDirectory","description":"A path to the directory you would like to snapshot","required":true}]},"start":{"id":"start","description":"Starts the percy process.","pluginName":"percy","pluginType":"core","hidden":true,"aliases":[],"examples":["$ percy start\ninfo: percy has started on port 5338."],"flags":{"detached":{"name":"detached","type":"boolean","char":"d","description":"start as a detached process","allowNo":false},"network-idle-timeout":{"name":"network-idle-timeout","type":"option","char":"t","description":"asset discovery network idle timeout (in milliseconds)","default":50},"port":{"name":"port","type":"option","char":"p","description":"port","default":5338}},"args":[]},"stop":{"id":"stop","description":"Stops the percy process.","pluginName":"percy","pluginType":"core","hidden":true,"aliases":[],"examples":["$ percy stop\ninfo: percy has stopped."],"flags":{"port":{"name":"port","type":"option","char":"p","description":"port","default":5338}},"args":[]}}}
{"version":"0.5.0","commands":{"exec":{"id":"exec","description":"Start and stop Percy around a supplied command.","pluginName":"percy","pluginType":"core","hidden":false,"aliases":[],"examples":["$ percy exec -- echo \"percy is running around this echo command\"","$ percy exec -- bash -c \"echo foo && echo bar\""],"flags":{"network-idle-timeout":{"name":"network-idle-timeout","type":"option","char":"t","description":"asset discovery network idle timeout (in milliseconds)","default":50},"port":{"name":"port","type":"option","char":"p","description":"port","default":5338}},"args":[]},"finalize":{"id":"finalize","description":"Finalize a build. Commonly used for parallelized builds, especially when the number of parallelized processes is unknown.","pluginName":"percy","pluginType":"core","hidden":false,"aliases":[],"examples":["$ percy finalize --all\n[percy] Finalized parallel build."],"flags":{"all":{"name":"all","type":"boolean","char":"a","required":true,"allowNo":false}},"args":[]},"health-check":{"id":"health-check","description":"Determines if the Percy Agent process is currently running","pluginName":"percy","pluginType":"core","hidden":true,"aliases":[],"examples":["$ percy healthcheck","$ percy healthcheck --port 6884"],"flags":{"port":{"name":"port","type":"option","char":"p","description":"port","default":5338}},"args":[]},"percy-command":{"id":"percy-command","pluginName":"percy","pluginType":"core","hidden":true,"aliases":[],"flags":{},"args":[]},"snapshot":{"id":"snapshot","description":"Snapshot a directory containing a pre-built static website.","pluginName":"percy","pluginType":"core","hidden":false,"aliases":[],"examples":["$ percy snapshot _site/","$ percy snapshot _site/ --base-url \"/blog\"","$ percy snapshot _site/ --ignore-files \"/blog/drafts/**\""],"flags":{"snapshot-files":{"name":"snapshot-files","type":"option","char":"s","description":"Glob or comma-seperated string of globs for matching the files and directories to snapshot.","default":"**/*.html,**/*.htm"},"ignore-files":{"name":"ignore-files","type":"option","char":"i","description":"Glob or comma-seperated string of globs for matching the files and directories to ignore.","default":""},"base-url":{"name":"base-url","type":"option","char":"b","description":"If your static files will be hosted in a subdirectory, instead \nof the webserver's root path, set that subdirectory with this flag.","default":"/"},"network-idle-timeout":{"name":"network-idle-timeout","type":"option","char":"t","description":"Asset discovery network idle timeout (in milliseconds)","default":50},"port":{"name":"port","type":"option","char":"p","description":"Port","default":5338}},"args":[{"name":"snapshotDirectory","description":"A path to the directory you would like to snapshot","required":true}]},"start":{"id":"start","description":"Starts the percy process.","pluginName":"percy","pluginType":"core","hidden":true,"aliases":[],"examples":["$ percy start\ninfo: percy has started on port 5338."],"flags":{"detached":{"name":"detached","type":"boolean","char":"d","description":"start as a detached process","allowNo":false},"network-idle-timeout":{"name":"network-idle-timeout","type":"option","char":"t","description":"asset discovery network idle timeout (in milliseconds)","default":50},"port":{"name":"port","type":"option","char":"p","description":"port","default":5338}},"args":[]},"stop":{"id":"stop","description":"Stops the percy process.","pluginName":"percy","pluginType":"core","hidden":true,"aliases":[],"examples":["$ percy stop\ninfo: percy has stopped."],"flags":{"port":{"name":"port","type":"option","char":"p","description":"port","default":5338}},"args":[]}}}

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

# [0.5.0](https://github.com/percy/percy-agent/compare/v0.4.9...v0.5.0) (2019-05-30)
### Features
* Support parallel snapshots calls ([#168](https://github.com/percy/percy-agent/issues/168)) ([744a399](https://github.com/percy/percy-agent/commit/744a399))
## [0.4.9](https://github.com/percy/percy-agent/compare/v0.4.8...v0.4.9) (2019-05-21)

@@ -2,0 +9,0 @@

@@ -0,1 +1,2 @@

import * as pool from 'generic-pool';
import * as puppeteer from 'puppeteer';

@@ -11,9 +12,14 @@ import { SnapshotOptions } from '../percy-agent-client/snapshot-options';

browser: puppeteer.Browser | null;
pages: puppeteer.Page[] | null;
pagePool: pool.Pool<puppeteer.Page> | null;
readonly DEFAULT_NETWORK_IDLE_TIMEOUT: number;
networkIdleTimeout: number;
readonly PAGE_POOL_SIZE: number;
readonly MAX_SNAPSHOT_WIDTHS: number;
readonly PAGE_POOL_SIZE_MIN: number;
readonly PAGE_POOL_SIZE_MAX: number;
readonly DEFAULT_WIDTHS: number[];
constructor(buildId: number, options?: AssetDiscoveryOptions);
setup(): Promise<void>;
createBrowser(): Promise<puppeteer.Browser>;
createPagePool(exec: () => PromiseLike<puppeteer.Page>, min: number, max: number): Promise<pool.Pool<puppeteer.Page>>;
createPage(browser: puppeteer.Browser): Promise<puppeteer.Page>;
discoverResources(rootResourceUrl: string, domSnapshot: string, options: SnapshotOptions): Promise<any[]>;

@@ -23,5 +29,5 @@ shouldRequestResolve(request: puppeteer.Request): boolean;

private resourcesForWidth;
private cleanPagePool;
private closeBrowser;
private closePages;
}
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const pool = require("generic-pool");
const puppeteer = require("puppeteer");

@@ -8,2 +9,3 @@ const logger_1 = require("../utils/logger");

const response_service_1 = require("./response-service");
const DEFAULT_PAGE_POOL_SIZE = process.env.PERCY_POOL_SIZE;
class AssetDiscoveryService extends percy_client_service_1.default {

@@ -13,5 +15,5 @@ constructor(buildId, options = {}) {

this.DEFAULT_NETWORK_IDLE_TIMEOUT = 50; // ms
// How many 'pages' (i.e. tabs) we'll keep around.
// We will only be able to process at most these many snapshot widths.
this.PAGE_POOL_SIZE = 10;
this.MAX_SNAPSHOT_WIDTHS = 10;
this.PAGE_POOL_SIZE_MIN = 2;
this.PAGE_POOL_SIZE_MAX = DEFAULT_PAGE_POOL_SIZE ? parseInt(DEFAULT_PAGE_POOL_SIZE) : 10;
// Default widths to use for asset discovery. Must match Percy service defaults.

@@ -22,7 +24,15 @@ this.DEFAULT_WIDTHS = [1280, 375];

this.browser = null;
this.pages = null;
this.pagePool = null;
}
async setup() {
logger_1.profile('-> assetDiscoveryService.setup');
const browser = this.browser = await this.createBrowser();
this.pagePool = await this.createPagePool(() => {
return this.createPage(browser);
}, this.PAGE_POOL_SIZE_MIN, this.PAGE_POOL_SIZE_MAX);
logger_1.profile('-> assetDiscoveryService.setup');
}
async createBrowser() {
logger_1.profile('-> assetDiscoveryService.puppeteer.launch');
this.browser = await puppeteer.launch({
const browser = await puppeteer.launch({
args: [

@@ -36,23 +46,38 @@ '--no-sandbox',

logger_1.profile('-> assetDiscoveryService.puppeteer.launch');
logger_1.profile('-> assetDiscoveryService.browser.newPagePool');
const pagePromises = [];
for (let i = 0; i < this.PAGE_POOL_SIZE; i++) {
const promise = this.browser.newPage().then((page) => {
return page.setRequestInterception(true).then(() => page);
});
pagePromises.push(promise);
}
this.pages = await Promise.all(pagePromises);
logger_1.profile('-> assetDiscoveryService.browser.newPagePool');
return browser;
}
async createPagePool(exec, min, max) {
logger_1.profile('-> assetDiscoveryService.createPagePool');
const result = pool.createPool({
create() {
return exec();
},
destroy(page) {
return page.close();
},
}, { min, max });
logger_1.profile('-> assetDiscoveryService.createPagePool');
return result;
}
async createPage(browser) {
logger_1.profile('-> assetDiscoveryService.browser.newPage');
const page = await browser.newPage();
await page.setRequestInterception(true);
logger_1.profile('-> assetDiscoveryService.browser.newPage');
return page;
}
async discoverResources(rootResourceUrl, domSnapshot, options) {
logger_1.profile('-> assetDiscoveryService.discoverResources');
if (!this.browser || !this.pages || !this.pages.length) {
logger_1.default.error('Puppeteer failed to open with a page pool.');
if (this.browser === null) {
logger_1.default.error('Puppeteer failed to open browser.');
return [];
}
if (options.widths && options.widths.length > this.pages.length) {
logger_1.default.error(`Too many widths requested. Max allowed is ${this.PAGE_POOL_SIZE}. Requested: ${options.widths}`);
if (!this.pagePool) {
logger_1.default.error('Failed to create pool of pages.');
return [];
}
if (options.widths && options.widths.length > this.MAX_SNAPSHOT_WIDTHS) {
logger_1.default.error(`Too many widths requested. Max is ${this.MAX_SNAPSHOT_WIDTHS}. Requested: ${options.widths}`);
return [];
}
rootResourceUrl = this.parseRequestPath(rootResourceUrl);

@@ -68,4 +93,4 @@ logger_1.default.debug(`discovering assets for URL: ${rootResourceUrl}`);

const resourcePromises = [];
for (let idx = 0; idx < widths.length; idx++) {
const promise = this.resourcesForWidth(this.pages[idx], widths[idx], domSnapshot, rootResourceUrl, enableJavaScript);
for (const width of widths) {
const promise = this.resourcesForWidth(this.pagePool, width, domSnapshot, rootResourceUrl, enableJavaScript);
resourcePromises.push(promise);

@@ -103,23 +128,31 @@ }

async teardown() {
await this.closePages();
await this.cleanPagePool();
await this.closeBrowser();
}
async resourcesForWidth(page, width, domSnapshot, rootResourceUrl, enableJavaScript) {
async resourcesForWidth(pool, width, domSnapshot, rootResourceUrl, enableJavaScript) {
logger_1.default.debug(`discovering assets for width: ${width}`);
logger_1.profile('--> assetDiscoveryService.pool.acquire', { url: rootResourceUrl });
const page = await pool.acquire();
logger_1.profile('--> assetDiscoveryService.pool.acquire');
await page.setJavaScriptEnabled(enableJavaScript);
await page.setViewport(Object.assign(page.viewport(), { width }));
page.on('request', async (request) => {
if (!this.shouldRequestResolve(request)) {
await request.abort();
return;
try {
if (!this.shouldRequestResolve(request)) {
await request.abort();
return;
}
if (request.url() === rootResourceUrl) {
await request.respond({
body: domSnapshot,
contentType: 'text/html',
status: 200,
});
return;
}
await request.continue();
}
if (request.url() === rootResourceUrl) {
await request.respond({
body: domSnapshot,
contentType: 'text/html',
status: 200,
});
return;
catch (error) {
logger_1.logError(error);
}
await request.continue();
});

@@ -146,16 +179,35 @@ const maybeResourcePromises = [];

});
logger_1.profile('--> assetDiscoveryService.page.goto', { url: rootResourceUrl });
await page.goto(rootResourceUrl);
logger_1.profile('--> assetDiscoveryService.page.goto');
logger_1.profile('--> assetDiscoveryService.waitForNetworkIdle');
await wait_for_network_idle_1.default(page, this.networkIdleTimeout).catch(logger_1.logError);
logger_1.profile('--> assetDiscoveryService.waitForNetworkIdle');
page.removeAllListeners();
logger_1.profile('--> assetDiscoveryServer.waitForResourceProcessing');
const maybeResources = await Promise.all(maybeResourcePromises);
logger_1.profile('--> assetDiscoveryServer.waitForResourceProcessing');
return maybeResources.filter((maybeResource) => maybeResource != null);
try {
logger_1.profile('--> assetDiscoveryService.page.goto', { url: rootResourceUrl });
await page.goto(rootResourceUrl);
logger_1.profile('--> assetDiscoveryService.page.goto');
logger_1.profile('--> assetDiscoveryService.waitForNetworkIdle');
await wait_for_network_idle_1.default(page, this.networkIdleTimeout);
logger_1.profile('--> assetDiscoveryService.waitForNetworkIdle');
logger_1.profile('--> assetDiscoveryServer.waitForResourceProcessing');
const maybeResources = await Promise.all(maybeResourcePromises);
logger_1.profile('--> assetDiscoveryServer.waitForResourceProcessing');
logger_1.profile('--> assetDiscoveryService.pool.release', { url: rootResourceUrl });
await page.removeAllListeners('request');
await page.removeAllListeners('requestfinished');
await page.removeAllListeners('requestfailed');
await pool.release(page);
logger_1.profile('--> assetDiscoveryService.pool.release');
return maybeResources.filter((maybeResource) => maybeResource != null);
}
catch (error) {
logger_1.logError(error);
}
return [];
}
async cleanPagePool() {
if (this.pagePool === null) {
return;
}
await this.pagePool.drain();
await this.pagePool.clear();
this.pagePool = null;
}
async closeBrowser() {
if (!this.browser) {
if (this.browser === null) {
return;

@@ -166,10 +218,3 @@ }

}
async closePages() {
if (!this.pages) {
return;
}
await Promise.all(this.pages.map((page) => page.close()));
this.pages = null;
}
}
exports.default = AssetDiscoveryService;
{
"name": "percy",
"description": "An agent process for integrating with Percy.",
"version": "0.4.9",
"version": "0.5.0",
"author": "Perceptual Inc",

@@ -34,2 +34,3 @@ "bin": {

"express": "^4.16.3",
"generic-pool": "^3.7.1",
"globby": "^9.2.0",

@@ -58,2 +59,3 @@ "js-yaml": "^3.13.1",

"@types/cross-spawn": "^6.0.0",
"@types/generic-pool": "^3.1.9",
"@types/http-server": "^0.10.0",

@@ -63,4 +65,5 @@ "@types/mocha": "^5.2.5",

"@types/node": "^12.0.0",
"@types/sinon": "^5.0.1",
"@types/sinon": "^7.0.12",
"@types/sinon-chai": "^3.2.0",
"babel-loader": "^8.0.6",
"browserify": "^16.2.3",

@@ -72,3 +75,9 @@ "chai": "^4.1.2",

"husky": "^1.0.0-rc.13",
"mocha": "^6.1.3",
"karma": "^4.1.0",
"karma-chrome-launcher": "^2.2.0",
"karma-firefox-launcher": "^1.1.0",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.5",
"karma-webpack": "^3.0.5",
"mocha": "^6.1.4",
"nock": "^10.0.6",

@@ -91,3 +100,4 @@ "npm-watch": "^0.6.0",

"tslint": "^5",
"typescript": "^3"
"typescript": "^3",
"webpack": "^4.32.2"
},

@@ -136,3 +146,3 @@ "engines": {

"test": "npm run build-client && PERCY_TOKEN=abc mocha --forbid-only \"test/**/*.test.ts\" --exclude \"test/percy-agent-client/**/*.test.ts\" --exclude \"test/integration/**/*\"",
"test-client": "mkdir -p dist-test/ && npm run build-client-test && testem ci --file ./test/percy-agent-client/testem.js",
"test-client": "npm run build-client && karma start ./test/percy-agent-client/karma.conf.js",
"test-integration": "npm run build-client && node ./bin/run exec -- mocha test/integration/**/*.test.ts",

@@ -139,0 +149,0 @@ "test-snapshot-command": "./bin/run snapshot test/integration/test-static-site -b /dummy-base-url -i '(red-keep)' -c '\\.(html)$'",

@@ -22,3 +22,3 @@ @percy/agent

$ percy (-v|--version|version)
percy/0.4.9 linux-x64 node-v10.15.3
percy/0.5.0 linux-x64 node-v10.16.0
$ percy --help [COMMAND]

@@ -54,3 +54,3 @@ USAGE

_See code: [dist/commands/exec.ts](https://github.com/percy/percy-agent/blob/v0.4.9/dist/commands/exec.ts)_
_See code: [dist/commands/exec.ts](https://github.com/percy/percy-agent/blob/v0.5.0/dist/commands/exec.ts)_

@@ -73,3 +73,3 @@ ## `percy finalize`

_See code: [dist/commands/finalize.ts](https://github.com/percy/percy-agent/blob/v0.4.9/dist/commands/finalize.ts)_
_See code: [dist/commands/finalize.ts](https://github.com/percy/percy-agent/blob/v0.5.0/dist/commands/finalize.ts)_

@@ -125,3 +125,3 @@ ## `percy help [COMMAND]`

_See code: [dist/commands/snapshot.ts](https://github.com/percy/percy-agent/blob/v0.4.9/dist/commands/snapshot.ts)_
_See code: [dist/commands/snapshot.ts](https://github.com/percy/percy-agent/blob/v0.5.0/dist/commands/snapshot.ts)_
<!-- commandsstop -->
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