Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pac file test #1829

Open
wants to merge 42 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
5067675
PAC file support via PERCY_PAC_FILE_URL env var (#1784)
khushhalm Nov 19, 2024
2a2172d
Fix import in ternary statement (#1779)
khushhalm Nov 19, 2024
3d14958
v1.30.3-alpha.0
ninadbstack Nov 19, 2024
cacd660
Cli bundling import fix (#1785)
khushhalm Nov 20, 2024
e342330
v1.30.3-alpha.1
ninadbstack Nov 20, 2024
aeaba47
v1.30.3-alpha.2
ninadbstack Nov 20, 2024
3b4c0a5
Cli bundling import fix (#1794)
khushhalm Nov 26, 2024
4d36bd8
v1.30.3-alpha.3
ninadbstack Nov 26, 2024
184c53a
Merge branch 'master' of github.com:percy/cli into pac-file-support
ninadbstack Nov 26, 2024
c524e28
Added PERCY_FORCE_PKG_VALUE in place of PERCY_FORCE_DIRNAME (#1799)
khushhalm Nov 26, 2024
b996f30
Added PERCY_FORCE_PKG_VALUE in env file and using from there (#1800)
khushhalm Nov 27, 2024
de0b4b7
taking master
prklm10 Dec 19, 2024
acbe4e3
client-fix
mucool1205 Dec 19, 2024
b40e8ce
upload-cli-fix
mucool1205 Dec 19, 2024
9b94dc2
cli-build-fix
mucool1205 Dec 19, 2024
cecdff9
cli-exec-fix
mucool1205 Dec 19, 2024
159e0dd
cli-snapshot-fix
mucool1205 Dec 19, 2024
22a3f9d
MERGE_COMMIT
mucool1205 Dec 19, 2024
027566c
MERGE_COMMIT
mucool1205 Dec 19, 2024
13a53c7
MERGE_COMMIT
mucool1205 Dec 19, 2024
c6d4d4f
MERGE_COMMIT
mucool1205 Dec 19, 2024
6b23cb5
Proxy.test
mucool1205 Dec 19, 2024
ff0eb6a
proxy
mucool1205 Dec 19, 2024
dcdb048
core fixed
mucool1205 Dec 19, 2024
989046b
client package
mucool1205 Dec 19, 2024
3b0238e
client package
mucool1205 Dec 20, 2024
02cc1f1
client package
mucool1205 Dec 20, 2024
2695c35
client package
mucool1205 Dec 20, 2024
8b69921
client package
mucool1205 Dec 20, 2024
7a3be55
lock file
mucool1205 Dec 20, 2024
aa4b1e2
pac-packages
mucool1205 Dec 20, 2024
997ae65
pac-packages
mucool1205 Dec 20, 2024
ef701ed
pac-packages
mucool1205 Dec 20, 2024
97bd378
lint pass
mucool1205 Dec 20, 2024
9a04b77
lint pass
mucool1205 Dec 20, 2024
c01bcc6
lint pass
mucool1205 Dec 20, 2024
4ae2f4f
lint pass
mucool1205 Dec 20, 2024
8208ee1
proxy pass
mucool1205 Dec 20, 2024
f1470f7
client pass
mucool1205 Dec 20, 2024
a6a1adb
api-test
mucool1205 Dec 20, 2024
e3f99ee
api-test
mucool1205 Dec 20, 2024
17df2f1
Merge branch 'master' into pac-file-test
bhutianimukul Dec 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@
"@babel/eslint-parser": "^7.14.7",
"@babel/preset-env": "^7.14.7",
"@babel/register": "^7.17.7",
"babel-plugin-transform-import-meta": "^2.2.1",
"@rollup/plugin-alias": "^5.1.1",
"@rollup/plugin-babel": "^6.0.0",
"@rollup/plugin-commonjs": "^21.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"babel-plugin-istanbul": "^7.0.0",
"babel-plugin-module-resolver": "^5.0.2",
"babel-plugin-transform-import-meta": "^2.2.1",
"cross-env": "^7.0.2",
"eslint": "^7.30.0",
"eslint-config-standard": "^16.0.2",
Expand Down
3 changes: 2 additions & 1 deletion packages/cli-build/test/finalize.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@ describe('percy build:finalize', () => {

it('defaults PERCY_PARALLEL_TOTAL to -1', async () => {
process.env.PERCY_TOKEN = '<<PERCY_TOKEN>>';

process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
expect(process.env.PERCY_PARALLEL_TOTAL).toBeUndefined();
await finalize();
expect(process.env.PERCY_PARALLEL_TOTAL).toEqual('-1');
});

it('gets parallel build info and finalizes all parallel builds', async () => {
process.env.PERCY_TOKEN = '<<PERCY_TOKEN>>';
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
await finalize();

expect(logger.stderr).toEqual([]);
Expand Down
3 changes: 2 additions & 1 deletion packages/cli-build/test/wait.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ describe('percy build:wait', () => {

beforeEach(async () => {
process.env.PERCY_TOKEN = '<<PERCY_TOKEN>>';
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
await setupTest({ loggerTTY: true });
});

afterEach(() => {
delete process.env.PERCY_TOKEN;
delete process.env.PERCY_ENABLE;
delete process.env.PERCY_FORCE_PKG_VALUE;
});

it('does nothing and logs when percy is not enabled', async () => {
Expand Down Expand Up @@ -232,7 +234,6 @@ describe('percy build:wait', () => {
})]);

await expectAsync(wait(['--build=123'])).toBeRejected();

expect(logger.stdout).toEqual([]);
expect(logger.stderr).toEqual(jasmine.arrayContaining([
'[percy] Build #10 failed! https://percy.io/test/test/123',
Expand Down
7 changes: 7 additions & 0 deletions packages/cli-exec/test/exec.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@ import exec from '@percy/cli-exec';
describe('percy exec', () => {
beforeEach(async () => {
process.env.PERCY_TOKEN = '<<PERCY_TOKEN>>';
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
jasmine.DEFAULT_TIMEOUT_INTERVAL = 25000;
await setupTest();

let { default: which } = await import('which');
spyOn(which, 'sync').and.callFake(c => c);
spyOn(process, 'exit').and.callFake(c => c);
process.env.PERCY_CLIENT_ERROR_LOGS = false;

// Ensure global.__MOCK_IMPORTS__ is defined
global.__MOCK_IMPORTS__ = global.__MOCK_IMPORTS__ || new Map();
});

afterEach(() => {
delete process.env.PERCY_TOKEN;
delete process.env.PERCY_FORCE_PKG_VALUE;
delete process.env.PERCY_ENABLE;
delete process.env.PERCY_BUILD_ID;
delete process.env.PERCY_PARALLEL_TOTAL;
Expand Down Expand Up @@ -243,9 +248,11 @@ describe('percy exec', () => {
let [e, err] = [new EventEmitter(), new Error('spawn error')];
let crossSpawn = () => (setImmediate(() => e.emit('error', err)), e);
global.__MOCK_IMPORTS__.set('cross-spawn', { default: crossSpawn });

let stdinSpy = spyOn(process.stdin, 'pipe').and.resolveTo('some response');

await expectAsync(exec(['--', 'foobar'])).toBeRejected();

expect(stdinSpy).toHaveBeenCalled();
console.log(logger.stderr);
expect(logger.stderr).toEqual(jasmine.arrayContaining([
Expand Down
2 changes: 2 additions & 0 deletions packages/cli-exec/test/ping.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ describe('percy exec:ping', () => {

beforeEach(async () => {
process.env.PERCY_TOKEN = '<<PERCY_TOKEN>>';
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
await setupTest();
});

afterEach(async () => {
delete process.env.PERCY_TOKEN;
delete process.env.PERCY_FORCE_PKG_VALUE;
delete process.env.PERCY_ENABLE;
delete process.env.PERCY_PARALLEL_TOTAL;
delete process.env.PERCY_PARTIAL_BUILD;
Expand Down
2 changes: 2 additions & 0 deletions packages/cli-exec/test/start.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ describe('percy exec:start', () => {

beforeEach(async () => {
process.env.PERCY_TOKEN = '<<PERCY_TOKEN>>';
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
await setupTest();

started = start(['--quiet']);
Expand Down Expand Up @@ -117,6 +118,7 @@ describe('percy exec:start', () => {
logger.reset();

process.env.PERCY_ENABLE = '0';
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
await start();

expect(logger.stdout).toEqual([]);
Expand Down
2 changes: 2 additions & 0 deletions packages/cli-exec/test/stop.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ describe('percy exec:stop', () => {

beforeEach(async () => {
process.env.PERCY_TOKEN = '<<PERCY_TOKEN>>';
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
await setupTest();
});

afterEach(async () => {
delete process.env.PERCY_TOKEN;
delete process.env.PERCY_FORCE_PKG_VALUE;
delete process.env.PERCY_ENABLE;
delete process.env.PERCY_PARALLEL_TOTAL;
delete process.env.PERCY_PARTIAL_BUILD;
Expand Down
2 changes: 2 additions & 0 deletions packages/cli-snapshot/test/directory.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ describe('percy snapshot <directory>', () => {
beforeEach(async () => {
snapshot.packageInformation = { name: '@percy/cli-snapshot' };
process.env.PERCY_TOKEN = '<<PERCY_TOKEN>>';
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });

await setupTest({
filesystem: {
Expand All @@ -21,6 +22,7 @@ describe('percy snapshot <directory>', () => {

afterEach(() => {
delete process.env.PERCY_TOKEN;
delete process.env.PERCY_FORCE_PKG_VALUE;
delete process.env.PERCY_ENABLE;
delete snapshot.packageInformation;
delete process.env.PERCY_CLIENT_ERROR_LOGS;
Expand Down
2 changes: 2 additions & 0 deletions packages/cli-snapshot/test/file.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('percy snapshot <file>', () => {
beforeEach(async () => {
snapshot.packageInformation = { name: '@percy/cli-snapshot' };
process.env.PERCY_TOKEN = '<<PERCY_TOKEN>>';
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });

server = await createTestServer({
default: () => [200, 'text/html', '<p>Test</p>']
Expand Down Expand Up @@ -44,6 +45,7 @@ describe('percy snapshot <file>', () => {

afterEach(async () => {
delete process.env.PERCY_TOKEN;
delete process.env.PERCY_FORCE_PKG_VALUE;
delete process.env.PERCY_CLIENT_ERROR_LOGS;
delete snapshot.packageInformation;
await server.close();
Expand Down
2 changes: 2 additions & 0 deletions packages/cli-snapshot/test/sitemap.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('percy snapshot <sitemap>', () => {
beforeEach(async () => {
snapshot.packageInformation = { name: '@percy/cli-snapshot' };
process.env.PERCY_TOKEN = '<<PERCY_TOKEN>>';
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
await setupTest();

server = await createTestServer({
Expand All @@ -33,6 +34,7 @@ describe('percy snapshot <sitemap>', () => {

afterEach(async () => {
delete process.env.PERCY_TOKEN;
delete process.env.PERCY_FORCE_PKG_VALUE;
delete snapshot.packageInformation;
await server.close();
});
Expand Down
1 change: 1 addition & 0 deletions packages/cli-upload/test/upload.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ describe('percy upload', () => {
upload.packageInformation = { name: '@percy/cli-upload' };
process.env.PERCY_TOKEN = 'web_<<PERCY_TOKEN>>';
process.env.PERCY_CLIENT_ERROR_LOGS = false;
process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
await setupTest({
filesystem: {
'images/test-1.png': pixel,
Expand Down
1 change: 1 addition & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"dependencies": {
"@percy/env": "1.30.6-beta.0",
"@percy/logger": "1.30.6-beta.0",
"pac-proxy-agent": "^7.0.2",
"pako": "^2.1.0"
}
}
4 changes: 3 additions & 1 deletion packages/client/src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {

// Default client API URL can be set with an env var for API development
const { PERCY_CLIENT_API_URL = 'https://percy.io/api/v1' } = process.env;
const pkg = getPackageJSON(import.meta.url);
let pkg = getPackageJSON(import.meta.url);
// minimum polling interval milliseconds
const MIN_POLLING_INTERVAL = 1_000;
const INVALID_TOKEN_ERROR_MESSAGE = 'Unable to retrieve snapshot details with write access token. Kindly use a full access token for retrieving snapshot details with Synchronous CLI.';
Expand Down Expand Up @@ -83,6 +83,8 @@ export class PercyClient {

// Stringifies client and environment info.
userAgent() {
if (this.env.forcedPkgValue) pkg = this.env.forcedPkgValue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add that this is added by LCNC team and why?


let client = new Set([`Percy/${/\w+$/.exec(this.apiUrl)}`]
.concat(`${pkg.name}/${pkg.version}`, ...this.clientInfo)
.filter(Boolean));
Expand Down
48 changes: 43 additions & 5 deletions packages/client/src/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,28 @@ import http from 'http';
import https from 'https';
import logger from '@percy/logger';
import { stripQuotesAndSpaces } from '@percy/env/utils';
import { PacProxyAgent } from 'pac-proxy-agent';

const CRLF = '\r\n';
const STATUS_REG = /^HTTP\/1.[01] (\d*)/;

// function to create PAC proxy agent
export function createPacAgent(pacUrl, options = {}) {
pacUrl = stripQuotesAndSpaces(pacUrl);
try {
const agent = new PacProxyAgent(pacUrl, {
keepAlive: true,
...options
});

logger('client:proxy').info(`Successfully loaded PAC file from: ${pacUrl}`);
return agent;
} catch (error) {
logger('client:proxy').error(`Failed to load PAC file, error message: ${error.message}, stack: ${error.stack}`);
throw new Error(`Failed to initialize PAC proxy: ${error.message}`);
}
}

// Returns true if the URL hostname matches any patterns
export function hostnameMatches(patterns, url) {
let subject = new URL(url);
Expand Down Expand Up @@ -219,11 +237,31 @@ export function proxyAgentFor(url, options) {
let { protocol, hostname } = new URL(url);
let cachekey = `${protocol}//${hostname}`;

if (!cache.has(cachekey)) {
cache.set(cachekey, protocol === 'https:'
? new ProxyHttpsAgent(options)
: new ProxyHttpAgent(options));
// If we already have a cached agent, return it
if (cache.has(cachekey)) {
return cache.get(cachekey);
}

return cache.get(cachekey);
try {
let agent;
const pacUrl = process.env.PERCY_PAC_FILE_URL;

// If PAC URL is provided, use PAC proxy
if (pacUrl) {
logger('client:proxy').info(`Using PAC file from: ${pacUrl}`);
agent = createPacAgent(pacUrl, options);
} else {
// Fall back to other proxy configuration
agent = protocol === 'https:'
? new ProxyHttpsAgent(options)
: new ProxyHttpAgent(options);
}

// Cache the created agent
cache.set(cachekey, agent);
return agent;
} catch (error) {
logger('client:proxy').error(`Failed to create proxy agent: ${error.message}`);
throw error;
}
}
4 changes: 3 additions & 1 deletion packages/client/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ export async function request(url, options = {}, callback) {
let { protocol, hostname, port, pathname, search, hash } = new URL(url);

// reference the default export so tests can mock it
let { default: http } = await import(protocol === 'https:' ? 'https' : 'http');
// bundling cli inside electron or another package fails if we import it
// like this: await import(protocol === 'https:' ? 'https' : 'http');
let { default: http } = protocol === 'https:' ? await import('https') : await import('http');
let { proxyAgentFor } = await import('./proxy.js');

// automatically stringify body content
Expand Down
23 changes: 21 additions & 2 deletions packages/client/test/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,21 @@ describe('PercyClient', () => {
await logger.mock({ level: 'debug' });
await api.mock();
delete process.env.PERCY_GZIP;

process.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
client = new PercyClient({
token: 'PERCY_TOKEN'
});
});

describe('#userAgent()', () => {
it('uses default package value when env.forcedPkgValue is not set', () => {
delete process.env.PERCY_FORCE_PKG_VALUE;
client = new PercyClient({ token: 'PERCY_TOKEN' });

expect(client.userAgent()).toMatch(
/^Percy\/v1 @percy\/client\/\S+ \(node\/v[\d.]+.*\)$/
);
});
it('contains client and environment information', () => {
expect(client.userAgent()).toMatch(
/^Percy\/v1 @percy\/client\/\S+ \(node\/v[\d.]+.*\)$/
Expand All @@ -38,7 +46,7 @@ describe('PercyClient', () => {
expect(client.userAgent()).toMatch(
/^Percy\/v1 @percy\/client\/\S+ client-info \(env-info; node\/v[\d.]+.*\)$/
);
expect(logger.stderr.length).toEqual(2);
expect(logger.stderr.length).toBeGreaterThanOrEqual(2);
});

it('it logs a debug warning when no info is passed', async () => {
Expand Down Expand Up @@ -98,6 +106,17 @@ describe('PercyClient', () => {
/^Percy\/v1 @percy\/client\/\S+ client-info \(env-info; node\/v[\d.]+.*\)$/
);
});

it('uses forced package value when set', () => {
client.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
client = new PercyClient({
token: 'PERCY_TOKEN'
});
client.env.PERCY_FORCE_PKG_VALUE = JSON.stringify({ name: '@percy/client', version: '1.0.0' });
expect(client.userAgent()).toMatch(
/^Percy\/v1 @percy\/client\/1.0.0 \(node\/v[\d.]+.*\)$/
);
});
});

describe('#get()', () => {
Expand Down
Loading
Loading