Coder Social home page Coder Social logo

cypress-fiddle's Introduction

cypress-fiddle renovate-app badge CircleCI

Generate Cypress tests live from HTML and JS

Instantly experiment with Cypress tests by creating a tiny live HTML fiddle and running E2E tests against it.

runExample test

Install

Cypress is a peer dependency of this module. Install the current version of Cypress by running npm i -D cypress.

After installing Cypress, install this module via npm:

npm i -D @cypress/fiddle

Then load the custom command by adding the following line to cypress/support/index.js

// adds "cy.runExample()" command
import '@cypress/fiddle'

Use

Create a single test

You can take an object with an html property containing HTML and a test property containing Cypress commands and run the tests.

For example in the cypress/integration/spec.js file:

// loads TypeScript definition for Cypress
// and "cy.runExample" custom command
/// <reference types="@cypress/fiddle" />

const helloTest = {
  html: `
    <div>Hello</div>
  `,
  test: `
    cy.get('div').should('have.text', 'Hello')
  `
}

it('tests hello', () => {
  cy.runExample(helloTest)
})

Which produces

runExample test

Parameters

The test object can have multiple properties, see src/index.d.ts for all.

  • test JavaScript with Cypress commands, required

The rest of the properties are optional

  • html to mount as DOM nodes before the test begins
  • name the name to display at the top of the page, otherwise the test title will be used
  • description extra test description under the name, supports Markdown via safe-marked
  • 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

The next properties are NOT used by cy.runExample but are used by the testExamples function from this package.

  • skip creates a skipped test with it.skip
  • only creates an exclusive test with it.only

Included scripts

You can include your own additional scripts by using environment variable block in cypress.json file

{
  "env": {
    "cypress-fiddle": {
      "scripts": [
        "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
      ]
    }
  }
}

Styles

Sometimes 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.

{
  "env": {
    "cypress-fiddle": {
      "stylesheets": [
        "https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
      ],
      "style": "body { padding: 1rem; }"
    }
  }
}

Tip: it is more convenient to set multiline environment variables or even load CSS files from plugins file.

Create multiple tests

Instead 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.

For example, here is a list of tests created from an array:

import { testExamples } from '@cypress/fiddle'

const tests = [
  {
    name: 'first test',
    description: 'cy.wrap() example',
    test: `
      cy.wrap('hello').should('have.length', 5)
    `
  },
  {
    name: 'second test',
    description: 'cy.wrap() + .then() example',
    test: `
        cy.wrap()
          .then(() => {
            cy.log('In .then')
          })
      `
  }
]
testExamples(tests)

List of tests

While working with tests, you can skip a test or make it exclusive. For example to skip the first test add a skip: true property.

{
  name: 'first test',
  description: 'cy.wrap example',
  skip: true
  ...
}

Or run just a single test by using the only: true property.

{
  name: 'first test',
  description: 'cy.wrap example',
  only: true
  ...
}

You can create suites by having nested objects. Each object becomes either a suite or a test.

import { testExamples } from '@cypress/fiddle'
const suite = {
  'parent suite': {
    'inner suite': [
      {
        name: 'a test',
        html: `
          <div id="name">Joe</div>
        `,
        test: `
          cy.contains('#name', 'Joe')
        `
      }
    ],
    'list test': {
      html: `
        <ul>
          <li>Alice</li>
          <li>Bob</li>
          <li>Cory</li>
        </ul>
      `,
      test: `
        cy.get('li').should('have.length', 3)
          .first().should('contain', 'Alice')
      `
    }
  }
}

testExamples(suite)

Tree of tests

Find more examples in cypress/integration folder.

Markdown

This 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:

<!-- fiddle Test name here -->
Add additional text if you want. HTML code block is optional.

```html
<div>Example</div>
```

Test code block that should be run as a test
```js
cy.contains('Bye').should('be.visible')
```
<!-- fiddle-end -->

See example bahmutov/vuepress-cypress-test-example and live site. Read blog posts Run End-to-end Tests from Markdown Files and Self-testing JAM pages.

You can have common HTML block and split the test across multiple JavaScript code blocks. This is useful to explain the test step by step

This test has multiple parts. First, it confirms the string value
```js
cy.wrap('first').should('equal', 'first')
```
Then it checks if 42 is 42
```js
cy.wrap(42).should('equal', 42)
```

The actual test to be executed will be

cy.wrap('first').should('equal', 'first')
cy.wrap(42).should('equal', 42)

Skip and only

You can skip a fiddle, or run only a particular fiddle similar to it.skip and it.only

<!-- fiddle.skip this is a skipped test -->
<!-- fiddle.only this is an exclusive test -->

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.

Page title

If the Markdown file has page title line like # <some text>, it will be used to create the top level suite of tests

describe('<some text>', () => {
  // tests
})

Nested suites

You can put a fiddle into nested suites using / as a separator

<!-- fiddle Top / nested / test -->

Will create

describe('Top', () => {
  describe('nested', () => {
    it('test', () => {})
  })
})

Live HTML

