Skip to main content
Transform your testing process with: Company-wide Licences, Test Observability & App Percy
No Result Found

Take snapshots via CLI

How to grab Percy snapshots via CLI

The Percy snapshot is a powerful command that allows you to capture visual snapshots of web pages, lists, sitemaps, or static directories.

On this page, we’ll explore the different usage of Percy snapshot command through CLI and respective examples for the same. You have the option to either capture a full screenshot or take a screenshot of a single element.

Percy snapshot command

Run the Percy snapshot command via the command-line interface (CLI) as shown below. You can specify a snapshots file, a static directory, or the URL of a sitemap that you wish to capture snapshots of.

Copy icon Copy
percy snapshot [options] <file|dir|sitemap>

Options

Use the below options along with percy snapshot command. For details, refer the below table:

Option Description
General -b, –base-url : Set the base URL for the pages when taking snapshots.
--include : Define one or more globs/patterns to include specific snapshots.
--exclude : Specify one or more globs/patterns to exclude specific snapshots.
Static –clean-urls: Rewrite static index and filepath URLs to be clean.
Percy -c, –config : Specify the path to the Percy configuration file.
-d, --dry-run: Print snapshot names only, useful for testing without actually taking snapshots.
-h, --allowed-hostname : Set allowed hostnames to capture during asset discovery.
-t, --network-idle-timeout : Define the asset discovery network idle timeout.
--disable-cache: Disable asset discovery caches.
--debug: Enable debug mode for asset discovery and prevent uploading snapshots.
Global -v, –verbose: Log all activity.
-q, –quiet: Log errors only.
-s, –silent: Disable all logging.
–help: Display command help.

Examples

Snapshot a file

When you have a file containing a list of snapshots, it must be in YAML, JSON, or a JavaScript format exporting a list of pages. Each snapshot should include at least a URL that can be navigated to using a browser.

  • snapshots.yml (YAML):
Copy icon Copy
- http://localhost:8080
- http://localhost:8080/two
  • Command:
Copy icon Copy
percy snapshot snapshots.yml

Snapshot options

You can provide a name, waitForTimeout, and waitForSelector to customize snapshot behavior.

  • snapshots.json (JSON):
Copy icon Copy
[{
  "name": "Snapshot one",
  "url": "http://localhost:8080",
  "waitForTimeout": 1000
}, {
  "name": "Snapshot two",
  "url": "http://localhost:8080/two",
  "waitForSelector": ".some-element"
}]
  • Command:
Copy icon Copy
percy snapshot snapshots.json

Advanced options

With the snapshot command, you can interact with the page by providing an execute option. This can be any valid JavaScript that runs inside a browser, except for certain non-serializable functions. For more information, refer to what makes JavaScript non-serializable.

Copy icon Copy
document.querySelector('.my-button-example').click()

The execute option can also accept an object with these keys:

  • afterNavigation - called after the page navigates to the given URL
  • beforeResize - called before the page viewport is resized to one of the passed width(s)
  • afterResize - called after the page viewport is resized to one of the passed width(s)
  • beforeSnapshot - called before Percy captures a snapshot
Copy icon Copy
- name: Execute Example
  url: http://localhost:8080/example
  execute:
    afterNavigation:
    beforeResize:
    afterResize:
    beforeSnapshot:
Copy icon Copy
[{
  name: 'Execute Example',
  url: 'http://localhost:8080/example',
  execute: {
    afterNavigation() {},
    beforeResize() {},
    afterResize() {},
    beforeSnapshot() {}
  }
}]

For advanced use cases, you can specify an execute function and additionalSnapshots for each snapshot to execute JavaScript within the page execution context before taking subsequent snapshots.

All options are also accepted by other file formats. For execute however, a string containing a function body can be provided when the file format prevents normal functions.

  • snapshots.js (JavaScript):
Copy icon Copy
module.exports = [{
  name: 'My form',
  url: 'http://localhost:8080/form',
  waitForSelector: '.form-loaded',
  execute() {
    document.querySelector('.name').value = 'Name Namerson';
    document.querySelector('.email').value = 'email@domain.com';
  },
  additionalSnapshots: [{
    suffix: ' - submitting',
    execute() {
      document.querySelector('.submit').click();
    }
  }, {
    suffix: ' - after submit',
    waitForSelector: '.form-submitted'
  }]
}]
  • Command:
