JAM Stack has become a popular way to build websites - you can write your pages using Markdown (the M
in JAM
), build using JavaScript tools that fetch data from APIs and get mostly static sites that are very fast. In this blog post I will show how each Markdown page can also include its own end-to-end tests using the Cypress Test Runner.
Code: The source repo for this blog post is at bahmutov/self-testing-jam and the deployed site is available at https://self-testing-jam.netlify.com/. It is a JAM static site that uses a Vuepress site deployed on Netlify.
Recently I have talked about end-to-end testing at ReactiveConf 2019 in Prague, Czech Republic. It was an excellent conference, and the 25 minute video of my talk was posted online almost immediately. We wanted to distribute the talk widely because it covered several topics very relevant to the testing community: code coverage, linting source code, and writing faster tests. You can watch the video down below and find the slides at https://slides.com/bahmutov/state-of-the-art/
Watching an entire 25 minute video and flipping through the 100 slide deck seems like a big commitment. I have created aliases that immediately go to the specific slide of the presentation for each topic, and found the video timestamp when I begin talking about it.
Topic | slide alias | Video at |
---|---|---|
Types of linters | #lint-pyramid |
3m46s |
Tests and plugins | #only-tests |
7m9s |
Cover coverage | #code-coverage |
11m39s |
Splitting long tests | #test-length |
20m5s |
Whenever I need to send someone additional information about code coverage for an example, I can send urls to the slides https://slides.com/bahmutov/state-of-the-art/#/code-coverage and the video https://youtu.be/JL3QKQO80fs?t=699 which is great.
Self-testing the Markdown file
Publishing a separate documentation page with each talk thus should embed the talk video and a table of shortcuts, plus possible additional information. Here is the Markdown of the page.
The page might get complex, thus it is a good idea to write at least a simple Cypress end-to-end test. For me, the best test is the one that sits closely to the code it is testing. Placing a spec file next to the code file is great, I could place tests next to Markdown files like this.
self-testing-jam/
README.md
reactiveconf.md
reactive-conf-spec.js
cypress.json
By default Cypress expects spec files to be placed in the cypress/integration
folder, so we need to set the integration folder to be .
using cypress.json
{
"integrationFolder": ".",
"fixturesFolder": false,
"supportFile": false
}
This is good, but we can go one step further. Cypress transpiles each spec file using cypress-browserify-preprocessor, which you can change to tweak options and even transpile other file types. Recently I have written a Cypress Markdown transpiler and placed it in the cypress-io/cypress-fiddle repository. To use this preprocessor, install it and add the following code to your plugins file:
// cypress/plugins/index.js
const mdPreprocessor = require('@cypress/fiddle/src/markdown-preprocessor')
module.exports = (on, config) => {
on('file:preprocessor', mdPreprocessor)
}
The new preprocessor allows you to write end-to-end tests inside Markdown text files - just surround the test's JavaScript test block with special HTML comments like this:
Great, we can write a test right inside the ReactiveConf video talk reactiveconf.md
file. For example, we can confirm the video player is loading and the individual section links are present.
cy.visit('/reactiveconf.html')
// YouTube player is embedded
cy.contains('Cypress.io - the State of the Art End-to-end Testing Tool')
cy.get('[data-cy=talk]')
.then($iframe => {
// this ensures the frame loaded
cy.wrap($iframe.contents()).should('have.length', 1)
return cy.wrap($iframe.contents().find("body"))
})
.find('.html5-video-player').should('be.visible')
// main sections links
;['Lint pyramid', 'Tests and plugins', 'Code coverage'].forEach(section => {
cy.contains('li', section).should('be.visible')
})
Tip: because the video player comes from 3rd party domain, you need to disable the browser security check using cypress.json
like this:
{
"baseUrl": "http://localhost:8080",
"chromeWebSecurity": false,
"viewportHeight": 1000
}
Hiding the test itself
To prevent the test itself from showing up and taking up the majority of the rendered page, we can place it inside <details>
tag right inside Markdown. Here is a screenshot of the page that shows the page and the embedded test fiddle.
Here is the final result running a local Cypress test against the built page.
Tip: you can completely hide the test by setting the test's tag to display:none
like this
<details style="display:none">
<summary>Cypress test for the current page</summary>
<!-- fiddle Talk and contents list -->
...
</details>
Links
- https://github.com/bahmutov/self-testing-jam has the source for this blog post, and you can find the deployed page at https://self-testing-jam.netlify.com/reactiveconf.html
- The markdown preprocessor with test extraction lives in https://github.com/cypress-io/cypress-fiddle, also read Run End-to-end Tests from Markdown Files
- It is a good idea to test static sites as you build them and after deploy, read these blog posts: Gatsby Netlify Circle and Cypress and VuePress and some Cypress end-to-end testing tips.