You can include "live" html blocks in the fiddle - in that case they will become the test fragment.

<!-- fiddle includes live html -->
<div id="live-block">Live Block</div>
```js
cy.contains('#live-block', 'Live Block').should('be.visible')
```
<!-- fiddle-end -->

When including HTML source fragment and live HTML block, live HTML block wins and will be used as the test fragment.

<!-- fiddle includes both live and html block -->
```html
<div id="my-block">Block</div>
```

<div id="live-block">Live Block</div>

```js
// when including both live HTML block and
// html code block, the live HTML block wins
cy.contains('#live-block', 'Live Block').should('be.visible')
cy.contains('#my-block', 'Block').should('not.exist')
```
<!-- fiddle-end -->

Common Live HTML

If 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

<!-- fiddle-markup
<link rel="stylesheet" href="some CSS URL">
<style>
body {
  padding: 2rem;
}
</style>
-->

You can load styles and external CDN scripts using this approach.

Hiding fiddle in Markdown

You can "hide" fiddle inside Markdown so the page can test itself. See cypress/integration/hidden-fiddle.md example.

Markdown

Hidden fiddle Markdown

Rendered page

Hidden fiddle Markdown preview

Notice how only the summary is displayed

Test runner

Hidden fiddle test

Note: by default the summary element is displayed in the HTML. You can the fiddle completely using

<details style="display:none">
 ...
</details>

Installation

In your plugins file use

const mdPreprocessor = require('@cypress/fiddle/src/markdown-preprocessor')
module.exports = (on, config) => {
  on('file:preprocessor', mdPreprocessor)
}

And in cypress.json file allow Markdown files

{
  "testFiles": "*.md"
}

Warning: issue #5401

Exporting JS specs from Markdown fiddles

# saves path/to/md.js file
npx export-fiddle <path/to/md>
# adds optional "beforeEach" hook with cy.visit(url)
npx export-fiddle <path/to/md> --before-each <url>
# adds optional "before" hook with cy.visit(url)
npx export-fiddle <path/to/md> --before <url>

Debug

To see debug logs, use DEBUG=@cypress/fiddle when running Cypress.

Publishing

Automatic semantic release on CircleCI using Cypress Circle Orb, see circle.yml file.

cypress-fiddle's People

Contributors

atofstryker avatar bahmutov avatar chrisbreiding avatar dependabot[bot] avatar emilyrohrbough avatar flotwig avatar jennifer-shehane avatar mike-plummer avatar mjhenkes avatar mschile avatar renovate-bot avatar renovate[bot] avatar ryanthemanuel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cypress-fiddle's Issues

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.

Hide fiddle completely using single comment block

We should be able to hide the fiddle's code completely by hiding it in the HTML comment block

Instead of

<!-- fiddle Initial -->
```js
cy.visit('/')
cy.get('input').should('be.visible')
cy.screenshot('initial')
```
<!-- fiddle-end -->

Do

<!-- fiddle Initial
```js
cy.visit('/')
cy.get('input').should('be.visible')
cy.screenshot('initial')
```
-->

ReferenceError: `Cypress` is not defined

Trying to start this via codesandbox (to fiddle around) I get this error right out the gate:

ReferenceError
Cypress is not defined
evaluate
/src/index.js:7
   4 | const { createMarkdown } = require('safe-marked')
   5 | const markdown = createMarkdown()
   6 | 
