{"id":22423361,"url":"https://github.com/prantlf/grunt-html-dom-snapshot","last_synced_at":"2025-10-12T13:37:44.403Z","repository":{"id":57255128,"uuid":"110438886","full_name":"prantlf/grunt-html-dom-snapshot","owner":"prantlf","description":"Takes snapshots of the HTML markup and screenshots of the viewport content displayed in the web browser.","archived":false,"fork":false,"pushed_at":"2020-08-11T03:44:43.000Z","size":446,"stargazers_count":13,"open_issues_count":0,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-08-30T21:33:37.177Z","etag":null,"topics":["browser","grunt-task","gruntplugin","html","screenshots","selenium","snapshots","testing","webdriver"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/prantlf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-11-12T14:24:22.000Z","updated_at":"2024-06-19T01:43:39.000Z","dependencies_parsed_at":"2022-08-31T08:21:35.972Z","dependency_job_id":null,"html_url":"https://github.com/prantlf/grunt-html-dom-snapshot","commit_stats":null,"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/prantlf/grunt-html-dom-snapshot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prantlf%2Fgrunt-html-dom-snapshot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prantlf%2Fgrunt-html-dom-snapshot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prantlf%2Fgrunt-html-dom-snapshot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prantlf%2Fgrunt-html-dom-snapshot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/prantlf","download_url":"https://codeload.github.com/prantlf/grunt-html-dom-snapshot/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prantlf%2Fgrunt-html-dom-snapshot/sbom","scorecard":{"id":743713,"data":{"date":"2025-08-11","repo":{"name":"github.com/prantlf/grunt-html-dom-snapshot","commit":"caecf529cfc2015f27e20a162c554e19c06eb6b1"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"58 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-fwr7-v2mv-hh25","Warn: Project is vulnerable to: GHSA-4w2v-q235-vp99","Warn: Project is vulnerable to: GHSA-cph5-m8f7-6c5x","Warn: Project is vulnerable to: GHSA-wf5p-g6vw-rhxx","Warn: Project is vulnerable to: GHSA-jr5f-v2jv-69x6","Warn: Project is vulnerable to: GHSA-pp7h-53gx-mx7r","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-hm92-vgmw-qfmx","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-h6ch-v84p-w6p9","Warn: Project is vulnerable to: GHSA-phwq-j96m-2c2q","Warn: Project is vulnerable to: GHSA-ghr5-ch3p-vcr6","Warn: Project is vulnerable to: GHSA-74fj-2j2h-c42q","Warn: Project is vulnerable to: GHSA-pw2r-vq6v-hr8c","Warn: Project is vulnerable to: GHSA-jchw-25xp-jwwc","Warn: Project is vulnerable to: GHSA-cxjh-pqwp-8mfp","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-957j-59c2-j692","Warn: Project is vulnerable to: GHSA-ww39-953v-wcq6","Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97","Warn: Project is vulnerable to: GHSA-m5pj-vjjf-4m3h","Warn: Project is vulnerable to: GHSA-j383-35pm-c5h4","Warn: Project is vulnerable to: GHSA-rm36-94g8-835r","Warn: Project is vulnerable to: GHSA-765h-qjxv-5f44","Warn: Project is vulnerable to: GHSA-f2jv-r9rf-7988","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-rc47-6667-2j5j","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-px4h-xg32-q955","Warn: Project is vulnerable to: GHSA-76c9-3jph-rj3q","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg","Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p","Warn: Project is vulnerable to: GHSA-pq67-2wwv-3xjx","Warn: Project is vulnerable to: GHSA-8cj5-5rvv-wf4v","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-7p7h-4mm5-852v","Warn: Project is vulnerable to: GHSA-662x-fhqg-9p8v","Warn: Project is vulnerable to: GHSA-394c-5j6w-4xmx","Warn: Project is vulnerable to: GHSA-78cj-fxph-m83p","Warn: Project is vulnerable to: GHSA-fhg7-m89q-25r3","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q","Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T18:10:52.342Z","repository_id":57255128,"created_at":"2025-08-22T18:10:52.342Z","updated_at":"2025-08-22T18:10:52.342Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279011451,"owners_count":26084947,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-12T02:00:06.719Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser","grunt-task","gruntplugin","html","screenshots","selenium","snapshots","testing","webdriver"],"created_at":"2024-12-05T18:10:36.831Z","updated_at":"2025-10-12T13:37:44.369Z","avatar_url":"https://github.com/prantlf.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# grunt-html-dom-snapshot\n[![NPM version](https://badge.fury.io/js/grunt-html-dom-snapshot.png)](http://badge.fury.io/js/grunt-html-dom-snapshot)\n[![Build Status](https://travis-ci.org/prantlf/grunt-html-dom-snapshot.png)](https://travis-ci.org/prantlf/grunt-html-dom-snapshot)\n[![Dependency Status](https://david-dm.org/prantlf/grunt-html-dom-snapshot.svg)](https://david-dm.org/prantlf/grunt-html-dom-snapshot)\n[![devDependency Status](https://david-dm.org/prantlf/grunt-html-dom-snapshot/dev-status.svg)](https://david-dm.org/prantlf/grunt-html-dom-snapshot#info=devDependencies)\n[![devDependency Status](https://david-dm.org/prantlf/grunt-html-dom-snapshot/peer-status.svg)](https://david-dm.org/prantlf/grunt-html-dom-snapshot#info=peerDependencies)\n\n[![NPM Downloads](https://nodei.co/npm/grunt-html-dom-snapshot.png?downloads=true\u0026stars=true)](https://www.npmjs.com/package/grunt-html-dom-snapshot)\n\nThis module provides a grunt multi-task for taking \"snapshots\" of the HTML markup on web pages - of their immediate DOM content - and saving them to HTML files. It can be used to obtain content of web pages, which are built dynamically by JavaScript, and check it for validity and accessibility. It uses [webdriverio] to control the selected web browser.\n\n![Sample page](https://raw.githubusercontent.com/prantlf/grunt-html-dom-snapshot/master/assets/sample-page.png) ![Right arrow](https://raw.githubusercontent.com/prantlf/grunt-html-dom-snapshot/master/assets/arrow-right.png) ![Sample snapshot](https://raw.githubusercontent.com/prantlf/grunt-html-dom-snapshot/master/assets/sample-snapshot.png)\n\nIn addition, recent versions can save \"screenshots\" of browser viewport at the same time to support visual testing by comparing the look of the page with the baseline picture. Actually, this task is quickly evolving to offer end-to-end test capabilities too.\n\nSee the [migration documentation] about compatibility of older versions with the latest v6.\n\nRecent versions of this documentation show how to use WebDrivers directly fror controlling the web browser ([grunt-chromedriver], [grunt-geckodriver] and [grunt-safaridriver]). It needs neither Java not [Selenum] installed. See the [version 6.0.1] or older for examples how to use the full [Selenium].\n\nAdditional Grunt tasks, which are usually used to support test automation:\n\n* [grunt-accessibility] - checks accessibility of HTML markup according to the [WCAG] standard\n* [grunt-accessibility-html-report-converter] - converts JSON report of `grunt-accessibility` to HTML\n* [grunt-contrib-connect] - starts a static web server to server testing pages for the web browser\n* [grunt-html] - validates HTML markup according to the [W3C HTML] standard\n* [grunt-html-html-report-converter] - converts JSON report of `grunt-html` to HTML\n* [grunt-reg-viz] - compares images and generates report with differences\n* [grunt-chromedriver] - runs a standalone chromedriver - no need for Selenium\n* [grunt-geckodriver] - runs a standalone geckodriver - no need for Selenium\n* [grunt-safaridriver] - runs a standalone safaridriver - no need for Selenium\n* [@prantlf/grunt-selenium-standalone] - runs a standalone Selenium server\n\n# Table of Contents\n\n- [Installation](#installation)\n- [Configuration](#configuration)\n  - [Options](#options)\n  - [Sub-tasks](#sub-tasks)\n  - [Instructions](#instructions)\n  - [Instruction Combinations](#instruction-combinations)\n  - [Loading](#loading)\n- [Build](#build)\n- [Example](#example)\n- [Contributing](#contributing)\n- [Release History](#release-history)\n- [License](#license)\n\n## Installation\n\nYou need [node \u003e= 10][node], [npm] and [grunt \u003e= 1.0.0][Grunt] installed\nand your project build managed by a [Gruntfile] with the necessary modules\nlisted in [package.json].  If you have not used Grunt before, be sure to\ncheck out the [Getting Started] guide, as it explains how to create a\nGruntfile as well as install and use Grunt plugins.  Once you are familiar\nwith that process, you may install this plugin with this command:\n\n```shell\n$ npm install grunt-html-dom-snapshot --save-dev\n```\n\n## Configuration\n\nAdd the `html-dom-snapshot` entry with the task configuration to the options of the `grunt.initConfig` method:\n\n```js\ngrunt.initConfig({\n  'html-dom-snapshot': {\n    'google': {\n      url: 'https://www.google.com'\n    }\n  }\n});\n```\n\nDefault options support the most usual usage scenario:\n\n```js\n'html-dom-snapshot': {\n  options: {\n    webdriver: {\n      logLevel: 'warn',\n      capabilities: {\n        browserName: 'chrome',\n        'goog:chromeOptions': {\n          args: ['--headless']\n        }\n      }\n    },\n    viewport: {\n      width: 1024,\n      height: 768\n    },\n    selectorTimeout: 10000,\n    instructionDelay: 0,\n    doctype: '\u003c!DOCTYPE html\u003e',\n    snapshots: 'snapshots',\n    screenshots: null,\n    fileNumbering: false,\n    fileNumberDigits: 3,\n    fileNumberSeparator: '.',\n    hangOnError: false,\n    snapshotOnError: '_last-error',\n    singleElementSelections: false,\n    force: false\n  },\n  'google': {\n    url: 'https://www.google.com'\n  }\n}\n```\n\nMake sure, that you have the stable version of Chrome installed, if you leave the defaults intact.\n\n### Options\n\n#### webdriver\nType: `Object`\nDefault value: see above\n\nChooses the web browser to take snapshots with, and other parameters supported by WebdriverIO as input for the  `webdriverio.remote` method. This object has to contain the property `capabilities` with `browserName` and optionally other properties depending on the web browser driver. The following browser names are the most usually used: `chrome`, `firefox`, `safari`. Depending on what browser you specify, you will need to load the corresponding WebDdriver. These are the tasks to load the drivers:\n\n```js\nchromedriver: {\n  default: { port: 4445 }\n},\ngeckodriver: {\n  default: { port: 4446 }\n},\nsafaridriver: {\n  default: { port: 4447 }\n},\n```\n\nThe other often used property is `logLevel`, set to \"warn\" by default. Valid values are \"trace\", \"debug\", \"info\", \"warn\", \"error\" and \"silent\".\n\n#### viewport\nType: `Object`\nDefault value: {width: 1024, height: 768}\n\nResizes the web browser viewport to the specified `width` and `height` values (in pixels) before taking snapshots.\n\n#### selectorTimeout\nType: `Number`\nDefault value: 10000\n\nMaximum waiting time (in milliseconds), until a DOM node with the selector specified by the `wait` property appears or disappears. Taking the snapshot fails, if this time is exceeded.\n\n#### instructionDelay\nType: `Number`\nDefault value: 0\n\nWaiting time after executing an instruction. If the test is not run in the headless browser, but debugged in the browser window, it is sometimes helpful to watch outcome of every operation. If introducing waiting instructions all over is too cumbersome, this configuration will add the delay (in milliseconds) after every instruction automatically.\n\n#### doctype\nType: `String`\nDefault value: '\u003c!DOCTYPE html\u003e'\n\nSets the HTML doctype to be written to the file with the snapshot. [WebdriverIO API] does not support getting its value. HTML validators require the doctype and to make the integration with other tasks easier it can be written to the snapshot file using this option.\n\n#### snapshots\nType: `String`\nDefault value: 'snapshots'\n\nDestination directory to write the page snapshots to. It will be created if it does not exist. If set to `null`, snapshots will not be saved. It can be used to have only screenshots saved.\n\n#### screenshots\nType: `String`\nDefault value: null\n\nDestination directory to write the viewport screenshots to. It will be created if it does not exist. Default value is `null`, which means, that no screenshots will be written out.\n\n#### fileNumbering\nType: `Booolean`|`String`\nDefault value: `false`\n\nIf set to `true`, enables prefixing names of snapshot and screenshot files with their index number, for example: \"002.google-input.html\". Every occurrence of the `file` instruction increases the file count.\n\nIf set to \"per-directory\", the index number will be increased separately per sub-directory with snapshots. If the value of the `file` instruction contains a slash, it will put the snapshot to a sub-directory, which may be useful to organize many snapshots created by multiple tasks.\n\n#### fileNumberDigits\nType: `Number`\nDefault value: `3`\n\nEnsures, that file numbers will have always at least the specified count of digits. If the number is smaller, than its power of 10, the number will be padded by zeros (0) from the left.\n\n#### fileNumberSeparator\nType: `String`\nDefault value: '.'\n\nThe character to put between the file number and the file name.\n\n### hangOnError\nType: `Boolean`\nDefault value: false\n\nIf set to `true`, it will not abort the process in case of a failure. It is useful, if you want to investigate the situation on the screen right after an error occurred. If you encounter an error flip this flag and re-run the failing scenario. Once you are finished terminate the process or interrupt it by Ctrl+C.\n\n### snapshotOnError\nType: `String`\nDefault value: '_last-error'\n\nIf set to a non-empty string, if will be used as a file name for an automatically taken snapshot and screenshot (if those are enabled), if the task execution fails.\n\n### singleElementSelections\nType: `Boolean`\nDefault value: false\n\nIf set to `true`, it will enforce every selector match either one or none elements. If any selector matches multiple elements, the instruction will fail. Tests usually address just one element. This setting helps to uncover errors like checking `isFocus` for multiple elements, which has unpredictable results.\n\nThis option can be set for the whole task or within a single command object.\n\n#### force\nType: `Boolean`\nDefault value: false\n\nIf set to `true`, it suppresses failures, which happened during taking snapshots. Instead of making the Grunt fail, the errors will be written only to the console.\n\nThis option can be set for the whole task or within a single command object.\n\n### Sub-tasks\n\nFile names for snapshots can be used as sub-task names. Separate sub-tasks initialize separate instance of the webdriver:\n\n```js\n'html-dom-snapshot': {\n  'google': {\n    url: 'https://google.com'\n  },\n  'github': {\n    url: 'https://github.com'\n  }\n}\n```\n\nIf the sub-task contains a property `commands`, this property is supposed to point to an array of command objects - navigations and other browser interactions, waiting for browser states and making snapshots. They share the same instance of the webdriver, which improves the performance:\n\n```js\n'html-dom-snapshot': {\n  all: {\n    commands: [\n      {\n        url: 'https://google.com',\n        file: 'google'\n      },\n      {\n        url: 'https://github.com',\n        file: 'github'\n      }\n    ]\n  }\n}\n```\n\nIf the sub-task contains a property `scenarios`, this property is supposed to point to a JavaScript module path or to an array of JavaScript module paths, which would export the array of commands. Relative paths will be resolved to the current (process) directory. It allows to keep the Gruntfile legible and supply the test instructions from other files:\n\n```js\n'html-dom-snapshot': {\n  all: {\n    scenarios: 'scenarios/*.js'\n  }\n}\n```\n\nYou can use sub-tasks, `commands` and `scenarios` to structure your code and execute the tests separately, or all of them in one browser window.\n\n### Instructions\n\nOne of the [instructions] has to be present in every command, otherwise its execution will fail. If you include a key in your command object, which is not recognised as an instruction or other known key (`file`, `options`), the execution will fail too. The following instructions are recognised (and their effect is executed) in the order, in which they are listed below:\n\n* [if-then-else](INSTRUCTIONS.md#if-then-else)\n* [while-do](INSTRUCTIONS.md#while-do)\n* [do-until](INSTRUCTIONS.md#do-until)\n* [repeat-do](INSTRUCTIONS.md#repeat-do)\n* [setViewport](INSTRUCTIONS.md#setviewport)\n* [url](INSTRUCTIONS.md#url)\n* [go](INSTRUCTIONS.md#go)\n* [scroll](INSTRUCTIONS.md#scroll)\n* [focus](INSTRUCTIONS.md#focus)\n* [clearValue](INSTRUCTIONS.md#clearvalue)\n* [setValue](INSTRUCTIONS.md#setvalue)\n* [addValue](INSTRUCTIONS.md#addvalue)\n* [selectOptionByIndex](INSTRUCTIONS.md#selectoptionbyindex)\n* [selectOptionByValue](INSTRUCTIONS.md#selectoptionbyvalue)\n* [moveCursor](INSTRUCTIONS.md#movecursor)\n* [click](INSTRUCTIONS.md#click)\n* [clickIfVisible](INSTRUCTIONS.md#clickIfVisible)\n* [keys](INSTRUCTIONS.md#keys)\n* [elementSendKeys](INSTRUCTIONS.md#elementSendKeys)\n* [wait](INSTRUCTIONS.md#wait)\n* [isExisting](INSTRUCTIONS.md#isexisting)\n* [isVisible](INSTRUCTIONS.md#isvisible)\n* [isVisibleWithinViewport](INSTRUCTIONS.md#isvisiblewithinviewport)\n* [isEnabled](INSTRUCTIONS.md#isenabled)\n* [isSelected](INSTRUCTIONS.md#isselected)\n* [isFocused](INSTRUCTIONS.md#isfocused)\n* [isNotExisting](INSTRUCTIONS.md#isnotexisting)\n* [isNotVisible](INSTRUCTIONS.md#isnotvisible)\n* [isNotVisibleWithinViewport](INSTRUCTIONS.md#isnotvisiblewithinviewport)\n* [isNotEnabled](INSTRUCTIONS.md#isnotenabled)\n* [isNotSelected](INSTRUCTIONS.md#isnotselected)\n* [isNotFocused](INSTRUCTIONS.md#isnotfocused)\n* [hasAttribute](INSTRUCTIONS.md#hasattribute)\n* [hasClass](INSTRUCTIONS.md#hasclass)\n* [hasValue](INSTRUCTIONS.md#hasvalue)\n* [hasText](INSTRUCTIONS.md#hastext)\n* [hasInnerHtml](INSTRUCTIONS.md#hasinnerhtml)\n* [hasOuterHtml](INSTRUCTIONS.md#hasouterhtml)\n* [break](INSTRUCTIONS.md#break)\n* [abort](INSTRUCTIONS.md#abort)\n* [file](INSTRUCTIONS.md#file)\n\n#### options\nType: `Object` (optional)\n\nOptions specific for the one particular command. They will be merged with the task options to specialize taking of the particular snapshot:\n\n```js\n{\n  options: {\n    viewport: {\n      width: 1600,\n      height: 900\n    }\n  },\n  url: 'https://google.com',\n  file: 'google'\n}\n```\n\n### Instruction Combinations\n\nThe following array of commands within the `commands` property will change location, make a snapshot immediately to save the server-side pre-rendered content, then another one to see the progress after the first 500 milliseconds and yet another one, once the search form is ready. Then it submits the form by clicking on the \"Search\" button, waits until the search results are displayed and makes one final snapshot.\n\n```js\n{\n  url: 'https://localhost/app'\n  file: 'initial.html'\n},\n{\n  wait: 500,\n  file: 'after-500ms'\n},\n{\n  wait: '#search',\n  file: 'form-ready'\n},\n{\n  wait: function (browser) {\n    return browser.$('#search')\n      .then(element =\u003e {\n        element.click();\n        return element;\n      })\n      .then(element =\u003e element.waitForExist({ timeout: 1000 }));\n  },\n  file: 'results-shown'\n}\n```\n\nThe last command can be written in a declarative way too:\n\n```js\n{\n  options: {\n    selectorTimeout: 1000\n  },\n  click: '#search',\n  wait: '#results',\n  file: 'results-shown'\n}\n```\n\nOther Grunt tasks can run later and validate, compare or otherwise process the page content in different stages of the \"Search\" scenario.\n\nNavigating to other location, interacting with the page, waiting for some effect to show and saving a snapshot can be divided to different objects in the `commands` array. However, at least One of the `file`, `url` ans `wait` parameters has to be present in ever object.\n\nWhen the commands become too many, you can divide them per page or per other criterion, which corresponds with a scenario and load them from separate modules:\n\n```js\n'html-dom-snapshot': {\n  addressbook: require('./test/scenarios/addressbook'),\n  calendar: require('./test/scenarios/calendar'),\n  inbox: require('./test/scenarios/inbox'),\n  tasks: require('./test/scenarios/tasks')\n}\n```\n\nThe module for the address book implementation would look like this:\n\n```js\nmodule.exports = {\n  options: {...}, // optional task-specific options\n  commands: [\n    {\n      url: 'https://localhost/addressbook'\n      wait: '#addressbook.complete'\n    },\n    ...\n  ]\n}\n```\n\nThe same tests will be run in a single browser window, if the Gruntfile contains just a single sub-task and the tests are specified by scenario files:\n\n```js\n'html-dom-snapshot': {\n  all: {\n    scenarios: 'test/scenarios/*.js'\n  }\n}\n```\n\nThe directory \"test/scenarios\" would contain files  \"addressbook.js\", \"calendar.js\", \"inbox.js\" and \"tasks.js\", which would specify only the array of commands; not the entire sub-task objects. For example, the address book implementation:\n\n```js\nmodule.exports = {\n  {\n    options: {...}, // optional command-specific options\n    url: 'https://localhost/addressbook'\n    wait: '#addressbook.complete'\n  },\n  ...\n]\n```\n\n### Loading\n\nLoad the plugin in `Gruntfile.js`:\n\n```javascript\ngrunt.loadNpmTasks('grunt-html-dom-snapshot');\n```\n\n## Build\n\nCall the `html-dom-snapshot` task:\n\n```shell\n$ grunt html-dom-snapshot\n```\n\nor integrate it to your build sequence in `Gruntfile.js`:\n\n```js\ngrunt.registerTask('default', ['html-dom-snapshot', ...]);\n```\n\n## Example\n\nWhen [webdriverio] is called, it needs to connect to a WebDriver or to the [Selenium] server. The easiest way, how to get it running, is using [grunt-chromedriver], [grunt-geckodriver], [grunt-safaridriver], or [@prantlf/grunt-selenium-standalone] Grunt tasks, which download, start and stop the browser. If the usage scenario is to validate static files or a mocked web application, a local web server like [grunt-contrib-connect] is usually added. And additional checking tasks like [grunt-html] pr [grunt-accessibility]. The complete Grunt initialisation could look like this:\n\n```js\ngrunt.initConfig({\n  connect: { // Serves static files in the current directory.\n    server: {\n      options: {port: 8881}\n    }\n  },\n\n  clean: { // Cleans the previously taken snapshots.\n    snapshots: ['snapshots/*']\n  },\n\n  'html-dom-snapshot': { // Takes new snapshots.\n    all: {\n      ...\n    }\n  },\n\n  htmllint: { // Checks if the HTML markup is valid.\n    all: {\n      src: ['snapshots/*.html']\n    }\n  },\n\n  accessibility: { // Checks if the page complies to the WCAG AA standard.\n    all: {\n      src: ['snapshots/*.html']\n    }\n  },\n\n  chromedriver: { // Launches the Chrome executable\n    default: {}\n  }\n});\n\ngrunt.loadNpmTasks('grunt-accessibility');\ngrunt.loadNpmTasks('grunt-chromedriver');\ngrunt.loadNpmTasks('grunt-contrib-clean');\ngrunt.loadNpmTasks('grunt-contrib-connect');\ngrunt.loadNpmTasks('grunt-html');\ngrunt.loadNpmTasks('grunt-html-dom-snapshot');\n\ngrunt.registerTask('default', [\n  'chromedriver:default:start',\n  'connect', 'clean', 'html-dom-snapshot',\n  'chromedriver:default:stop',\n  'htmllint', 'accessibility']);\n```\n\nThe installation of the necessary Grunt tasks:\n\n```sh\nnpm install grunt-html-dom-snapshot grunt-chromedriver \\\n  grunt-contrib-clean grunt-contrib-connect \\\n  grunt-accessibility grunt-html --save-dev\n```\n\n### Notes\n\nChrome, Chromium and Firefox support a headless mode. It simplifies automated testing, because you need no graphic subsystem like X.Org installed.\n\nThe default configuration of this task will choose Chrome in the headless mode:\n\n```js\n'html-dom-snapshot': {\n  options: {\n    webdriver: {\n      capabilities: {\n        browserName: 'chrome',\n        'goog:chromeOptions': { args: ['--headless'] }\n      }\n    }\n  }\n},\nchromedriver: {\n  default: {}\n}\n```\n\nIf you want to run Chrome in the windowed mode, override the `chromeOptions` object with yours, even an empty one, which is missing the `--headless` argument, for example:\n\n```js\n'html-dom-snapshot': {\n  options: {\n    webdriver: {\n      capabilities: {\n        browserName: 'chrome',\n        'goog:chromeOptions': {}\n      }\n    }\n  }\n},\nchromedriver: {\n  default: {}\n}\n```\n\nIf you want to run Chrome in Travis CI, override the `goog:chromeOptions` object with yours and disable the sandbox with `--no-sandbox`:\n\n```js\n'html-dom-snapshot': {\n  options: {\n    webdriver: {\n      capabilities: {\n        browserName: 'chrome',\n        'goog:chromeOptions': { args: ['--headless', '--no-sandbox'] }\n      }\n    }\n  }\n},\nchromedriver: {\n  default: {}\n}\n```\n\nThe following configuration will choose Firefox in the headless mode:\n\n```js\n'html-dom-snapshot': {\n  options: {\n    webdriver: {\n      capabilities: {\n        browserName: 'firefox',\n        'moz:firefoxOptions': { args: ['-headless'] }\n      }\n    }\n  }\n},\ngeckodriver: {\n  default: {}\n}\n```\n\nThe following configuration will choose Safari in the windowed mode:\n\n```js\n'html-dom-snapshot': {\n  options: {\n    webdriver: {\n      capabilities: { browserName: 'safari' }\n    }\n  }\n},\nsafaridriver: {\n  default: {}\n}\n```\n\n## Contributing\n\nIn lieu of a formal styleguide, take care to maintain the existing coding\nstyle.  Add unit tests for any new or changed functionality. Lint and test\nyour code using Grunt.\n\n## Release History\n\n * 2020-04-25  [v6.0.0]  Upgrade to WebDriverIO 6\n * 2019-09-21  [v5.1.0]  Reorder checking instructions, enforce single-element matching\n * 2019-09-21  [v4.0.0]  Upgrade to WebDriverIO 5, add the instruction \"elementSendKeys\"\n * 2019-07-21  [v3.0.0]  Report unrecognised instructions as errors, introduce new instructions (focus, while-do, do-until, repeat-do, break)\n * 2019-07-08  [v2.2.0]  Optionally hang the browser in case of failure to be able to inspect the web page in developer tools\n * 2018-11-26  [v2.0.0]  Use headless Chrome instead of PhantomJS by default, introduce conditional if-then-else instructions\n * 2018-05-14  [v1.3.0]  Allow saving snapshots to sub-directories, file numbering per-directory, add `scroll` instruction\n * 2018-05-11  [v1.2.0]  Introduce delay after every instruction to be able to visually follow the actions when debugging\n * 2018-03-29  [v1.1.0]  Allow specifying all initialization parameters supported by WebdriverIO\n * 2018-03-28  [v1.0.2]  Stop Selenium and Chromedriver processes on unexpected Grunt process abortion\n * 2018-03-28  [v1.0.1]  Workaround for hanging chromedriver after finishing the task\n * 2018-03-11  [v1.0.0]  Require Node.js \u003e= 6\n * 2018-03-11  [v0.8.0]  Add a new instruction - \"abort\"\n * 2018-03-01  [v0.7.0]  Add optional automatic file numbering\n * 2018-02-28  [v0.6.0]  Add the allRequired option to the hasClass instruction\n * 2018-02-26  [v0.5.0]  Allow checking and setting various properties\n * 2018-02-22  [v0.4.0]  Allow sending key strokes to the browser\n * 2018-01-30  [v0.3.0]  Allow specifying test commands in separate modules\n * 2018-01-27  [v0.2.0]  Allow saving screenshots in addition to snapshots\n * 2017-11-18  [v0.1.0]  Allow separate navigation, page interaction and saving snapshots\n * 2017-11-12  [v0.0.1]  Initial release\n\n## License\n\nCopyright (c) 2017-2020 Ferdinand Prantl\n\nLicensed under the MIT license.\n\n[migration documentation]: ./MIGRATION.md\n[node]: https://nodejs.org\n[npm]: https://npmjs.org\n[package.json]: https://docs.npmjs.com/files/package.json\n[Grunt]: https://gruntjs.com\n[Gruntfile]: https://gruntjs.com/sample-gruntfile\n[Getting Gtarted]: https://github.com/gruntjs/grunt/wiki/Getting-started\n[Selenium]: http://www.seleniumhq.org/download/\n[webdriverio]: http://webdriver.io/\n[WebdriverIO API]: http://webdriver.io/api.html\n[Java]: https://java.com/en/download/\n[W3C HTML]: https://www.w3.org/standards/techs/html\n[WCAG]: https://www.w3.org/WAI/intro/wcag\n[grunt-accessibility]: https://github.com/yargalot/grunt-accessibility\n[grunt-accessibility-html-report-converter]: https://github.com/prantlf/grunt-accessibility-html-report-converter\n[grunt-contrib-connect]: https://github.com/gruntjs/grunt-contrib-connect\n[grunt-html]: https://github.com/jzaefferer/grunt-html\n[grunt-html-html-report-converter]: https://github.com/prantlf/grunt-html-html-report-converter\n[grunt-reg-viz]: https://github.com/prantlf/grunt-reg-viz\n[@prantlf/grunt-selenium-standalone]: https://github.com/prantlf/grunt-selenium-standalone\n[grunt-chromedriver]: https://github.com/prantlf/grunt-chromedriver\n[grunt-geckodriver]: https://github.com/prantlf/grunt-geckodriver\n[grunt-safaridriver]: https://github.com/prantlf/grunt-safaridriver\n[keyboard key identifiers]: https://w3c.github.io/webdriver/webdriver-spec.html#keyboard-actions\n[version 6.0.1]: https://github.com/prantlf/grunt-html-dom-snapshot/tree/v6.0.1#readme\n[v6.0.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v6.0.0\n[v5.1.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v5.1.0\n[v4.0.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v4.0.0\n[v3.0.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v3.0.0\n[v2.2.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v2.2.0\n[v2.0.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v2.0.0\n[v1.3.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v1.3.0\n[v1.2.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v1.2.0\n[v1.1.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v1.1.0\n[v1.0.2]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v1.0.2\n[v1.0.1]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v1.0.1\n[v1.0.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v1.0.0\n[v0.8.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v0.8.0\n[v0.7.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v0.7.0\n[v0.6.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v0.6.0\n[v0.5.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v0.5.0\n[v0.4.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v0.4.0\n[v0.3.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v0.3.0\n[v0.2.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v0.2.0\n[v0.1.0]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v0.1.0\n[v0.0.1]: https://github.com/prantlf/grunt-html-dom-snapshot/releases/tag/v0.0.1\n[instructions]: INSTRUCTIONS.md\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprantlf%2Fgrunt-html-dom-snapshot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprantlf%2Fgrunt-html-dom-snapshot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprantlf%2Fgrunt-html-dom-snapshot/lists"}