From 64a42cb5f49c68e4a4649a928db76c5ece7e7998 Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Wed, 3 Apr 2019 14:01:06 -0500 Subject: [PATCH 01/17] Add hidden snapshot command --- src/commands/snapshot.ts | 101 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/commands/snapshot.ts diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts new file mode 100644 index 00000000..ff939d15 --- /dev/null +++ b/src/commands/snapshot.ts @@ -0,0 +1,101 @@ +import {flags} from '@oclif/command' +import Constants from '../services/constants' +import StaticSnapshotService from '../services/static-snapshot-service' +import PercyCommand from './percy-command' + +export default class Snapshot extends PercyCommand { + static description = 'Snapshot a directory of static site assets' + static hidden = true + + static args = [{ + name: 'staticAssets', + description: 'The path to the compiled static asset directory.', + required: true, + }] + + static examples = [ + '$ percy snapshot _mySite/', + '$ percy snapshot _mySite/ --baseUrl "blog/"', + '$ percy snapshot _mySite/ --widths "320,780,1280"', + ] + + static flags = { + 'snapshot-capture-regex': flags.string({ + char: 'c', + description: 'Regular expression for matching the files to snapshot. Defaults to: "\.(html|htm)$"', + default: '\.(html|htm)$', + }), + 'snapshot-ignore-regex': flags.string({ + char: 'i', + description: 'Regular expression for matching the files to NOT snapshot.', + }), + 'widths': flags.string({ + char: 'w', + description: 'Comma-separated string of rendering widths for snapshots. Ex: 320,1280', + default: '1280', + }), + 'baseUrl': flags.string({ + char: 'b', + description: 'The path that the site will be deployed to on a production server. \ + Use this if your site will be hosted at a non-root url.', + default: '/', + }), + // from exec command. needed to start the agent service. + 'network-idle-timeout': flags.integer({ + char: 't', + default: 50, + description: 'asset discovery network idle timeout (in milliseconds)', + }), + 'port': flags.integer({ + char: 'p', + default: Constants.PORT, + description: 'port', + }), + } + + staticSnapshotService: StaticSnapshotService = new StaticSnapshotService() + + async run() { + await super.run() + + const {args} = this.parse(Snapshot) + const {flags} = this.parse(Snapshot) + + const staticAssetDirectory = args.staticAssets as string + const port = flags.port as number + const portPlusOne = port + 1 + const networkIdleTimeout = flags['network-idle-timeout'] as number + const rawWidths = flags.widths as string + const baseUrl = flags.baseUrl as string + const snapshotIgnoreRegex = flags['snapshot-ignore-regex'] as string + const snapshotCaptureRegex = flags['snapshot-capture-regex'] as string + + // Exit snapshot command if percy will not run + if (!this.percyWillRun()) { this.exit(0) } + + const widths = rawWidths.split(',').map(Number) + + // start the agent service + await this.agentService.start({port, networkIdleTimeout}) + this.logStart() + + // need to start the snapshot service + // NEED A DIFFERENT PORT HERE + const staticSnapshotService = this.staticSnapshotService.start({ + port: portPlusOne, + staticAssetDirectory, + widths, + baseUrl, + snapshotCaptureRegex, + snapshotIgnoreRegex, + }) + + // then wait for the snapshot service to complete + // staticSnapshotService.on('exit', async (code: any) => { + // if (this.percyWillRun()) { + // // and then stop the agent + // await this.agentService.stop() + // } + // }) + } +} From e482c3af39945d4c1ba62d0a47c65d63f6f48356 Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Wed, 3 Apr 2019 14:02:06 -0500 Subject: [PATCH 02/17] Add stubbed static snapshot service --- src/services/static-snapshot-options.ts | 8 ++++++++ src/services/static-snapshot-service.ts | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/services/static-snapshot-options.ts create mode 100644 src/services/static-snapshot-service.ts diff --git a/src/services/static-snapshot-options.ts b/src/services/static-snapshot-options.ts new file mode 100644 index 00000000..85081089 --- /dev/null +++ b/src/services/static-snapshot-options.ts @@ -0,0 +1,8 @@ +export interface StaticSnapshotOptions { + staticAssetDirectory: string, + port: number, + widths: number[], + baseUrl: string, + snapshotCaptureRegex: string, + snapshotIgnoreRegex?: string | undefined, + } diff --git a/src/services/static-snapshot-service.ts b/src/services/static-snapshot-service.ts new file mode 100644 index 00000000..ed568288 --- /dev/null +++ b/src/services/static-snapshot-service.ts @@ -0,0 +1,16 @@ +import logger from '../utils/logger' +import {StaticSnapshotOptions} from './static-snapshot-options' + +export default class StaticSnapshotService { + constructor() { + // logger.info('calling constructor...') + } + + async start(options: StaticSnapshotOptions) { + // logger.info('starting static snapshot service...') + } + + async stop() { + // logger.info('stopping static snapshot service...') + } +} From 37f8c5d0cd0f3d5e248afd492f7056cb77d81a8d Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Wed, 3 Apr 2019 14:02:28 -0500 Subject: [PATCH 03/17] Add snapshot command tests --- test/commands/snapshot.test.ts | 119 +++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 test/commands/snapshot.test.ts diff --git a/test/commands/snapshot.test.ts b/test/commands/snapshot.test.ts new file mode 100644 index 00000000..4c03da22 --- /dev/null +++ b/test/commands/snapshot.test.ts @@ -0,0 +1,119 @@ +import * as chai from 'chai' +import {describe} from 'mocha' +import * as sinon from 'sinon' +import Snapshot from '../../src/commands/snapshot' +import AgentService from '../../src/services/agent-service' +import StaticSnapshotService from '../../src/services/static-snapshot-service' +import {captureStdOut} from '../helpers/stdout' + +import {expect, test} from '@oclif/test' + +describe('snapshot', () => { + describe('#run', () => { + const sandbox = sinon.createSandbox() + + afterEach(() => { + sandbox.restore() + }) + + function AgentServiceStub(): AgentService { + const agentService = AgentService.prototype as AgentService + sandbox.stub(agentService, 'start') + + const start = new Snapshot([], '') as Snapshot + sandbox.stub(start, 'agentService').returns(agentService) + + return agentService + } + + function StaticSnapshotServiceStub(): StaticSnapshotService { + const staticSnapshotService = StaticSnapshotService.prototype as StaticSnapshotService + sandbox.stub(staticSnapshotService, 'start') + + const snapshot = new Snapshot([], '') as Snapshot + sandbox.stub(snapshot, 'staticSnapshotService').returns(staticSnapshotService) + + return staticSnapshotService + } + + it('starts the static snapshot service', async () => { + const expectedAgentOptions = {networkIdleTimeout: 50, port: 5338} + const expectedSnapshotOptions = { + port: 5339, + staticAssetDirectory: './dummy-test-dir', + widths: [1280], + baseUrl: '/', + snapshotCaptureRegex: '\.(html|htm)$', + snapshotIgnoreRegex: undefined, + } + + const agentServiceStub = AgentServiceStub() + const staticSnapshotServiceStub = StaticSnapshotServiceStub() + + const stdout = await captureStdOut(async () => { + await Snapshot.run(['./dummy-test-dir']) + }) + + chai.expect(agentServiceStub.start).to.be.calledWith(expectedAgentOptions) + chai.expect(staticSnapshotServiceStub.start).to.be.calledWith(expectedSnapshotOptions) + chai.expect(stdout).to.match(/\[percy\] percy has started./) + }) + + it('passes the correct args to the static snapshot service', async () => { + const port = 5338 + + const expectedAgentOptions = {networkIdleTimeout: 50, port} + const expectedSnapshotOptions = { + port: port + 1, + staticAssetDirectory: './dummy-test-dir', + widths: [1280], + baseUrl: '/', + snapshotCaptureRegex: 'custom-capture', + snapshotIgnoreRegex: 'custom-ignore', + } + + const snapshotCommandOptions = [ + '-p', + port.toString(), + '-w', + expectedSnapshotOptions.widths.toString(), + '-b', + expectedSnapshotOptions.baseUrl, + '-c', + expectedSnapshotOptions.snapshotCaptureRegex, + '-i', + expectedSnapshotOptions.snapshotIgnoreRegex, + expectedSnapshotOptions.staticAssetDirectory, + ] + + const agentServiceStub = AgentServiceStub() + const staticSnapshotServiceStub = StaticSnapshotServiceStub() + + const stdout = await captureStdOut(async () => { + await Snapshot.run(snapshotCommandOptions) + }) + + chai.expect(stdout).to.match(/\[percy\] percy has started./) + chai.expect(staticSnapshotServiceStub.start).to.be.calledWith(expectedSnapshotOptions) + chai.expect(agentServiceStub.start).to.be.calledWith(expectedAgentOptions) + }) + }) + + describe('snapshot command', () => { + test + .stub(process, 'env', {PERCY_TOKEN: ''}) + .stderr() + .command(['snapshot', './test_dir']) + .exit(0) + .do((output) => expect(output.stderr).to.contain( + 'Warning: Skipping visual tests. PERCY_TOKEN was not provided.', + )) + .it('warns about PERCY_TOKEN not being set and exits gracefully') + + test + .env({PERCY_TOKEN: 'abc'}) + .command(['snapshot']) + .exit(2) + .it('exits when the asset directory arg is missing') + }) +}) From c5f77887768eecb381e0d64973447a1bacd370e9 Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Wed, 3 Apr 2019 15:04:02 -0500 Subject: [PATCH 04/17] Rename the static snapshot service start command --- src/commands/snapshot.ts | 3 +-- src/services/static-snapshot-service.ts | 2 +- test/commands/snapshot.test.ts | 8 ++++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index ff939d15..13280f90 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -80,8 +80,7 @@ export default class Snapshot extends PercyCommand { this.logStart() // need to start the snapshot service - // NEED A DIFFERENT PORT HERE - const staticSnapshotService = this.staticSnapshotService.start({ + const staticSnapshotService = this.staticSnapshotService.snapshot({ port: portPlusOne, staticAssetDirectory, widths, diff --git a/src/services/static-snapshot-service.ts b/src/services/static-snapshot-service.ts index ed568288..8bf07a44 100644 --- a/src/services/static-snapshot-service.ts +++ b/src/services/static-snapshot-service.ts @@ -6,7 +6,7 @@ export default class StaticSnapshotService { // logger.info('calling constructor...') } - async start(options: StaticSnapshotOptions) { + async snapshot(options: StaticSnapshotOptions) { // logger.info('starting static snapshot service...') } diff --git a/test/commands/snapshot.test.ts b/test/commands/snapshot.test.ts index 4c03da22..2c33fc5f 100644 --- a/test/commands/snapshot.test.ts +++ b/test/commands/snapshot.test.ts @@ -1,9 +1,9 @@ import * as chai from 'chai' -import {describe} from 'mocha' import * as sinon from 'sinon' import Snapshot from '../../src/commands/snapshot' import AgentService from '../../src/services/agent-service' import StaticSnapshotService from '../../src/services/static-snapshot-service' +import {describe} from 'mocha' import {captureStdOut} from '../helpers/stdout' import {expect, test} from '@oclif/test' @@ -28,7 +28,7 @@ describe('snapshot', () => { function StaticSnapshotServiceStub(): StaticSnapshotService { const staticSnapshotService = StaticSnapshotService.prototype as StaticSnapshotService - sandbox.stub(staticSnapshotService, 'start') + sandbox.stub(staticSnapshotService, 'snapshot') const snapshot = new Snapshot([], '') as Snapshot sandbox.stub(snapshot, 'staticSnapshotService').returns(staticSnapshotService) @@ -55,7 +55,7 @@ describe('snapshot', () => { }) chai.expect(agentServiceStub.start).to.be.calledWith(expectedAgentOptions) - chai.expect(staticSnapshotServiceStub.start).to.be.calledWith(expectedSnapshotOptions) + chai.expect(staticSnapshotServiceStub.snapshot).to.be.calledWith(expectedSnapshotOptions) chai.expect(stdout).to.match(/\[percy\] percy has started./) }) @@ -94,7 +94,7 @@ describe('snapshot', () => { }) chai.expect(stdout).to.match(/\[percy\] percy has started./) - chai.expect(staticSnapshotServiceStub.start).to.be.calledWith(expectedSnapshotOptions) + chai.expect(staticSnapshotServiceStub.snapshot).to.be.calledWith(expectedSnapshotOptions) chai.expect(agentServiceStub.start).to.be.calledWith(expectedAgentOptions) }) }) From 409e9d0245cc8a1d082a73eb2493b4653484b0c0 Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Wed, 10 Apr 2019 14:09:54 -0500 Subject: [PATCH 05/17] Update snapshot command and associated tests --- src/commands/snapshot.ts | 38 +++++---- src/services/static-snapshot-options.ts | 2 +- src/services/static-snapshot-service.ts | 8 +- test/commands/snapshot.test.ts | 101 ++++++++++++------------ 4 files changed, 77 insertions(+), 72 deletions(-) diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index 13280f90..cacfa8a8 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -1,5 +1,6 @@ import {flags} from '@oclif/command' import Constants from '../services/constants' +import {StaticSnapshotOptions} from '../services/static-snapshot-options' import StaticSnapshotService from '../services/static-snapshot-service' import PercyCommand from './percy-command' @@ -17,6 +18,7 @@ export default class Snapshot extends PercyCommand { '$ percy snapshot _mySite/', '$ percy snapshot _mySite/ --baseUrl "blog/"', '$ percy snapshot _mySite/ --widths "320,780,1280"', + '$ percy snapshot _mySite/ --ignore-folders "Tmp,_secrets,node_modules"', ] static flags = { @@ -25,9 +27,9 @@ export default class Snapshot extends PercyCommand { description: 'Regular expression for matching the files to snapshot. Defaults to: "\.(html|htm)$"', default: '\.(html|htm)$', }), - 'snapshot-ignore-regex': flags.string({ + 'ignore-folders': flags.string({ char: 'i', - description: 'Regular expression for matching the files to NOT snapshot.', + description: 'Comma-seperated string of folders to ignore. Ex: Tmp,_secrets,node_modules', }), 'widths': flags.string({ char: 'w', @@ -53,8 +55,6 @@ export default class Snapshot extends PercyCommand { }), } - staticSnapshotService: StaticSnapshotService = new StaticSnapshotService() - async run() { await super.run() @@ -67,34 +67,38 @@ export default class Snapshot extends PercyCommand { const networkIdleTimeout = flags['network-idle-timeout'] as number const rawWidths = flags.widths as string const baseUrl = flags.baseUrl as string - const snapshotIgnoreRegex = flags['snapshot-ignore-regex'] as string + const rawIgnoreFolders = flags['ignore-folders'] as string const snapshotCaptureRegex = flags['snapshot-capture-regex'] as string - // Exit snapshot command if percy will not run + // exit gracefully if percy will not run if (!this.percyWillRun()) { this.exit(0) } const widths = rawWidths.split(',').map(Number) + const ignoreFolders = rawIgnoreFolders.split(',') // start the agent service await this.agentService.start({port, networkIdleTimeout}) this.logStart() - // need to start the snapshot service - const staticSnapshotService = this.staticSnapshotService.snapshot({ + const options: StaticSnapshotOptions = { port: portPlusOne, staticAssetDirectory, widths, baseUrl, snapshotCaptureRegex, - snapshotIgnoreRegex, - }) + ignoreFolders, + } + + const staticSnapshotService = new StaticSnapshotService(options) + + // start the snapshot service + staticSnapshotService.start() + + // take the snapshots + await staticSnapshotService.snapshotAll() - // then wait for the snapshot service to complete - // staticSnapshotService.on('exit', async (code: any) => { - // if (this.percyWillRun()) { - // // and then stop the agent - // await this.agentService.stop() - // } - // }) + // stop the static snapshot and agent services + await staticSnapshotService.stop() + await this.agentService.stop() } } diff --git a/src/services/static-snapshot-options.ts b/src/services/static-snapshot-options.ts index 85081089..c895144d 100644 --- a/src/services/static-snapshot-options.ts +++ b/src/services/static-snapshot-options.ts @@ -4,5 +4,5 @@ export interface StaticSnapshotOptions { widths: number[], baseUrl: string, snapshotCaptureRegex: string, - snapshotIgnoreRegex?: string | undefined, + ignoreFolders?: string[] | undefined, } diff --git a/src/services/static-snapshot-service.ts b/src/services/static-snapshot-service.ts index 8bf07a44..65dded53 100644 --- a/src/services/static-snapshot-service.ts +++ b/src/services/static-snapshot-service.ts @@ -2,14 +2,18 @@ import logger from '../utils/logger' import {StaticSnapshotOptions} from './static-snapshot-options' export default class StaticSnapshotService { - constructor() { + constructor(options: StaticSnapshotOptions) { // logger.info('calling constructor...') } - async snapshot(options: StaticSnapshotOptions) { + async start() { // logger.info('starting static snapshot service...') } + async snapshotAll() { + // logger.info('taking snapshots of the static site...') + } + async stop() { // logger.info('stopping static snapshot service...') } diff --git a/test/commands/snapshot.test.ts b/test/commands/snapshot.test.ts index 2c33fc5f..30ea5cb4 100644 --- a/test/commands/snapshot.test.ts +++ b/test/commands/snapshot.test.ts @@ -1,9 +1,9 @@ import * as chai from 'chai' +import {describe} from 'mocha' import * as sinon from 'sinon' import Snapshot from '../../src/commands/snapshot' import AgentService from '../../src/services/agent-service' import StaticSnapshotService from '../../src/services/static-snapshot-service' -import {describe} from 'mocha' import {captureStdOut} from '../helpers/stdout' import {expect, test} from '@oclif/test' @@ -28,24 +28,14 @@ describe('snapshot', () => { function StaticSnapshotServiceStub(): StaticSnapshotService { const staticSnapshotService = StaticSnapshotService.prototype as StaticSnapshotService - sandbox.stub(staticSnapshotService, 'snapshot') - - const snapshot = new Snapshot([], '') as Snapshot - sandbox.stub(snapshot, 'staticSnapshotService').returns(staticSnapshotService) + sandbox.stub(staticSnapshotService, 'snapshotAll') + sandbox.stub(staticSnapshotService, 'start') return staticSnapshotService } it('starts the static snapshot service', async () => { const expectedAgentOptions = {networkIdleTimeout: 50, port: 5338} - const expectedSnapshotOptions = { - port: 5339, - staticAssetDirectory: './dummy-test-dir', - widths: [1280], - baseUrl: '/', - snapshotCaptureRegex: '\.(html|htm)$', - snapshotIgnoreRegex: undefined, - } const agentServiceStub = AgentServiceStub() const staticSnapshotServiceStub = StaticSnapshotServiceStub() @@ -55,48 +45,55 @@ describe('snapshot', () => { }) chai.expect(agentServiceStub.start).to.be.calledWith(expectedAgentOptions) - chai.expect(staticSnapshotServiceStub.snapshot).to.be.calledWith(expectedSnapshotOptions) + chai.expect(staticSnapshotServiceStub.start).to.have.callCount(1) + chai.expect(staticSnapshotServiceStub.snapshotAll).to.have.callCount(1) chai.expect(stdout).to.match(/\[percy\] percy has started./) }) - it('passes the correct args to the static snapshot service', async () => { - const port = 5338 - - const expectedAgentOptions = {networkIdleTimeout: 50, port} - const expectedSnapshotOptions = { - port: port + 1, - staticAssetDirectory: './dummy-test-dir', - widths: [1280], - baseUrl: '/', - snapshotCaptureRegex: 'custom-capture', - snapshotIgnoreRegex: 'custom-ignore', - } - - const snapshotCommandOptions = [ - '-p', - port.toString(), - '-w', - expectedSnapshotOptions.widths.toString(), - '-b', - expectedSnapshotOptions.baseUrl, - '-c', - expectedSnapshotOptions.snapshotCaptureRegex, - '-i', - expectedSnapshotOptions.snapshotIgnoreRegex, - expectedSnapshotOptions.staticAssetDirectory, - ] - - const agentServiceStub = AgentServiceStub() - const staticSnapshotServiceStub = StaticSnapshotServiceStub() - - const stdout = await captureStdOut(async () => { - await Snapshot.run(snapshotCommandOptions) - }) - - chai.expect(stdout).to.match(/\[percy\] percy has started./) - chai.expect(staticSnapshotServiceStub.snapshot).to.be.calledWith(expectedSnapshotOptions) - chai.expect(agentServiceStub.start).to.be.calledWith(expectedAgentOptions) - }) + // todo: how to test that the flags are being passed to the service correctly? + xit('starts the snapshot service on the correct port') + xit('passes the correct args to the snapshotAll command') + + // old way of testing flags + // it('passes the correct args to the static snapshot service', async () => { + // const port = 5338 + + // const expectedAgentOptions = {networkIdleTimeout: 50, port} + // const expectedSnapshotOptions = { + // port: port + 1, + // staticAssetDirectory: './dummy-test-dir', + // widths: [1280], + // baseUrl: '/', + // snapshotCaptureRegex: 'custom-capture', + // snapshotIgnoreRegex: 'custom-ignore', + // } + + // const snapshotCommandOptions = [ + // '-p', + // port.toString(), + // '-w', + // expectedSnapshotOptions.widths.toString(), + // '-b', + // expectedSnapshotOptions.baseUrl, + // '-c', + // expectedSnapshotOptions.snapshotCaptureRegex, + // '-i', + // expectedSnapshotOptions.snapshotIgnoreRegex, + // expectedSnapshotOptions.staticAssetDirectory, + // ] + + // const agentServiceStub = AgentServiceStub() + // const staticSnapshotServiceStub = StaticSnapshotServiceStub() + + // const stdout = await captureStdOut(async () => { + // await Snapshot.run(snapshotCommandOptions) + // }) + + // chai.expect(stdout).to.match(/\[percy\] percy has started./) + + // chai.expect(staticSnapshotServiceStub.snapshot).to.be.calledWith(expectedSnapshotOptions) + // chai.expect(agentServiceStub.start).to.be.calledWith(expectedAgentOptions) + // }) }) describe('snapshot command', () => { From 5de524c6ba73b42b30556e68d5362e95c963ed98 Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Wed, 10 Apr 2019 14:18:17 -0500 Subject: [PATCH 06/17] Fix broken test --- src/commands/snapshot.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index cacfa8a8..8c7e3ca9 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -30,6 +30,7 @@ export default class Snapshot extends PercyCommand { 'ignore-folders': flags.string({ char: 'i', description: 'Comma-seperated string of folders to ignore. Ex: Tmp,_secrets,node_modules', + default: '', }), 'widths': flags.string({ char: 'w', @@ -74,7 +75,7 @@ export default class Snapshot extends PercyCommand { if (!this.percyWillRun()) { this.exit(0) } const widths = rawWidths.split(',').map(Number) - const ignoreFolders = rawIgnoreFolders.split(',') + const ignoreFolders = rawIgnoreFolders ? rawIgnoreFolders.split(',') : undefined // start the agent service await this.agentService.start({port, networkIdleTimeout}) From 1149bcbacb66fb8d6ac3a4b1e53ffb069cdd9f81 Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Fri, 12 Apr 2019 16:53:35 -0500 Subject: [PATCH 07/17] Incorporate PR feedback --- src/commands/snapshot.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index 8c7e3ca9..5710297d 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -5,12 +5,12 @@ import StaticSnapshotService from '../services/static-snapshot-service' import PercyCommand from './percy-command' export default class Snapshot extends PercyCommand { - static description = 'Snapshot a directory of static site assets' + static description = 'Snapshot a directory of webpages' static hidden = true static args = [{ - name: 'staticAssets', - description: 'The path to the compiled static asset directory.', + name: 'snapshotDirectory', + description: 'A path to the directory you would like to snapshot', required: true, }] @@ -24,7 +24,7 @@ export default class Snapshot extends PercyCommand { static flags = { 'snapshot-capture-regex': flags.string({ char: 'c', - description: 'Regular expression for matching the files to snapshot. Defaults to: "\.(html|htm)$"', + description: 'Regular expression for matching the files to snapshot.', default: '\.(html|htm)$', }), 'ignore-folders': flags.string({ @@ -34,7 +34,7 @@ export default class Snapshot extends PercyCommand { }), 'widths': flags.string({ char: 'w', - description: 'Comma-separated string of rendering widths for snapshots. Ex: 320,1280', + description: 'Comma-separated string of rendering widths for snapshots.', default: '1280', }), 'baseUrl': flags.string({ @@ -59,8 +59,7 @@ export default class Snapshot extends PercyCommand { async run() { await super.run() - const {args} = this.parse(Snapshot) - const {flags} = this.parse(Snapshot) + const {args, flags} = this.parse(Snapshot) const staticAssetDirectory = args.staticAssets as string const port = flags.port as number @@ -93,7 +92,7 @@ export default class Snapshot extends PercyCommand { const staticSnapshotService = new StaticSnapshotService(options) // start the snapshot service - staticSnapshotService.start() + await staticSnapshotService.start() // take the snapshots await staticSnapshotService.snapshotAll() From f4b1428e29ca088c31286647aca268c44d00b6e3 Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Fri, 12 Apr 2019 17:14:21 -0500 Subject: [PATCH 08/17] Move network-idle-timout into constants file --- src/commands/exec.ts | 2 +- src/commands/snapshot.ts | 2 +- src/commands/start.ts | 2 +- src/services/constants.ts | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/commands/exec.ts b/src/commands/exec.ts index 2165df46..dd2dc6d1 100644 --- a/src/commands/exec.ts +++ b/src/commands/exec.ts @@ -16,7 +16,7 @@ export default class Exec extends PercyCommand { static flags = { 'network-idle-timeout': flags.integer({ char: 't', - default: 50, + default: Constants.NETWORK_IDLE_TIMEOUT, description: 'asset discovery network idle timeout (in milliseconds)', }), 'port': flags.integer({ diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index 5710297d..6347c4c8 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -46,7 +46,7 @@ export default class Snapshot extends PercyCommand { // from exec command. needed to start the agent service. 'network-idle-timeout': flags.integer({ char: 't', - default: 50, + default: Constants.NETWORK_IDLE_TIMEOUT, description: 'asset discovery network idle timeout (in milliseconds)', }), 'port': flags.integer({ diff --git a/src/commands/start.ts b/src/commands/start.ts index 5c5d5fb7..bfee6b61 100644 --- a/src/commands/start.ts +++ b/src/commands/start.ts @@ -21,7 +21,7 @@ export default class Start extends PercyCommand { }), 'network-idle-timeout': flags.integer({ char: 't', - default: 50, + default: Constants.NETWORK_IDLE_TIMEOUT, description: 'asset discovery network idle timeout (in milliseconds)', }), 'port': flags.integer({ diff --git a/src/services/constants.ts b/src/services/constants.ts index 72cab3f3..1263f9da 100644 --- a/src/services/constants.ts +++ b/src/services/constants.ts @@ -1,5 +1,6 @@ export default class Constants { static readonly PORT: number = 5338 + static readonly NETWORK_IDLE_TIMEOUT: number = 50 // in milliseconds // Agent Service paths static readonly SNAPSHOT_PATH = '/percy/snapshot' From ce050e09e3fe0109f6d8f740827b4c5c65303bfe Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Fri, 12 Apr 2019 20:18:56 -0500 Subject: [PATCH 09/17] Remove widths flag --- src/commands/snapshot.ts | 9 --------- src/services/static-snapshot-options.ts | 1 - 2 files changed, 10 deletions(-) diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index 6347c4c8..ade4df34 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -17,7 +17,6 @@ export default class Snapshot extends PercyCommand { static examples = [ '$ percy snapshot _mySite/', '$ percy snapshot _mySite/ --baseUrl "blog/"', - '$ percy snapshot _mySite/ --widths "320,780,1280"', '$ percy snapshot _mySite/ --ignore-folders "Tmp,_secrets,node_modules"', ] @@ -32,11 +31,6 @@ export default class Snapshot extends PercyCommand { description: 'Comma-seperated string of folders to ignore. Ex: Tmp,_secrets,node_modules', default: '', }), - 'widths': flags.string({ - char: 'w', - description: 'Comma-separated string of rendering widths for snapshots.', - default: '1280', - }), 'baseUrl': flags.string({ char: 'b', description: 'The path that the site will be deployed to on a production server. \ @@ -65,7 +59,6 @@ export default class Snapshot extends PercyCommand { const port = flags.port as number const portPlusOne = port + 1 const networkIdleTimeout = flags['network-idle-timeout'] as number - const rawWidths = flags.widths as string const baseUrl = flags.baseUrl as string const rawIgnoreFolders = flags['ignore-folders'] as string const snapshotCaptureRegex = flags['snapshot-capture-regex'] as string @@ -73,7 +66,6 @@ export default class Snapshot extends PercyCommand { // exit gracefully if percy will not run if (!this.percyWillRun()) { this.exit(0) } - const widths = rawWidths.split(',').map(Number) const ignoreFolders = rawIgnoreFolders ? rawIgnoreFolders.split(',') : undefined // start the agent service @@ -83,7 +75,6 @@ export default class Snapshot extends PercyCommand { const options: StaticSnapshotOptions = { port: portPlusOne, staticAssetDirectory, - widths, baseUrl, snapshotCaptureRegex, ignoreFolders, diff --git a/src/services/static-snapshot-options.ts b/src/services/static-snapshot-options.ts index c895144d..f3afcbbd 100644 --- a/src/services/static-snapshot-options.ts +++ b/src/services/static-snapshot-options.ts @@ -1,7 +1,6 @@ export interface StaticSnapshotOptions { staticAssetDirectory: string, port: number, - widths: number[], baseUrl: string, snapshotCaptureRegex: string, ignoreFolders?: string[] | undefined, From 1d468a55281c1448a10d7d045584c3b4d31c4465 Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Fri, 12 Apr 2019 20:23:44 -0500 Subject: [PATCH 10/17] Change snapshot file capture flag name --- src/commands/snapshot.ts | 6 +++--- src/services/static-snapshot-options.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index ade4df34..e5a17460 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -21,7 +21,7 @@ export default class Snapshot extends PercyCommand { ] static flags = { - 'snapshot-capture-regex': flags.string({ + 'snapshot-files': flags.string({ char: 'c', description: 'Regular expression for matching the files to snapshot.', default: '\.(html|htm)$', @@ -61,7 +61,7 @@ export default class Snapshot extends PercyCommand { const networkIdleTimeout = flags['network-idle-timeout'] as number const baseUrl = flags.baseUrl as string const rawIgnoreFolders = flags['ignore-folders'] as string - const snapshotCaptureRegex = flags['snapshot-capture-regex'] as string + const snapshotFilesRegex = flags['snapshot-files'] as string // exit gracefully if percy will not run if (!this.percyWillRun()) { this.exit(0) } @@ -76,7 +76,7 @@ export default class Snapshot extends PercyCommand { port: portPlusOne, staticAssetDirectory, baseUrl, - snapshotCaptureRegex, + snapshotFilesRegex, ignoreFolders, } diff --git a/src/services/static-snapshot-options.ts b/src/services/static-snapshot-options.ts index f3afcbbd..3dc33f9e 100644 --- a/src/services/static-snapshot-options.ts +++ b/src/services/static-snapshot-options.ts @@ -2,6 +2,6 @@ export interface StaticSnapshotOptions { staticAssetDirectory: string, port: number, baseUrl: string, - snapshotCaptureRegex: string, + snapshotFilesRegex: string, ignoreFolders?: string[] | undefined, } From baf61ae78eba099dd075972ad8d9fc1e72730e56 Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Fri, 12 Apr 2019 20:28:42 -0500 Subject: [PATCH 11/17] Rename ignore files regex flag --- src/commands/snapshot.ts | 8 +++----- src/services/static-snapshot-options.ts | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index e5a17460..2e15c472 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -26,7 +26,7 @@ export default class Snapshot extends PercyCommand { description: 'Regular expression for matching the files to snapshot.', default: '\.(html|htm)$', }), - 'ignore-folders': flags.string({ + 'ignore-files': flags.string({ char: 'i', description: 'Comma-seperated string of folders to ignore. Ex: Tmp,_secrets,node_modules', default: '', @@ -60,14 +60,12 @@ export default class Snapshot extends PercyCommand { const portPlusOne = port + 1 const networkIdleTimeout = flags['network-idle-timeout'] as number const baseUrl = flags.baseUrl as string - const rawIgnoreFolders = flags['ignore-folders'] as string + const ignoreFilesRegex = flags['ignore-files'] as string const snapshotFilesRegex = flags['snapshot-files'] as string // exit gracefully if percy will not run if (!this.percyWillRun()) { this.exit(0) } - const ignoreFolders = rawIgnoreFolders ? rawIgnoreFolders.split(',') : undefined - // start the agent service await this.agentService.start({port, networkIdleTimeout}) this.logStart() @@ -77,7 +75,7 @@ export default class Snapshot extends PercyCommand { staticAssetDirectory, baseUrl, snapshotFilesRegex, - ignoreFolders, + ignoreFilesRegex, } const staticSnapshotService = new StaticSnapshotService(options) diff --git a/src/services/static-snapshot-options.ts b/src/services/static-snapshot-options.ts index 3dc33f9e..5b425998 100644 --- a/src/services/static-snapshot-options.ts +++ b/src/services/static-snapshot-options.ts @@ -3,5 +3,5 @@ export interface StaticSnapshotOptions { port: number, baseUrl: string, snapshotFilesRegex: string, - ignoreFolders?: string[] | undefined, + ignoreFilesRegex?: string, } From 1f7623b1b714b38c6095894c599e957e97d48e6d Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Fri, 12 Apr 2019 20:32:57 -0500 Subject: [PATCH 12/17] Incorporate PR feedback --- src/commands/snapshot.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index 2e15c472..b44c9e18 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -15,9 +15,9 @@ export default class Snapshot extends PercyCommand { }] static examples = [ - '$ percy snapshot _mySite/', - '$ percy snapshot _mySite/ --baseUrl "blog/"', - '$ percy snapshot _mySite/ --ignore-folders "Tmp,_secrets,node_modules"', + '$ percy snapshot _site/', + '$ percy snapshot _site/ --baseUrl "blog/"', + '$ percy snapshot _site/ --ignore-files "\.(blog|docs)$"', ] static flags = { @@ -31,7 +31,7 @@ export default class Snapshot extends PercyCommand { description: 'Comma-seperated string of folders to ignore. Ex: Tmp,_secrets,node_modules', default: '', }), - 'baseUrl': flags.string({ + 'base-url': flags.string({ char: 'b', description: 'The path that the site will be deployed to on a production server. \ Use this if your site will be hosted at a non-root url.', @@ -57,9 +57,9 @@ export default class Snapshot extends PercyCommand { const staticAssetDirectory = args.staticAssets as string const port = flags.port as number - const portPlusOne = port + 1 + const staticServerPort = port + 1 const networkIdleTimeout = flags['network-idle-timeout'] as number - const baseUrl = flags.baseUrl as string + const baseUrl = flags['base-url'] as string const ignoreFilesRegex = flags['ignore-files'] as string const snapshotFilesRegex = flags['snapshot-files'] as string @@ -71,7 +71,7 @@ export default class Snapshot extends PercyCommand { this.logStart() const options: StaticSnapshotOptions = { - port: portPlusOne, + port: staticServerPort, staticAssetDirectory, baseUrl, snapshotFilesRegex, From 5b085ba416fbdecd47d5712c32f8c1f6cd9e889d Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Mon, 15 Apr 2019 16:11:30 -0500 Subject: [PATCH 13/17] Incorporate PR feedback --- src/commands/snapshot.ts | 8 ++++---- src/services/static-snapshot-options.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index b44c9e18..213a4ed9 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -16,7 +16,7 @@ export default class Snapshot extends PercyCommand { static examples = [ '$ percy snapshot _site/', - '$ percy snapshot _site/ --baseUrl "blog/"', + '$ percy snapshot _site/ --base-url "blog/"', '$ percy snapshot _site/ --ignore-files "\.(blog|docs)$"', ] @@ -28,7 +28,7 @@ export default class Snapshot extends PercyCommand { }), 'ignore-files': flags.string({ char: 'i', - description: 'Comma-seperated string of folders to ignore. Ex: Tmp,_secrets,node_modules', + description: 'Regular expression for matching the files to ignore.', default: '', }), 'base-url': flags.string({ @@ -55,7 +55,7 @@ export default class Snapshot extends PercyCommand { const {args, flags} = this.parse(Snapshot) - const staticAssetDirectory = args.staticAssets as string + const snapshotDirectory = args.snapshotDirectory as string const port = flags.port as number const staticServerPort = port + 1 const networkIdleTimeout = flags['network-idle-timeout'] as number @@ -72,7 +72,7 @@ export default class Snapshot extends PercyCommand { const options: StaticSnapshotOptions = { port: staticServerPort, - staticAssetDirectory, + snapshotDirectory, baseUrl, snapshotFilesRegex, ignoreFilesRegex, diff --git a/src/services/static-snapshot-options.ts b/src/services/static-snapshot-options.ts index 5b425998..d936e2a4 100644 --- a/src/services/static-snapshot-options.ts +++ b/src/services/static-snapshot-options.ts @@ -1,5 +1,5 @@ export interface StaticSnapshotOptions { - staticAssetDirectory: string, + snapshotDirectory: string, port: number, baseUrl: string, snapshotFilesRegex: string, From cd99901392d8b02c0a834fc10af30a9e2af1d8f7 Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Mon, 15 Apr 2019 16:23:53 -0500 Subject: [PATCH 14/17] Remove unused test code --- test/commands/snapshot.test.ts | 43 ---------------------------------- 1 file changed, 43 deletions(-) diff --git a/test/commands/snapshot.test.ts b/test/commands/snapshot.test.ts index 30ea5cb4..93a1be4a 100644 --- a/test/commands/snapshot.test.ts +++ b/test/commands/snapshot.test.ts @@ -50,50 +50,7 @@ describe('snapshot', () => { chai.expect(stdout).to.match(/\[percy\] percy has started./) }) - // todo: how to test that the flags are being passed to the service correctly? xit('starts the snapshot service on the correct port') - xit('passes the correct args to the snapshotAll command') - - // old way of testing flags - // it('passes the correct args to the static snapshot service', async () => { - // const port = 5338 - - // const expectedAgentOptions = {networkIdleTimeout: 50, port} - // const expectedSnapshotOptions = { - // port: port + 1, - // staticAssetDirectory: './dummy-test-dir', - // widths: [1280], - // baseUrl: '/', - // snapshotCaptureRegex: 'custom-capture', - // snapshotIgnoreRegex: 'custom-ignore', - // } - - // const snapshotCommandOptions = [ - // '-p', - // port.toString(), - // '-w', - // expectedSnapshotOptions.widths.toString(), - // '-b', - // expectedSnapshotOptions.baseUrl, - // '-c', - // expectedSnapshotOptions.snapshotCaptureRegex, - // '-i', - // expectedSnapshotOptions.snapshotIgnoreRegex, - // expectedSnapshotOptions.staticAssetDirectory, - // ] - - // const agentServiceStub = AgentServiceStub() - // const staticSnapshotServiceStub = StaticSnapshotServiceStub() - - // const stdout = await captureStdOut(async () => { - // await Snapshot.run(snapshotCommandOptions) - // }) - - // chai.expect(stdout).to.match(/\[percy\] percy has started./) - - // chai.expect(staticSnapshotServiceStub.snapshot).to.be.calledWith(expectedSnapshotOptions) - // chai.expect(agentServiceStub.start).to.be.calledWith(expectedAgentOptions) - // }) }) describe('snapshot command', () => { From 07d3e5a31279aa64cf6a27d64f34273ca8163d3b Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Tue, 16 Apr 2019 11:04:22 -0500 Subject: [PATCH 15/17] Incorporate feedback and add check for base-url slashes --- src/commands/snapshot.ts | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index 213a4ed9..1b53953c 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -2,6 +2,7 @@ import {flags} from '@oclif/command' import Constants from '../services/constants' import {StaticSnapshotOptions} from '../services/static-snapshot-options' import StaticSnapshotService from '../services/static-snapshot-service' +import logger from '../utils/logger' import PercyCommand from './percy-command' export default class Snapshot extends PercyCommand { @@ -16,7 +17,7 @@ export default class Snapshot extends PercyCommand { static examples = [ '$ percy snapshot _site/', - '$ percy snapshot _site/ --base-url "blog/"', + '$ percy snapshot _site/ --base-url "/blog/"', '$ percy snapshot _site/ --ignore-files "\.(blog|docs)$"', ] @@ -33,8 +34,8 @@ export default class Snapshot extends PercyCommand { }), 'base-url': flags.string({ char: 'b', - description: 'The path that the site will be deployed to on a production server. \ - Use this if your site will be hosted at a non-root url.', + description: 'If your static files will be hosted in a subdirectory, instead \n' + + 'of the webserver\'s root path, set that subdirectory with this flag.', default: '/', }), // from exec command. needed to start the agent service. @@ -55,6 +56,8 @@ export default class Snapshot extends PercyCommand { const {args, flags} = this.parse(Snapshot) + const isWindows = process.platform === 'win32' + const snapshotDirectory = args.snapshotDirectory as string const port = flags.port as number const staticServerPort = port + 1 @@ -66,6 +69,13 @@ export default class Snapshot extends PercyCommand { // exit gracefully if percy will not run if (!this.percyWillRun()) { this.exit(0) } + // check that base url starts with a slash and exit if it is missing + if (isWindows) { + this.checkForWrappingSlashes(baseUrl, '\\') + } else { + this.checkForWrappingSlashes(baseUrl, '/') + } + // start the agent service await this.agentService.start({port, networkIdleTimeout}) this.logStart() @@ -90,4 +100,11 @@ export default class Snapshot extends PercyCommand { await staticSnapshotService.stop() await this.agentService.stop() } + + private checkForWrappingSlashes(url: string, slash: string) { + if (url[0] !== slash || url[url.length - 1] !== slash) { + logger.warn('The base-url flag must begin and end with a slash.') + this.exit(1) + } + } } From b33b65756a831d0907b9aa21aec4a2878e056e7f Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Tue, 16 Apr 2019 12:59:21 -0500 Subject: [PATCH 16/17] Remove unnecessary windows slash check --- src/commands/snapshot.ts | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index 1b53953c..f928d41c 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -17,7 +17,7 @@ export default class Snapshot extends PercyCommand { static examples = [ '$ percy snapshot _site/', - '$ percy snapshot _site/ --base-url "/blog/"', + '$ percy snapshot _site/ --base-url "/blog"', '$ percy snapshot _site/ --ignore-files "\.(blog|docs)$"', ] @@ -69,11 +69,10 @@ export default class Snapshot extends PercyCommand { // exit gracefully if percy will not run if (!this.percyWillRun()) { this.exit(0) } - // check that base url starts with a slash and exit if it is missing - if (isWindows) { - this.checkForWrappingSlashes(baseUrl, '\\') - } else { - this.checkForWrappingSlashes(baseUrl, '/') + // check that base url starts with a slash and exit if it is missing + if (baseUrl[0] !== '/') { + logger.warn('The base-url flag must begin with a slash.') + this.exit(1) } // start the agent service @@ -100,11 +99,4 @@ export default class Snapshot extends PercyCommand { await staticSnapshotService.stop() await this.agentService.stop() } - - private checkForWrappingSlashes(url: string, slash: string) { - if (url[0] !== slash || url[url.length - 1] !== slash) { - logger.warn('The base-url flag must begin and end with a slash.') - this.exit(1) - } - } } From c096fd75c33d23ca12c8dd379688fb62e3ba199b Mon Sep 17 00:00:00 2001 From: Michael Padon Date: Tue, 16 Apr 2019 13:08:19 -0500 Subject: [PATCH 17/17] Update wording --- src/commands/snapshot.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/snapshot.ts b/src/commands/snapshot.ts index f928d41c..2f777b24 100644 --- a/src/commands/snapshot.ts +++ b/src/commands/snapshot.ts @@ -6,7 +6,7 @@ import logger from '../utils/logger' import PercyCommand from './percy-command' export default class Snapshot extends PercyCommand { - static description = 'Snapshot a directory of webpages' + static description = 'Snapshot a directory containing a pre-built static website' static hidden = true static args = [{ @@ -42,12 +42,12 @@ export default class Snapshot extends PercyCommand { 'network-idle-timeout': flags.integer({ char: 't', default: Constants.NETWORK_IDLE_TIMEOUT, - description: 'asset discovery network idle timeout (in milliseconds)', + description: 'Asset discovery network idle timeout (in milliseconds)', }), 'port': flags.integer({ char: 'p', default: Constants.PORT, - description: 'port', + description: 'Port', }), }