>  7 | Cypress.Commands.add('runExample', options => {
   8 |   const { name, description, html, test } = options
   9 |   const testTitle = name || cy.state('runnable').title
  10 | 
View compiled

Link for reproduction: https://codesandbox.io/s/github/cypress-io/cypress-fiddle

Check exported JS spec with nested suites

Fiddles with parts generate empty tests in output JS specs

<!-- fiddle cy.spy() / wrap a method in a spy -->

In GUI

Screen Shot 2020-04-23 at 6 16 07 PM

but in the generated specs

Screen Shot 2020-04-23 at 6 14 39 PM

and it has generated empty tests

describe('Spies, Stubs & Clocks', () => {
  before(() => {
    cy.visit('http://localhost:5000/cypress-examples/commands/spies_stubs_clocks')
  })
  
  it('', () => {
    
  })
  
  it('', () => {
    
  })
  
  it('', () => {
    
  })

Merge individual describes blocks into a single list

The Markdown

<!-- fiddle parent suite / test A -->
```js
...
```
<!-- fiddle-end -->
<!-- fiddle parent suite / test B -->
```js
...
```
<!-- fiddle-end -->

should produce

describe("parent suite", () => {
  it("test A", () => {})
  it("test B", () => {})
})

if the test uses `cy.visit` do not do `cy.within`

Because we no longer are mounting our code, and instead we load external site.

Note: if the test is visiting a site, then it cannot have HTML block, since it will be overwritten. Should throw an error.

Add Markdown preprocessor

After looking at Cypress documentation and how to use this fiddle to insert checked tests into the Hexo Markdown in cypress-io/cypress-documentation#2063 I think I should do the following:

  • allow Cypress to run tests from Markdown files if it finds appropriately tagged html / javascript code blocks

Maybe something like this

<!-- cypress-fiddle --->
## Fiddle title
This is test description

    html to mount


    cy.get(...)
    // and the rest of the test
<!-- cypress-fiddle-end --->

Allow including user-specified scripts

Probably external URLs for now in addition to the bundled jQuery and Highlight.js

Screen Shot 2020-11-16 at 10 39 40 AM

Could be specified in the cypress.json similar to the CSS styles

{
  "env": {
    "cypress-fiddle": {
      "stylesheets": [
        "https://stackpath.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
      ],
      "style": "body { padding: 2rem; } .action-focus.focus { border: 5px solid orange; }"
    }
  }
}

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • chore(deps): update dependency prettier to v2.8.4
  • chore(deps): update node.js to v18.14.2
  • fix(deps): update dependency @textlint/markdown-to-ast to v12.6.1
  • chore(deps): update dependency cypress-expect to v3
  • chore(deps): update dependency semantic-release to v20
  • fix(deps): update dependency @textlint/markdown-to-ast to v13
  • fix(deps): update dependency safe-marked to v12
  • fix(deps): update dependency safe-marked to v13
  • fix(deps): update dependency safe-marked to v14
  • πŸ” Create all rate-limited PRs at once πŸ”

Other Branches

These updates are pending. To force PRs open, click the checkbox below.

  • chore(deps): lock file maintenance

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

nodenv
.node-version
  • node 18.12.1
npm
package.json
  • @cypress/browserify-preprocessor 3.0.2
  • @textlint/markdown-to-ast 12.2.3
  • arg 5.0.2
  • common-tags 1.8.2
  • debug 4.3.4
  • safe-marked 11.0.0
  • temp-write 4.0.0
  • cypress ^12.0.2
  • cypress-expect 2.5.3
  • cypress-pipe 2.0.0
  • prettier 2.8.1
  • semantic-release 17.4.7

  • Check this box to trigger a request for Renovate to run again on this repository

Properly escape JavaScript comments

Seems if the JS comments include HTML elements, then mounting code creates extra elements

Works

'single a': {
      only: false,
      html: source`
        <a id="single">Single anchor</a>
      `,
      test: source`
        // yields "a"
        cy.get('a').should('have.id', 'single')
      `
    }

No surprises

Screen Shot 2019-09-09 at 3 44 46 PM

But if the test has comment like // <a>

'single a': {
      only: false,
      html: source`
        <a id="single">Single anchor</a>
      `,
      test: source`
        // yields <a>
        cy.get('a').should('have.id', 'single')
      `
    }

Then the live markup contains additional empty anchor tag

Screen Shot 2019-09-09 at 3 45 08 PM

Add ability to change spec text before executing it

Example: we mount the DOM markup in a div, while some tests might assume they use the full iframe

// By default, root is the document
cy.root().should('match', 'html')

Screen Shot 2020-04-11 at 2 27 56 PM

So this test fails, but would pass if we ran

// By default, root is the document
cy.root().should('match', 'div#live')

It would be nice to give us ability to have hidden text processing over test code before executing it in Cypress

<!-- fiddle -->
```js
// By default, root is the document
cy.root().should('match', 'html')
```
```js transform
code.replace('html', 'div#live')
```

Where we execute js transform block if found by giving it a variable code with the current test code and then we evaluate the returned code.

Allow merging multiple JS blocks into a single test

If a long fiddle explains what is going it can have several JS blocks

<!-- fiddle -->
this thing does A
```js
// cypress commands
```
then it does B
```js
// continue Cypress tests
```

All the blocks should be concatenated and evaluated together as a single test

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you can benefit from your bug fixes and new features again.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can fix this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here are some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


Invalid npm token.

The npm token configured in the NPM_TOKEN environment variable must be a valid token allowing to publish to the registry https://registry.npmjs.org/.

If you are using Two Factor Authentication for your account, set its level to "Authorization only" in your account settings. semantic-release cannot publish with the default "
Authorization and writes" level.

Please make sure to set the NPM_TOKEN environment variable in your CI with the exact value of the npm token.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

Allow lists of tests

Right now to create several tests we can use name as key in an object, which is weird

import { source } from 'common-tags'

export default {
  'cy.wrap()': {
    'detects when property gets added to an object': {
      test: source`
        // an object without a property
        const o = {}
        // property "id" gets added after a delay
        setTimeout(() => {
          o.id = 'abc123'
        }, 500)
        // detects when property "id" get added to the object "o"
        cy.wrap(o).should('have.property', 'id')
      `
    },

I would like to list tests in an array, and use name property

import { source } from 'common-tags'

export default {
  'cy.wrap()': [{
      name: 'detects when property gets added to an object',
      test: source`
        // an object without a property
        const o = {}
        // property "id" gets added after a delay
        setTimeout(() => {
          o.id = 'abc123'
        }, 500)
        // detects when property "id" get added to the object "o"
        cy.wrap(o).should('have.property', 'id')
      `
    },
    // second test

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.