{"id":15552371,"url":"https://github.com/bahmutov/cypress-fiddle","last_synced_at":"2025-09-26T11:31:10.452Z","repository":{"id":39563787,"uuid":"465040595","full_name":"bahmutov/cypress-fiddle","owner":"bahmutov","description":"Generate Cypress tests from HTML and JS","archived":false,"fork":false,"pushed_at":"2024-12-17T21:42:40.000Z","size":2077,"stargazers_count":2,"open_issues_count":5,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-12-27T20:11:29.769Z","etag":null,"topics":["cypress-plugin"],"latest_commit_sha":null,"homepage":"https://glebbahmutov.com/blog/cypress-fiddle/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bahmutov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-01T20:08:19.000Z","updated_at":"2023-06-07T19:44:40.000Z","dependencies_parsed_at":"2024-02-08T05:28:19.477Z","dependency_job_id":"2fdd5222-1f2f-43f2-a2f9-08ba5251a188","html_url":"https://github.com/bahmutov/cypress-fiddle","commit_stats":{"total_commits":23,"total_committers":3,"mean_commits":7.666666666666667,"dds":"0.17391304347826086","last_synced_commit":"ce42c7c5f501ed71c8b2e63dabbdeb6b1c5e9fb2"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahmutov%2Fcypress-fiddle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahmutov%2Fcypress-fiddle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahmutov%2Fcypress-fiddle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bahmutov%2Fcypress-fiddle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bahmutov","download_url":"https://codeload.github.com/bahmutov/cypress-fiddle/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234305801,"owners_count":18811427,"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","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":["cypress-plugin"],"created_at":"2024-10-02T14:17:46.478Z","updated_at":"2025-09-26T11:31:04.833Z","avatar_url":"https://github.com/bahmutov.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @bahmutov/cypress-fiddle [![renovate-app badge][renovate-badge]][renovate-app] ![cypress version](https://img.shields.io/badge/cypress-12.5.1-brightgreen) [![ci](https://github.com/bahmutov/cypress-fiddle/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/bahmutov/cypress-fiddle/actions/workflows/ci.yml)\n\n\u003e Generate Cypress tests live from HTML and JS\n\nInstantly experiment with Cypress tests by creating a tiny live HTML fiddle and running E2E tests against it.\n\n![runExample test](images/runExample.png)\n\n## Install\n\nCypress is a peer dependency of this module. Install the current version of Cypress by running `npm i -D cypress`.\n\nAfter installing Cypress, install this module via npm:\n\n```shell\nnpm i -D @bahmutov/cypress-fiddle\n```\n\nThen load the custom command by adding the following line to `cypress/support/index.js`\n\n```js\n// adds \"cy.runExample()\" command\nimport '@bahmutov/cypress-fiddle'\n```\n\n## Use\n\n### Create a single test\n\nYou can take an object with an `html` property containing HTML and a `test` property containing Cypress commands and run the tests.\n\nFor example in the `cypress/e2e/spec.js` file:\n\n```js\n// loads TypeScript definition for Cypress\n// and \"cy.runExample\" custom command\n/// \u003creference types=\"@bahmutov/cypress-fiddle\" /\u003e\n\nconst helloTest = {\n  html: `\n    \u003cdiv\u003eHello\u003c/div\u003e\n  `,\n  test: `\n    cy.get('div').should('have.text', 'Hello')\n  `,\n}\n\nit('tests hello', () =\u003e {\n  cy.runExample(helloTest)\n})\n```\n\nWhich produces\n\n![runExample test](images/runExample.png)\n\n### Parameters\n\nThe test object can have multiple properties, see [src/index.d.ts](src/index.d.ts) for all.\n\n- `test` JavaScript with Cypress commands, required\n\nThe rest of the properties are optional\n\n- `html` to mount as DOM nodes before the test begins\n- `name` the name to display at the top of the page, otherwise the test title will be used\n- `description` extra test description under the name, supports Markdown via [safe-marked](https://github.com/azu/safe-marked)\n- `commonHtml` is extra HTML markup to attach to the live HTML (if any) element. Useful for loading external stylesheets or styles without cluttering every HTML block\n- `meta` lets you include additional meta tags into the `\u003cHEAD\u003e` element of the page\n- `fullDocument` lets you avoid limiting your test commands to be within the mounted live HTML\n\nThe next properties are NOT used by `cy.runExample` but are used by the `testExamples` function from this package.\n\n- `skip` creates a skipped test with `it.skip`\n- `only` creates an exclusive test with `it.only`\n- `order` controls which widgets are shown in the map: 'test', 'html', 'live'\n\n### Included scripts\n\n- [jQuery minified](https://code.jquery.com/)\n- [Highlight.js](https://highlightjs.org/)\n\nYou can include your own additional scripts by using environment variable block in `cypress.json` file\n\n```json\n{\n  \"env\": {\n    \"cypress-fiddle\": {\n      \"scripts\": [\n        \"https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js\"\n      ]\n    }\n  }\n}\n```\n\n### Styles\n\nSometimes you want to inject external stylesheets and maybe custom style CSS into the frame (we already include Highlight.js). Pass additional CSS link urls and custom styles through environment variables in `cypress.json` config file.\n\n```json\n{\n  \"env\": {\n    \"cypress-fiddle\": {\n      \"stylesheets\": [\n        \"https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css\"\n      ],\n      \"style\": \"body { padding: 1rem; }\"\n    }\n  }\n}\n```\n\n**Tip:** it is more convenient to set multiline environment variables or even load CSS files from plugins file.\n\n### Create multiple tests\n\nInstead of writing the `cy.runExample()` command one by one, you can collect all test definitions into a list or a nested object of suites and create tests automatically.\n\nFor example, here is a list of tests created from an array:\n\n```js\nimport { testExamples } from '@bahmutov/cypress-fiddle'\n\nconst tests = [\n  {\n    name: 'first test',\n    description: 'cy.wrap() example',\n    test: `\n      cy.wrap('hello').should('have.length', 5)\n    `,\n  },\n  {\n    name: 'second test',\n    description: 'cy.wrap() + .then() example',\n    test: `\n        cy.wrap()\n          .then(() =\u003e {\n            cy.log('In .then')\n          })\n      `,\n  },\n]\ntestExamples(tests)\n```\n\n![List of tests](images/list.png)\n\nWhile working with tests, you can skip a test or make it exclusive. For example to skip the first test add a `skip: true` property.\n\n```js\n{\n  name: 'first test',\n  description: 'cy.wrap example',\n  skip: true\n  ...\n}\n```\n\nOr run just a single test by using the `only: true` property.\n\n```js\n{\n  name: 'first test',\n  description: 'cy.wrap example',\n  only: true\n  ...\n}\n```\n\nYou can create suites by having nested objects. Each object becomes either a suite or a test.\n\n```js\nimport { testExamples } from '@bahmutov/cypress-fiddle'\nconst suite = {\n  'parent suite': {\n    'inner suite': [\n      {\n        name: 'a test',\n        html: `\n          \u003cdiv id=\"name\"\u003eJoe\u003c/div\u003e\n        `,\n        test: `\n          cy.contains('#name', 'Joe')\n        `,\n      },\n    ],\n    'list test': {\n      html: `\n        \u003cul\u003e\n          \u003cli\u003eAlice\u003c/li\u003e\n          \u003cli\u003eBob\u003c/li\u003e\n          \u003cli\u003eCory\u003c/li\u003e\n        \u003c/ul\u003e\n      `,\n      test: `\n        cy.get('li').should('have.length', 3)\n          .first().should('contain', 'Alice')\n      `,\n    },\n  },\n}\n\ntestExamples(suite)\n```\n\n![Tree of tests](images/tree.png)\n\nFind more examples in [cypress/e2e](cypress/e2e) folder.\n\n### Markdown\n\nThis package includes a JS/CoffeeScript/Markdown preprocessor that can find and run tests in `.md` files. Just surround the tests with HTML comments like this:\n\n    \u003c!-- fiddle Test name here --\u003e\n    Add additional text if you want. HTML code block is optional.\n\n    ```html\n    \u003cdiv\u003eExample\u003c/div\u003e\n    ```\n\n    Test code block that should be run as a test\n    ```js\n    cy.contains('Bye').should('be.visible')\n    ```\n    \u003c!-- fiddle-end --\u003e\n\nSee example [bahmutov/vuepress-cypress-test-example](https://github.com/bahmutov/vuepress-cypress-test-example) and [live site](https://vuepress-cypress-test-example.netlify.com/). Read blog posts [Run End-to-end Tests from Markdown Files](https://glebbahmutov.com/blog/cypress-fiddle/) and [Self-testing JAM pages](https://www.cypress.io/blog/2019/11/13/self-testing-jam-pages/).\n\nYou can have common HTML block and split the test across multiple JavaScript code blocks. This is useful to explain the test step by step\n\n    This test has multiple parts. First, it confirms the string value\n    ```js\n    cy.wrap('first').should('equal', 'first')\n    ```\n    Then it checks if 42 is 42\n    ```js\n    cy.wrap(42).should('equal', 42)\n    ```\n\nThe actual test to be executed will be\n\n```js\ncy.wrap('first').should('equal', 'first')\ncy.wrap(42).should('equal', 42)\n```\n\n### Skip and only\n\nYou can skip a fiddle, or run only a particular fiddle similar to `it.skip` and `it.only`\n\n```\n\u003c!-- fiddle.skip this is a skipped test --\u003e\n\u003c!-- fiddle.only this is an exclusive test --\u003e\n```\n\n**Note:** there is also `fiddle.export` modifier. These fiddles are skipped during normal testing from Markdown, but exported and enabled in the output JavaScript specs.\n\n### Page title\n\nIf the Markdown file has page title line like `# \u003csome text\u003e`, it will be used to create the top level suite of tests\n\n```js\ndescribe('\u003csome text\u003e', () =\u003e {\n  // tests\n})\n```\n\n### Nested suites\n\nYou can put a fiddle into nested suites using `/` as a separator\n\n```\n\u003c!-- fiddle Top / nested / test --\u003e\n```\n\nWill create\n\n```js\ndescribe('Top', () =\u003e {\n  describe('nested', () =\u003e {\n    it('test', () =\u003e {})\n  })\n})\n```\n\n### Multiple HTML fragments\n\nYou can pass multiple HTML blocks via an array\n\n    // single html code block\n    {\n      html: '\u003cdiv id=\"greeting\"\u003eHello\u003c/div\u003e'\n    }\n    // multiple html code blocks\n    // are concatenated\n    {\n      html: [\n        '\u003cdiv id=\"greeting\"\u003eHello\u003c/div\u003e',\n        '\u003cdiv id=\"name\"\u003eWorld\u003c/div\u003e'\n      ]\n    }\n\n### Hide HTML fragment\n\nYou can hide an HTML fragment to avoid including it in the HTML source shown on the page. The hidden HTML is still included in the live HTML block. Each code block must be an object with the `source` property and `hide: true|false` property.\n\n    html: [\n      source`\n        \u003cdiv id=\"greeting\"\u003eHello\u003c/div\u003e\n      `,\n      {\n        source: source`\n          \u003cdiv id=\"name\"\u003eWorld\u003c/div\u003e\n        `,\n        // do not show the source code this html block\n        // but still include it in the live html app\n        hide: true,\n      },\n    ]\n\n### Live HTML\n\nYou can include \"live\" html blocks in the fiddle - in that case they will become the test fragment.\n\n    \u003c!-- fiddle includes live html --\u003e\n    \u003cdiv id=\"live-block\"\u003eLive Block\u003c/div\u003e\n    ```js\n    cy.contains('#live-block', 'Live Block').should('be.visible')\n    ```\n    \u003c!-- fiddle-end --\u003e\n\nWhen including HTML source fragment and live HTML block, live HTML block wins and will be used as the test fragment.\n\n    \u003c!-- fiddle includes both live and html block --\u003e\n    ```html\n    \u003cdiv id=\"my-block\"\u003eBlock\u003c/div\u003e\n    ```\n\n    \u003cdiv id=\"live-block\"\u003eLive Block\u003c/div\u003e\n\n    ```js\n    // when including both live HTML block and\n    // html code block, the live HTML block wins\n    cy.contains('#live-block', 'Live Block').should('be.visible')\n    cy.contains('#my-block', 'Block').should('not.exist')\n    ```\n    \u003c!-- fiddle-end --\u003e\n\n### Common Live HTML\n\nIf you have common HTML to load before the live HTML block, but do not want to show it in the HTML snippet, put it into a comment like this\n\n    \u003c!-- fiddle-markup\n    \u003clink rel=\"stylesheet\" href=\"some CSS URL\"\u003e\n    \u003cstyle\u003e\n    body {\n      padding: 2rem;\n    }\n    \u003c/style\u003e\n    --\u003e\n\nYou can load styles and external CDN scripts using this approach.\n\n### Hide JS block\n\nYou can pass `testShown` in the fiddle object to show that code (or no JS block at all) in the HTML page\n\n```js\nconst test = {\n  html: '...',\n  test: '...',\n  // hide the test block completely\n  testShown: null,\n}\n```\n\nShow something else to the user\n\n```js\nconst test = {\n  html: '...',\n  test: '...',\n  testShown: '// test code snippet',\n}\n```\n\n### CSS block\n\nYou can apply CSS style to the HTML without showing it on the page\n\n```js\nconst test = {\n  html: source`\n    \u003cdiv id=\"greeting\"\u003eHello\u003c/div\u003e\n  `,\n  css: source`\n    #greeting {\n      color: #f0f;\n      padding: 1rem;\n      font-weight: bold;\n    }\n  `,\n}\ncy.runExample(test)\n```\n\n### Hiding fiddle in Markdown\n\nYou can \"hide\" fiddle inside Markdown so the page _can test itself_. See [cypress/e2e/hidden-fiddle.md](cypress/e2e/hidden-fiddle.md) example.\n\n**Markdown**\n\n![Hidden fiddle Markdown](images/hidden-fiddle.png)\n\n**Rendered page**\n\n![Hidden fiddle Markdown preview](images/hidden-fiddle-preview.png)\n\nNotice how only the summary is displayed\n\n**Test runner**\n\n![Hidden fiddle test](images/hidden-fiddle-test.png)\n\n**Note:** by default the summary element is displayed in the HTML. You can the fiddle completely using\n\n```html\n\u003cdetails style=\"display:none\"\u003e...\u003c/details\u003e\n```\n\n#### Installation\n\nIn your plugins file use\n\n```js\nconst mdPreprocessor = require('@cypress/fiddle/src/markdown-preprocessor')\nmodule.exports = (on, config) =\u003e {\n  on('file:preprocessor', mdPreprocessor)\n}\n```\n\nAnd in `cypress.json` file allow Markdown files\n\n```json\n{\n  \"testFiles\": \"*.md\"\n}\n```\n\nWarning: [issue #5401](https://github.com/cypress-io/cypress/issues/5401)\n\n## Debug\n\nTo see debug logs, use `DEBUG=@bahmutov/cypress-fiddle` when running Cypress.\n\n## Small print\n\nI wrote this plugin first in [cypress-io/cypress-fiddle](https://github.com/bahmutov/cypress-fiddle) and then continued development in this repo.\n\nAuthor: Gleb Bahmutov \u0026lt;gleb.bahmutov@gmail.com\u0026gt; \u0026copy; 2022\n\n- [@bahmutov](https://twitter.com/bahmutov)\n- [glebbahmutov.com](https://glebbahmutov.com)\n- [blog](https://glebbahmutov.com/blog)\n- [videos](https://www.youtube.com/glebbahmutov)\n- [presentations](https://slides.com/bahmutov)\n- [cypress.tips](https://cypress.tips)\n- [Cypress Advent 2021](https://cypresstips.substack.com/)\n\nLicense: MIT - do anything with the code, but don't blame me if it does not work.\n\nSupport: if you find any problems with this module, email / tweet /\n[open issue](https://github.com/bahmutov/cypress-data-session/issues) on Github\n\n## MIT License\n\nCopyright (c) 2022 Gleb Bahmutov \u0026lt;gleb.bahmutov@gmail.com\u0026gt;\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\n[renovate-badge]: https://img.shields.io/badge/renovate-app-blue.svg\n[renovate-app]: https://renovateapp.com/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbahmutov%2Fcypress-fiddle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbahmutov%2Fcypress-fiddle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbahmutov%2Fcypress-fiddle/lists"}