Copy icon Copy
percy snapshot snapshots.js

The snapshot command also accepts a JavaScript file that exports an array of objects (with the keys name & url present). You can export sync or async functions from this file.

For example, a common use case is to build an array of pages dynamically and then iterate over that array to snapshot pages. You can export that array to the snapshot command. As a snapshots.js file:

Copy icon Copy
module.exports = async () => {  
  let urls = await getSnapshotUrls()  
  return urls.map(url => ({ name: url, url }))  
}

Instead of an array of snapshots, list files can also contain an object that defines additional top-level options along with a snapshots option containing the array of snapshots. This allows dynamically filtering lists with include/exclude options, and enables utilizing features such as YAML anchors and references.

  • Example snapshots.yml
Copy icon Copy
base-url: https://example.com
exclude:
  - /page/(\d+)
references:
  dismiss-cookie-banner: &dismiss-cookie-banner |
    document.querySelector('.cookie-banner .dismiss').click();
snapshots:
  - url: /foo
    execute: *dismiss-cookie-banner
  - url: /foo
    name: "/foo - with cookie banner"
  - url: /bar
    execute: *dismiss-cookie-banner
Option Description
url (required) URL of the page to visit and snapshot.
name Name of the snapshot (must be unique).
execute JavaScript you would like to execute in browser before capturing a snapshot.
waitForTimeout An amount of time to wait before capturing a snapshot.
waitForSelector A CSS selector to wait to appear on page before capturing a snapshot.

See per-snapshot configuration options for additional common per-snapshot options (like widths, percy-css, etc).

Snapshot a static directory

When providing a static directory, it will be served locally and with below use cases:

  • Pages matching the files argument (excluding the ignore argument) will be navigated to and snapshotted.
  • Pages matching the include argument (and excluding the exclude argument) will be navigated to and snapshotted.
Copy icon Copy
percy snapshot ./public
  • Static Options
    For snapshotting static directories, you can configure options in the Percy configuration file.

.percy.yml (YAML):

Copy icon Copy
version: 2
static:
  base-url: /
  clean-urls: false
  include: **/*.html
  exclude: []
  rewrites: {}
  options: []
  • Example using include/exclude options
Copy icon Copy
// .percy.js
module.exports = {
  version: 2,
  static: {
    include: [
      'blog/**/*.html',          // glob
      'pages/page-(?!10).html$', // pattern
      /about-(.+)\.html/i        // regexp
    ],
    exclude: [
      // function that returns true when matching
      ({ name }) => DISALLOWED.includes(name)
    ]
  }
};
  • Example using rewrite
Copy icon Copy
# .percy.yml
version: 2
static:
  base-url: /blog
  rewrites:
    /:year/:month/:title: /posts/:year-:month--:title.html
    /:year/:month: /posts/index-:year-:month.html
    /:year: /posts/index-:year.html
  • Example using options
Copy icon Copy
# .percy.yml
version: 2
static:
  options:
  - files: /foo-bar.html
    waitForSelector: .is-ready
    execute: |
      document.querySelector('.button').click()
Option Description
base-url The base URL path the static site should be served under.
clean-urls When true, rewrite index and filepath URLs to be clean.
include/exclude A predicate or an array of predicates matching snapshots to include/exclude.
A predicate can be a string glob or pattern, a regular expression, or a function that accepts a snapshot object and returns true or false if the snapshot is considered matching or not.
rewrites An object containing source-destination pairs for rewriting URLs.
Paths for resources can sometimes be expected to be in a certain format that may not be covered by the clean-urls option. For such paths, rewrites can map a short, clean, or pretty path to a specific resource. Paths are matched using path-to-regexp.
overrides An array of per-snapshot option overrides.
Just like page listing options, static snapshots may also contain per-snapshot configuration options. However, since pages are matched against the files option, so are per-snapshot configuration options via an array of overrides. If multiple overrides match a snapshot, they will be merged with previously matched overrides.

Snapshot a sitemap URL

When providing a sitemap URL, the document must be an XML document. You can use --include and --exclude flags to filter snapshots. The Percy configuration file also accepts options.

Sitemaps can contain a lot of URLs, so its best to always start with the --dry-run flag while fine tuning the include and exclude options.

  • Command:
