Skip to content

Commit

Permalink
feat: Add hidden snapshot command for future implementation (#120)
Browse files Browse the repository at this point in the history
* Add hidden snapshot command

* Add stubbed static snapshot service

* Add snapshot command tests

* Rename the static snapshot service start command

* Update snapshot command and associated tests

* Fix broken test

* Incorporate PR feedback

* Move network-idle-timout into constants file

* Remove widths flag

* Change snapshot file capture flag name

* Rename ignore files regex flag

* Incorporate PR feedback

* Incorporate PR feedback

* Remove unused test code

* Incorporate feedback and add check for base-url slashes

* Remove unnecessary windows slash check

* Update wording
  • Loading branch information
maprules1000 authored Apr 16, 2019
1 parent 8c33b79 commit 98ae4b8
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/commands/exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
102 changes: 102 additions & 0 deletions src/commands/snapshot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
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 {
static description = 'Snapshot a directory containing a pre-built static website'
static hidden = true

static args = [{
name: 'snapshotDirectory',
description: 'A path to the directory you would like to snapshot',
required: true,
}]

static examples = [
'$ percy snapshot _site/',
'$ percy snapshot _site/ --base-url "/blog"',
'$ percy snapshot _site/ --ignore-files "\.(blog|docs)$"',
]

static flags = {
'snapshot-files': flags.string({
char: 'c',
description: 'Regular expression for matching the files to snapshot.',
default: '\.(html|htm)$',
}),
'ignore-files': flags.string({
char: 'i',
description: 'Regular expression for matching the files to ignore.',
default: '',
}),
'base-url': flags.string({
char: 'b',
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.
'network-idle-timeout': flags.integer({
char: 't',
default: Constants.NETWORK_IDLE_TIMEOUT,
description: 'Asset discovery network idle timeout (in milliseconds)',
}),
'port': flags.integer({
char: 'p',
default: Constants.PORT,
description: 'Port',
}),
}

async run() {
await super.run()

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
const networkIdleTimeout = flags['network-idle-timeout'] as number
const baseUrl = flags['base-url'] 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) }

// 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
await this.agentService.start({port, networkIdleTimeout})
this.logStart()

const options: StaticSnapshotOptions = {
port: staticServerPort,
snapshotDirectory,
baseUrl,
snapshotFilesRegex,
ignoreFilesRegex,
}

const staticSnapshotService = new StaticSnapshotService(options)

// start the snapshot service
await staticSnapshotService.start()

// take the snapshots
await staticSnapshotService.snapshotAll()

// stop the static snapshot and agent services
await staticSnapshotService.stop()
await this.agentService.stop()
}
}
2 changes: 1 addition & 1 deletion src/commands/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
1 change: 1 addition & 0 deletions src/services/constants.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
7 changes: 7 additions & 0 deletions src/services/static-snapshot-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface StaticSnapshotOptions {
snapshotDirectory: string,
port: number,
baseUrl: string,
snapshotFilesRegex: string,
ignoreFilesRegex?: string,
}
20 changes: 20 additions & 0 deletions src/services/static-snapshot-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import logger from '../utils/logger'
import {StaticSnapshotOptions} from './static-snapshot-options'

export default class StaticSnapshotService {
constructor(options: StaticSnapshotOptions) {
// logger.info('calling constructor...')
}

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...')
}
}
73 changes: 73 additions & 0 deletions test/commands/snapshot.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
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, 'snapshotAll')
sandbox.stub(staticSnapshotService, 'start')

return staticSnapshotService
}

it('starts the static snapshot service', async () => {
const expectedAgentOptions = {networkIdleTimeout: 50, port: 5338}

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.have.callCount(1)
chai.expect(staticSnapshotServiceStub.snapshotAll).to.have.callCount(1)
chai.expect(stdout).to.match(/\[percy\] percy has started./)
})

xit('starts the snapshot service on the correct port')
})

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')
})
})

0 comments on commit 98ae4b8

Please sign in to comment.