Copy icon Copy
percy snapshot https://percy.io/sitemap.xml --dry-run
  • Sitemap options:
Copy icon Copy
# .percy.yml
version: 2
sitemap:
  include: **/*.html
  exclude: []
  overrides: []
  • Command:
Copy icon Copy
percy snapshot snapshots.js

JavaScript files may also export sync or async functions that return a list of pages to snapshot.

Copy icon Copy
module.exports = async () => {
  let urls = await getSnapshotUrls()
  return urls.map(url => ({ name: url, url }))
}

Screenshot a single element

Sometimes capturing a full-page screenshot isn’t necessary. For example, if there are dynamic parts of the page that you don’t need to test or are only interested in a very specific region to test. For these cases, you can pass a scope snapshot option and Percy will only capture the scoped element on the given widths. This can be passed as a per-snapshot option. The scope selector accepts any valid selector you would be able to pass to document querySelector.

  • If there are multiple matching selectors on the page, Percy will select the first matching element.

Screenshot a single element using selector

Shell
Copy icon Copy
```yaml
version: 2
snapshot:
	scope: '.selector'

Screenshot a single element using xpath

Shell
Copy icon Copy
```yaml
version: 2
snapshot:
	scope: '/html/body/header/div/div[6]/h1'

Screenshot a scrollable single element

Shell
Copy icon Copy
```yaml
version: 2
snapshot:
	scope: '.selector'
	scope-options:
	  scroll: true

The Percy Snapshot Command is a versatile command for capturing and comparing visual snapshots, making it an indispensable part of your web development and testing workflow.

Use cases

Multiple elements with the same selector

If you would like to scope a screenshot to a specific element that has the same matching selector as other elements on the page you’ll have to get more specific with your selector. This can be done by either adding another unique selector to that element or by using standard CSS selectors to get more specific. This is the same way you would write CSS – Percy doesn’t add anything to this process.

For example, given the below DOM:

Copy icon Copy
<html>
  <head>
    <title>Example</title>
  </head>
  <body>
    <h1 class="underline">My example</h1>
    <p class="underline">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas tristique convallis sem, vitae sodales risus accumsan in</p>
    <p class="underline">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas tristique convallis sem, vitae sodales risus accumsan in</p>
  </body>
</html>

Instead of using just .underline to select the element, you would want to either specify the element type (h1 / p) or by using CSS tree-structural pseudo-classes like :last-of-type or :nth-child.

Copy icon Copy
version: 2
snapshot:
	scope: ‘h1.underline’

Likewise,

  • p.underline scope selects the ‘first’ paragraph
  • p.underline:last-of-type scope selects last paragraph

Selector for elements serialized by Percy

It may happen that your single-element screenshots are not working correctly with canvas/video elements.

During DOM serialization <canvas>, <video> elements are converted to <img>. Check canvas elements in Percy’s SDK Workflow. This can cause the selector to not match, and an incorrect screenshot.

To work around this, we can use CSS tree structural pseudo-classes as suggested in the previous section.

Copy icon Copy
<!-- Skipping most of the stuff for brevity -->
<!-- Original DOM -->
<div class="selector">
  <canvas> </canvas>
  <canvas> </canvas>
  <video> </video>
</div>
<!-- Post DOM Serialization -->
<div class="selector">
  <img> </img>
  <img> </img>
  <img> </img>
</div>
  • Instead of canvas or video you’ll need to change it to img
  • If there is only a single canvas/video tag inside div we can directly use .selector as the scope.
Copy icon Copy
version: 2
snapshot:
	scope: '.selector img:nth-of-type(1)' // selects first canvas

Likewise,

  • .selector img:nth-of-type(2) scope selects the ‘second’ canvas
  • .selector img:last-of-type scope selects the ‘last’ video

We're sorry to hear that. Please share your feedback so we can do better

Contact our Support team for immediate help while we work on improving our docs.

We're continuously improving our docs. We'd love to know what you liked





Thank you for your valuable feedback

Is this page helping you?

Yes
No

We're sorry to hear that. Please share your feedback so we can do better

Contact our Support team for immediate help while we work on improving our docs.

We're continuously improving our docs. We'd love to know what you liked





Thank you for your valuable feedback!

Talk to an Expert
Download Copy Check Circle